diff --git a/.gitignore b/.gitignore index 665b11f9bb947d04a4ca0f4a25a39f66c47ab94a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +0,0 @@ -vas/rest/class/* -vas/rest/class/!*/ -vas/rest/class/!*.* -vas/sql/* -vas/sql/!*/ -vas/sql/!*.* - -utils - Copie/ diff --git a/vas/rest/class/.htaccess b/vas/rest/class/.htaccess new file mode 100755 index 0000000000000000000000000000000000000000..3418e55a68383c1cbc687c52a2994d1e8ed83800 --- /dev/null +++ b/vas/rest/class/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/vas/rest/class/Ldap.class.inc b/vas/rest/class/Ldap.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..a9c691eaf4400bbc112c0c96bf79bfc5442a42a6 --- /dev/null +++ b/vas/rest/class/Ldap.class.inc @@ -0,0 +1,347 @@ +<?php + header('Content-Type: text/html; charset=UTF-8;'); + // require_once("../properties.inc"); + require_once(__DIR__.'/vmlib/phpUtil.inc'); + require_once(__DIR__.'/vmlib/logUtil.inc'); + require_once(__DIR__.'/vmlib/cryptUtil.inc'); +class Ldap { + + // Tableau des informations de l'AD + public $aLdap = array(); + public $userprincipalname = ''; + private $sDcLdap = ''; + + public function __construct($sLdap) { + $this->aLdap = unserialize($sLdap); + $aTmp = explode('.',$this->aLdap['sLdapName']); + foreach($aTmp as $sDomain){ + if($this->sDcLdap=="") + $this->sDcLdap .= "dc=".$sDomain; + else + $this->sDcLdap .= ",dc=".$sDomain; + } + + if($this->aLdap['sType'] == 'AD') + $this->userprincipalname = 'userprincipalname'; + else + $this->userprincipalname = 'uid'; + } + + /* + * Permet la connexion au serveur AD + */ + public function connectLdap(){ + $sLdapConn = ldap_connect($this->aLdap['sServer'], $this->aLdap['sPort']) or die(writeToErrorLog("Could not connect to LDAP server.")); + if ($sLdapConn) { // Si la connexion s'est bien déroulée + ldap_set_option($sLdapConn, LDAP_OPT_PROTOCOL_VERSION, 3); + ldap_set_option($sLdapConn, LDAP_OPT_REFERRALS, 0); + //Authentification + $sPwdLdap =utf8_encode(trim(des (rtrim(utf8_decode($this->aLdap['sLoginLdap'])), hexToString(rtrim($this->aLdap['sPwdLdap'])), 0, 0, null))); + $sLoginLdap = mb_strtolower($this->aLdap['sLoginLdap'], 'UTF-8'); + $sLoginLdap = str_replace(array('à', 'â', 'ä', 'á', 'ã', 'å','î', 'ï', 'ì', 'í', 'ô', 'ö', 'ò', 'ó', 'õ', 'ø', 'ù', 'û', 'ü', 'ú', 'é', 'è', 'ê', 'ë', 'ç', 'ÿ', 'ñ'), array('a', 'a', 'a', 'a', 'a', 'a', 'i', 'i', 'i', 'i', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'e', 'e', 'e', 'e', 'c', 'y', 'n', ), $sLoginLdap); + $sLdapBind = ldap_bind($sLdapConn,$sLoginLdap,$sPwdLdap); + return $sLdapConn; + } + return "Could not connect to LDAP server."; + } + + /* + * Permet la déconnexion au serveur AD + */ + public function closeLdap($sLdapConn) { + ldap_close($sLdapConn); + } + /** + * Retourne la liste des OU du noeud + */ + + public function getOU($sLdapConn, $sDn) { + $sFilter = "(|(objectclass=organizationalUnit)(objectClass=container))"; + $aOUList = array(); + + if($sDn == null){ + if($this->aLdap['sDnResearch'] == 'null'){ + $sDn = $this->sDcLdap; + }else{ + $sDn = $this->aLdap['sDnResearch'].",".$this->sDcLdap; + $aOUList[] = $sDn; + return $aOUList; + } + } + $oSearch= ldap_list($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + $i=0; + for ($i=0;$i<$aInfo['count'];$i++) { + $aOUList[] = $aInfo[$i]['dn']; + } + natcasesort($aOUList); + + return $aOUList; + } + + /** + * Retourne la liste des utilisateurs du noeud + */ + public function getUsers($sLdapConn, $sDn) { + $sFilter = "objectclass=person"; + $aUserList = array(); + $oSearch= ldap_list($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + $i=0; + for ($i=0;$i<$aInfo['count'];$i++) { + //company et department non tester sur openldap car pas de données pour ses attibuts + if($aInfo[$i][$this->userprincipalname][0]!='') { + $aUser = array('userprincipalname'=>'', 'displayname'=>'', 'email'=>'', 'company'=>'', 'department'=>''); + if (!empty($aInfo[$i][$this->userprincipalname])) + $aUser['userprincipalname'] = $aInfo[$i][$this->userprincipalname][0]; + if (!empty($aInfo[$i]['cn'])) + $aUser['displayname'] = $aInfo[$i]['cn'][0]; + if (!empty($aInfo[$i]['mail'])) + $aUser['email'] = $aInfo[$i]['mail'][0]; + if (!empty($aInfo[$i]['company'])) + $aUser['company'] = $aInfo[$i]['company'][0]; + if (!empty($aInfo[$i]['department'])) + $aUser['department'] = $aInfo[$i]['department'][0]; + $aUserList[] = $aUser; + } + } + + if(count($aUserList)>1){ + // Permet de trier le tableau par rapport à "displayname" (insensible à la casse) + foreach ($aUserList as $key => $row) + $displayname[$key] = strtolower($row['displayname']); + array_multisort($displayname, $aUserList); + } + + return $aUserList; + } + function explode_dn($dn, $with_attributes=0) { + $result = ldap_explode_dn($dn, $with_attributes); + //translate hex code into ascii again + foreach($result as $key => $value) $result[$key] = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $value); + return $result; + } + + public function getCriteria($sLdapConn, $sDn, $sFilter, $sObject) { + $aUserList = array(); + $oSearch= ldap_search($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + $i=0; + for ($i=0;$i<$aInfo['count'];$i++) { + if ($sObject == "person"){ + if(!empty($aInfo[$i][$this->userprincipalname][0]) && $aInfo[$i][$this->userprincipalname][0] != '') { + $aUser = array('userprincipalname'=>'', 'displayname'=>'', 'email'=>'', 'company'=>'', 'department'=>''); + if (!empty($aInfo[$i][$this->userprincipalname])) + $aUser['userprincipalname'] = $aInfo[$i][$this->userprincipalname][0]; + if (!empty($aInfo[$i]['cn'])) + $aUser['displayname'] = $aInfo[$i]['cn'][0]; + if (!empty($aInfo[$i]['mail'])) + $aUser['email'] = $aInfo[$i]['mail'][0]; + if (!empty($aInfo[$i]['company'])) + $aUser['company'] = $aInfo[$i]['company'][0]; + if (!empty($aInfo[$i]['department'])) + $aUser['department'] = $aInfo[$i]['department'][0]; + $aUserList[] = $aUser; + } + }else{ + $aUserList[] = array('name'=>$aInfo[$i]['name'][0]); + } + } + + if(count($aUserList)>1){ + if ($sObject == "person"){ + // Permet de trier le tableau par rapport à "displayname" (insensible à la casse) + foreach ($aUserList as $key => $row) + $displayname[$key] = strtolower($row['displayname']); + array_multisort($displayname, $aUserList); + }else{ + // Permet de trier le tableau par rapport à "name" (insensible à la casse) + foreach ($aUserList as $key => $row) + if (!empty($row['cn'])) + $name[$key] = strtolower($row['cn']); + if (!empty($name)) + array_multisort($name, $aUserList); + } + } + + return $aUserList; + } + + function get_members($sLdapConn, $sDn, $group, $sLogin, $sDepartment) { + $results = ldap_search($sLdapConn,$sDn, "cn=" . $group); + $member_list = ldap_get_entries($sLdapConn, $results); + $dirty = 0; + $aUserList = array(); + if(count($member_list[0]['member'])>0){ + foreach($member_list[0]['member'] as $member) { + if($dirty == 0) { + $dirty = 1; + } else { + $member_dn = $this->explode_dn($member); + $member_cn = str_ireplace("cn=","",$member_dn[0]); + $member_search = ldap_search($sLdapConn,$sDn, "(cn=" . $member_cn . ")"); + $member_details = ldap_get_entries($sLdapConn, $member_search); + $bGet = true; + if ($sLogin != ""){ + if (!($this->startsWith($member_details[0][$this->userprincipalname][0],$sLogin))){ + $bGet = false; + } + } + if ($sDepartment != ""){ + if (!($this->startsWith($member_details[0]['department'][0],$sDepartment))){ + $bGet = false; + } + } + if ($bGet){ + $aUserList[] = array('userprincipalname'=>$member_details[0][$this->userprincipalname][0], 'displayname'=>$member_details[0]['cn'][0], 'email'=>$member_details[0]['mail'][0], 'company'=>$member_details[0]['company'][0], 'department'=>$member_details[0]['department'][0]); + } + } + } + } + return $aUserList; + } + + function startsWith($haystack, $needle) { + return $needle === "" || strpos($haystack, $needle) === 0; + } + + public function getGroups($sLdapConn, $sDn) { + $sFilter = "(&(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=group))(!(objectClass=person)))"; + $aGroupList = array(); + $oSearch= ldap_list($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + $i=0; + for ($i=0;$i<$aInfo['count'];$i++) { + if($aInfo[$i]['cn'][0]!='') + $aGroupList[] = array('name'=>$aInfo[$i]['cn'][0]); + } + + if(count($aGroupList)>1){ + // Permet de trier le tableau par rapport à "name" (insensible à la casse) + foreach ($aGroupList as $key => $row) + if (!empty($row['cn'])) + $name[$key] = strtolower($row['cn']); + if (!empty($name)) + array_multisort($name, $aGroupList); + } + + return $aGroupList; + } + + public function getGroupInfo($sLdapConn, $sDn, $group) { + $sFilter = '(&(objectClass=group)(name='.$group.'))'; + //Recherche de la personne dans l'AD + $oSearch = ldap_search($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_first_entry($sLdapConn, $oSearch); + $objectSid = ldap_get_values($sLdapConn,$aInfo,"objectSid"); + $hex_Sid= $this->getTextSID($objectSid[0]); + //Récupération des autres groupes de l'utilisateur + $aPrimaryGroupId = explode('-',$hex_Sid); + $iPrimaryGroupId = $aPrimaryGroupId[count($aPrimaryGroupId) - 1]; + return $iPrimaryGroupId; + } + + /* + * Retourne les groupes de l'utilisateur + */ + function getGroup($sLdapConn, $userprincipalname){ + if($this->aLdap['sType'] == 'AD') + $sFilter = "userprincipalname=".$userprincipalname; + else + $sFilter = "(&(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames))(member=".$sDn."))"; + + $aGroupList = array(); + //Recherche de la personne dans l'AD + if($this->aLdap['sDnResearch'] == '') + $sDn = $this->sDcLdap; + else + $sDn = $this->aLdap['sDnResearch'].",".$this->sDcLdap; + + $oSearch = ldap_search($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + if($this->aLdap['sType'] == 'AD'){ + //Récupération de son groupe principal + $aGroupList[] = $this->getPrimaryGroup($sLdapConn,$aInfo[0]["primarygroupid"][0], $aInfo[0]["objectsid"][0]); + //Récupération des autres groupes de l'utilisateur + if(!empty($aInfo[0]["memberof"])){ + foreach ($aInfo[0]["memberof"] as $sGroup){ + $sGroup = explode(',',$sGroup); + $aGroupList[] = substr($sGroup[0],3); + } + } + }else{ + foreach ($aInfo as $aGroupInfo){ + $aGroupList[] = $aGroupInfo["cn"][0]; + } + } + natcasesort($aGroupList); + return $aGroupList; + } + + /* + * Retourne le DN d'une personne à partir de son uid + */ + function getDN($sLdapConn, $sUid){ + $sFilter = $this->userprincipalname."=".$sUid; + $sDn = "dc=cpa,dc=fr"; + $oSearch = ldap_search($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + return $aInfo[0]["dn"]; + } + + /* + * Retourne le groupe principal de l'utilisateur + */ + function getPrimaryGroup($sLdapConn, $iGid, $sUsersId){ + if ($iGid === NULL || $sUsersId === NULL) { return false; } + $oSearch = false; + //Plusieurs calculs pour retrouver les sid du groupe principal + $sGsid = substr_replace($sUsersId, pack('V',$iGid), strlen($sUsersId)-4,4); + + $sFilter = '(&(objectClass=group)(objectsid='.$this->getTextSID($sGsid).'))'; + + // Recherche sur le serveur du SID du groupe + // if($this->aLdap['sDnResearch'] == ''){ + $sDn = $this->sDcLdap; + // } + // else{ + // $sDn = $this->aLdap['sDnResearch'].",".$this->sDcLdap; + // } + + $oSearch= ldap_search($sLdapConn, $sDn, $sFilter); + $aInfo = ldap_get_entries($sLdapConn, $oSearch); + if (isset($aInfo[0]['name'][0])) { + return $aInfo[0]['name'][0]; + } + return false; + } + + /* + * Les 2 fonctions suivantes servent à calculer le SID du groupe principal + */ + function getTextSID($binsid){ + $hex_sid = bin2hex($binsid); + $rev = hexdec(substr($hex_sid, 0, 2)); + $subcount = hexdec(substr($hex_sid, 2, 2)); + $auth = hexdec(substr($hex_sid, 4, 12)); + $result = "$rev-$auth"; + for ($x=0;$x < $subcount; $x++) { + $subauth[$x] = hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); + $result .= "-" . $subauth[$x]; + } + return 'S-' . $result; + } + function littleEndian($hex){ + $result = ''; + for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) { + $result .= substr($hex, $x, 2); + } + return $result; + } + + function getDcLdap(){ + return $this->sDcLdap; + } + +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Autoloader.php b/vas/rest/class/PEAR/Autoloader.php new file mode 100755 index 0000000000000000000000000000000000000000..07c4de109901c4af551ec19ed06dc911299b3c24 --- /dev/null +++ b/vas/rest/class/PEAR/Autoloader.php @@ -0,0 +1,223 @@ +<?php +/** + * Class auto-loader + * + * PHP versions 4 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Autoloader.php,v 1.14 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ + +// /* vim: set expandtab tabstop=4 shiftwidth=4: */ + +if (!extension_loaded("overload")) { + // die hard without ext/overload + die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); +} + +/** + * Include for PEAR_Error and PEAR classes + */ +require_once "PEAR.php"; + +/** + * This class is for objects where you want to separate the code for + * some methods into separate classes. This is useful if you have a + * class with not-frequently-used methods that contain lots of code + * that you would like to avoid always parsing. + * + * The PEAR_Autoloader class provides autoloading and aggregation. + * The autoloading lets you set up in which classes the separated + * methods are found. Aggregation is the technique used to import new + * methods, an instance of each class providing separated methods is + * stored and called every time the aggregated method is called. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ +class PEAR_Autoloader extends PEAR +{ + // {{{ properties + + /** + * Map of methods and classes where they are defined + * + * @var array + * + * @access private + */ + var $_autoload_map = array(); + + /** + * Map of methods and aggregate objects + * + * @var array + * + * @access private + */ + var $_method_map = array(); + + // }}} + // {{{ addAutoload() + + /** + * Add one or more autoload entries. + * + * @param string $method which method to autoload + * + * @param string $classname (optional) which class to find the method in. + * If the $method parameter is an array, this + * parameter may be omitted (and will be ignored + * if not), and the $method parameter will be + * treated as an associative array with method + * names as keys and class names as values. + * + * @return void + * + * @access public + */ + function addAutoload($method, $classname = null) + { + if (is_array($method)) { + array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); + $this->_autoload_map = array_merge($this->_autoload_map, $method); + } else { + $this->_autoload_map[strtolower($method)] = $classname; + } + } + + // }}} + // {{{ removeAutoload() + + /** + * Remove an autoload entry. + * + * @param string $method which method to remove the autoload entry for + * + * @return bool TRUE if an entry was removed, FALSE if not + * + * @access public + */ + function removeAutoload($method) + { + $method = strtolower($method); + $ok = isset($this->_autoload_map[$method]); + unset($this->_autoload_map[$method]); + return $ok; + } + + // }}} + // {{{ addAggregateObject() + + /** + * Add an aggregate object to this object. If the specified class + * is not defined, loading it will be attempted following PEAR's + * file naming scheme. All the methods in the class will be + * aggregated, except private ones (name starting with an + * underscore) and constructors. + * + * @param string $classname what class to instantiate for the object. + * + * @return void + * + * @access public + */ + function addAggregateObject($classname) + { + $classname = strtolower($classname); + if (!class_exists($classname)) { + $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); + include_once $include_file; + } + $obj =& new $classname; + $methods = get_class_methods($classname); + foreach ($methods as $method) { + // don't import priviate methods and constructors + if ($method{0} != '_' && $method != $classname) { + $this->_method_map[$method] = $obj; + } + } + } + + // }}} + // {{{ removeAggregateObject() + + /** + * Remove an aggregate object. + * + * @param string $classname the class of the object to remove + * + * @return bool TRUE if an object was removed, FALSE if not + * + * @access public + */ + function removeAggregateObject($classname) + { + $ok = false; + $classname = strtolower($classname); + reset($this->_method_map); + while (list($method, $obj) = each($this->_method_map)) { + if (is_a($obj, $classname)) { + unset($this->_method_map[$method]); + $ok = true; + } + } + return $ok; + } + + // }}} + // {{{ __call() + + /** + * Overloaded object call handler, called each time an + * undefined/aggregated method is invoked. This method repeats + * the call in the right aggregate object and passes on the return + * value. + * + * @param string $method which method that was called + * + * @param string $args An array of the parameters passed in the + * original call + * + * @return mixed The return value from the aggregated method, or a PEAR + * error if the called method was unknown. + */ + function __call($method, $args, &$retval) + { + $method = strtolower($method); + if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { + $this->addAggregateObject($this->_autoload_map[$method]); + } + if (isset($this->_method_map[$method])) { + $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); + return true; + } + return false; + } + + // }}} +} + +overload("PEAR_Autoloader"); + +?> diff --git a/vas/rest/class/PEAR/Builder.php b/vas/rest/class/PEAR/Builder.php new file mode 100755 index 0000000000000000000000000000000000000000..f7986c0096095ce844ba335df726ac2ac8b72464 --- /dev/null +++ b/vas/rest/class/PEAR/Builder.php @@ -0,0 +1,486 @@ +<?php +/** + * PEAR_Builder for building PHP extensions (PECL packages) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Builder.php,v 1.34 2008/05/12 23:43:21 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + * + * TODO: log output parameters in PECL command line + * TODO: msdev path in configuration + */ + +/** + * Needed for extending PEAR_Builder + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; +/** + * Class to handle building (compiling) extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since PHP 4.0.2 + * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php + */ +class PEAR_Builder extends PEAR_Common +{ + // {{{ properties + + var $php_api_version = 0; + var $zend_module_api_no = 0; + var $zend_extension_api_no = 0; + + var $extensions_built = array(); + + /** + * @var string Used for reporting when it is not possible to pass function + * via extra parameter, e.g. log, msdevCallback + */ + var $current_callback = null; + + // used for msdev builds + var $_lastline = null; + var $_firstline = null; + // }}} + // {{{ constructor + + /** + * PEAR_Builder constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Builder(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + } + + // }}} + + // {{{ _build_win32() + + /** + * Build an extension from source on windows. + * requires msdev + */ + function _build_win32($descfile, $callback = null) + { + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); + } else { + $pf = &new PEAR_PackageFile($this->config, $this->debug); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } + } + $dir = dirname($descfile); + $old_cwd = getcwd(); + + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + // packages that were in a .tar have the packagefile in this directory + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (file_exists($dir) && is_dir($vdir)) { + if (chdir($vdir)) { + $dir = getcwd(); + } else { + return $this->raiseError("could not chdir to " . realpath($vdir)); + } + } + + $this->log(2, "building in $dir"); + + $dsp = $pkg->getPackage().'.dsp'; + if (!file_exists("$dir/$dsp")) { + return $this->raiseError("The DSP $dsp does not exist."); + } + // XXX TODO: make release build type configurable + $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"'; + + $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); + if (PEAR::isError($err)) { + return $err; + } + + // figure out the build platform and type + $platform = 'Win32'; + $buildtype = 'Release'; + if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { + $platform = $matches[1]; + $buildtype = $matches[2]; + } + + if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/',$this->_lastline,$matches)) { + if ($matches[2]) { + // there were errors in the build + return $this->raiseError("There were errors during compilation."); + } + $out = $matches[1]; + } else { + return $this->raiseError("Did not understand the completion status returned from msdev.exe."); + } + + // msdev doesn't tell us the output directory :/ + // open the dsp, find /out and use that directory + $dsptext = join(file($dsp),''); + + // this regex depends on the build platform and type having been + // correctly identified above. + $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. + $pkg->getPackage().'\s-\s'. + $platform.'\s'. + $buildtype.'").*?'. + '\/out:"(.*?)"/is'; + + if ($dsptext && preg_match($regex,$dsptext,$matches)) { + // what we get back is a relative path to the output file itself. + $outfile = realpath($matches[2]); + } else { + return $this->raiseError("Could not retrieve output information from $dsp."); + } + // realpath returns false if the file doesn't exist + if ($outfile && copy($outfile, "$dir/$out")) { + $outfile = "$dir/$out"; + } + + $built_files[] = array( + 'file' => "$outfile", + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + + return $built_files; + } + // }}} + + // {{{ msdevCallback() + function msdevCallback($what, $data) + { + if (!$this->_firstline) + $this->_firstline = $data; + $this->_lastline = $data; + call_user_func($this->current_callback, $what, $data); + } + // }}} + + // {{{ _harventInstDir + /** + * @param string + * @param string + * @param array + * @access private + */ + function _harvestInstDir($dest_prefix, $dirname, &$built_files) + { + $d = opendir($dirname); + if (!$d) + return false; + + $ret = true; + while (($ent = readdir($d)) !== false) { + if ($ent{0} == '.') + continue; + + $full = $dirname . DIRECTORY_SEPARATOR . $ent; + if (is_dir($full)) { + if (!$this->_harvestInstDir( + $dest_prefix . DIRECTORY_SEPARATOR . $ent, + $full, $built_files)) { + $ret = false; + break; + } + } else { + $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; + $built_files[] = array( + 'file' => $full, + 'dest' => $dest, + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + } + } + closedir($d); + return $ret; + } + + // }}} + + // {{{ build() + + /** + * Build an extension from source. Runs "phpize" in the source + * directory, but compiles in a temporary directory + * (/var/tmp/pear-build-USER/PACKAGE-VERSION). + * + * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or + * a PEAR_PackageFile object + * + * @param mixed $callback callback function used to report output, + * see PEAR_Builder::_runCommand for details + * + * @return array an array of associative arrays with built files, + * format: + * array( array( 'file' => '/path/to/ext.so', + * 'php_api' => YYYYMMDD, + * 'zend_mod_api' => YYYYMMDD, + * 'zend_ext_api' => YYYYMMDD ), + * ... ) + * + * @access public + * + * @see PEAR_Builder::_runCommand + */ + function build($descfile, $callback = null) + { + $this->current_callback = $callback; + if (PEAR_OS == "Windows") { + return $this->_build_win32($descfile,$callback); + } + if (PEAR_OS != 'Unix') { + return $this->raiseError("building extensions not supported on this platform"); + } + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); + if (is_a($pkg, 'PEAR_PackageFile_v1')) { + $dir = dirname($descfile); + } else { + $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName(); + // automatically delete at session end + $this->addTempFile($dir); + } + } else { + $pf = &new PEAR_PackageFile($this->config); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } + $dir = dirname($descfile); + } + $old_cwd = getcwd(); + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (is_dir($vdir)) { + chdir($vdir); + } + $dir = getcwd(); + $this->log(2, "building in $dir"); + putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); + $err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback')); + if (PEAR::isError($err)) { + return $err; + } + if (!$err) { + return $this->raiseError("`phpize' failed"); + } + + // {{{ start of interactive part + $configure_command = "$dir/configure"; + $configure_options = $pkg->getConfigureOptions(); + if ($configure_options) { + foreach ($configure_options as $o) { + $default = array_key_exists('default', $o) ? $o['default'] : null; + list($r) = $this->ui->userDialog('build', + array($o['prompt']), + array('text'), + array($default)); + if (substr($o['name'], 0, 5) == 'with-' && + ($r == 'yes' || $r == 'autodetect')) { + $configure_command .= " --$o[name]"; + } else { + $configure_command .= " --$o[name]=".trim($r); + } + } + } + // }}} end of interactive part + + // FIXME make configurable + if(!$user=getenv('USER')){ + $user='defaultuser'; + } + $build_basedir = "/var/tmp/pear-build-$user"; + $build_dir = "$build_basedir/$vdir"; + $inst_dir = "$build_basedir/install-$vdir"; + $this->log(1, "building in $build_dir"); + if (is_dir($build_dir)) { + System::rm(array('-rf', $build_dir)); + } + if (!System::mkDir(array('-p', $build_dir))) { + return $this->raiseError("could not create build dir: $build_dir"); + } + $this->addTempFile($build_dir); + if (!System::mkDir(array('-p', $inst_dir))) { + return $this->raiseError("could not create temporary install dir: $inst_dir"); + } + $this->addTempFile($inst_dir); + + if (getenv('MAKE')) { + $make_command = getenv('MAKE'); + } else { + $make_command = 'make'; + } + $to_run = array( + $configure_command, + $make_command, + "$make_command INSTALL_ROOT=\"$inst_dir\" install", + "find \"$inst_dir\" | xargs ls -dils" + ); + if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) { + return $this->raiseError("could not chdir to $build_dir"); + } + putenv('PHP_PEAR_VERSION=1.7.2'); + foreach ($to_run as $cmd) { + $err = $this->_runCommand($cmd, $callback); + if (PEAR::isError($err)) { + chdir($old_cwd); + return $err; + } + if (!$err) { + chdir($old_cwd); + return $this->raiseError("`$cmd' failed"); + } + } + if (!($dp = opendir("modules"))) { + chdir($old_cwd); + return $this->raiseError("no `modules' directory found"); + } + $built_files = array(); + $prefix = exec("php-config --prefix"); + $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); + chdir($old_cwd); + return $built_files; + } + + // }}} + // {{{ phpizeCallback() + + /** + * Message callback function used when running the "phpize" + * program. Extracts the API numbers used. Ignores other message + * types than "cmdoutput". + * + * @param string $what the type of message + * @param mixed $data the message + * + * @return void + * + * @access public + */ + function phpizeCallback($what, $data) + { + if ($what != 'cmdoutput') { + return; + } + $this->log(1, rtrim($data)); + if (preg_match('/You should update your .aclocal.m4/', $data)) { + return; + } + $matches = array(); + if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { + $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); + $apino = (int)$matches[2]; + if (isset($this->$member)) { + $this->$member = $apino; + //$msg = sprintf("%-22s : %d", $matches[1], $apino); + //$this->log(1, $msg); + } + } + } + + // }}} + // {{{ _runCommand() + + /** + * Run an external command, using a message callback to report + * output. The command will be run through popen and output is + * reported for every line with a "cmdoutput" message with the + * line string, including newlines, as payload. + * + * @param string $command the command to run + * + * @param mixed $callback (optional) function to use as message + * callback + * + * @return bool whether the command was successful (exit code 0 + * means success, any other means failure) + * + * @access private + */ + function _runCommand($command, $callback = null) + { + $this->log(1, "running: $command"); + $pp = popen("$command 2>&1", "r"); + if (!$pp) { + return $this->raiseError("failed to run `$command'"); + } + if ($callback && $callback[0]->debug == 1) { + $olddbg = $callback[0]->debug; + $callback[0]->debug = 2; + } + + while ($line = fgets($pp, 1024)) { + if ($callback) { + call_user_func($callback, 'cmdoutput', $line); + } else { + $this->log(2, rtrim($line)); + } + } + if ($callback && isset($olddbg)) { + $callback[0]->debug = $olddbg; + } + if (is_resource($pp)) { + $exitcode = pclose($pp); + } else { + $exitcode = -1; + } + return ($exitcode == 0); + } + + // }}} + // {{{ log() + + function log($level, $msg) + { + if ($this->current_callback) { + if ($this->debug >= $level) { + call_user_func($this->current_callback, 'output', $msg); + } + return; + } + return PEAR_Common::log($level, $msg); + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/ChannelFile.php b/vas/rest/class/PEAR/ChannelFile.php new file mode 100755 index 0000000000000000000000000000000000000000..46dd691b54e2799a3395375b74d9810d8c5c8e33 --- /dev/null +++ b/vas/rest/class/PEAR/ChannelFile.php @@ -0,0 +1,1615 @@ +<?php +/** + * PEAR_ChannelFile, the channel handling class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ChannelFile.php,v 1.80 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR/ErrorStack.php'; +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/Common.php'; + +/** + * Error code if the channel.xml <channel> tag does not contain a valid version + */ +define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); +/** + * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version, + * currently + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); + +/**#@+ + * Validation errors + */ +/** + * Error code when channel name is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); +/** + * Error code when channel name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); +/** + * Error code when channel summary is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); +/** + * Error code when channel summary is multi-line + */ +define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); +/** + * Error code when channel server is missing for xmlrpc or soap protocol + */ +define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); +/** + * Error code when channel server is invalid for xmlrpc or soap protocol + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); +/** + * Error code when a mirror name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); +/** + * Error code when a mirror type is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); +/** + * Error code when an attempt is made to generate xml, but the parsed content is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID', 23); +/** + * Error code when an empty package name validate regex is passed in + */ +define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); +/** + * Error code when a <function> tag has no version + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); +/** + * Error code when a <function> tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); +/** + * Error code when a <validatepackage> tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); +/** + * Error code when a <validatepackage> tag has no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); +/** + * Error code when a mirror does not exist but is called for in one of the set* + * methods. + */ +define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); +/** + * Error code when a server port is not numeric + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); +/** + * Error code when <static> contains no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); +/** + * Error code when <baseurl> contains no type attribute in a <rest> protocol definition + */ +define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); +/** + * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel + */ +define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); +/** + * Error code when ssl attribute is present and is not "yes" + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); +/**#@-*/ + +/** + * Mirror types allowed. Currently only internet servers are recognized. + */ +$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); + + +/** + * The Channel handling class + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile { + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; + + /** + * Supported channel.xml versions, for parsing + * @var array + * @access private + */ + var $_supportedVersions = array('1.0'); + + /** + * Parsed channel information + * @var array + * @access private + */ + var $_channelInfo; + + /** + * index into the subchannels array, used for parsing xml + * @var int + * @access private + */ + var $_subchannelIndex; + + /** + * index into the mirrors array, used for parsing xml + * @var int + * @access private + */ + var $_mirrorIndex; + + /** + * Flag used to determine the validity of parsed content + * @var boolean + * @access private + */ + var $_isValid = false; + + function PEAR_ChannelFile() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = false; + } + + /** + * @return array + * @access protected + */ + function _getErrorMessage() + { + return + array( + PEAR_CHANNELFILE_ERROR_INVALID_VERSION => + 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', + PEAR_CHANNELFILE_ERROR_NO_VERSION => + 'No version number found in <channel> tag', + PEAR_CHANNELFILE_ERROR_NO_XML_EXT => + '%error%', + PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => + 'Unable to create XML parser', + PEAR_CHANNELFILE_ERROR_PARSER_ERROR => + '%error%', + PEAR_CHANNELFILE_ERROR_NO_NAME => + 'Missing channel name', + PEAR_CHANNELFILE_ERROR_INVALID_NAME => + 'Invalid channel %tag% "%name%"', + PEAR_CHANNELFILE_ERROR_NO_SUMMARY => + 'Missing channel summary', + PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => + 'Channel summary should be on one line, but is multi-line', + PEAR_CHANNELFILE_ERROR_NO_HOST => + 'Missing channel server for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_HOST => + 'Server name "%server%" is invalid for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => + 'Invalid mirror name "%name%", mirror type %type%', + PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => + 'Invalid mirror type "%type%"', + PEAR_CHANNELFILE_ERROR_INVALID => + 'Cannot generate xml, contents are invalid', + PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => + 'packagenameregex cannot be empty', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => + '%parent% %protocol% function has no version', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => + '%parent% %protocol% function has no name', + PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => + '%parent% rest baseurl has no type', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => + 'Validation package has no name in <validatepackage> tag', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => + 'Validation package "%package%" has no version', + PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => + 'Mirror "%mirror%" does not exist', + PEAR_CHANNELFILE_ERROR_INVALID_PORT => + 'Port "%port%" must be numeric', + PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => + '<static> tag must contain version attribute', + PEAR_CHANNELFILE_URI_CANT_MIRROR => + 'The __uri pseudo-channel cannot have mirrors', + PEAR_CHANNELFILE_ERROR_INVALID_SSL => + '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', + ); + } + + /** + * @param string contents of package.xml file + * @return bool success of parsing + */ + function fromXmlString($data) + { + if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) { + if (!in_array($channelversion[1], $this->_supportedVersions)) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', + array('version' => $channelversion[1])); + return false; + } + $parser = new PEAR_XMLParser; + $result = $parser->parse($data); + if ($result !== true) { + if ($result->getCode() == 1) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', + array('error' => $result->getMessage())); + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + } + return false; + } + $this->_channelInfo = $parser->getData(); + return true; + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); + return false; + } + } + + /** + * @return array + */ + function toArray() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + return $this->_channelInfo; + } + + /** + * @param array + * @static + * @return PEAR_ChannelFile|false false if invalid + */ + function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + if (!$a->validate()) { + $a = false; + return $a; + } + return $a; + } + + /** + * Unlike {@link fromArray()} this does not do any validation + * @param array + * @static + * @return PEAR_ChannelFile + */ + function &fromArrayWithErrors($data, $compatibility = false, + $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + return $a; + } + + /** + * @param array + * @access private + */ + function _fromArray($data) + { + $this->_channelInfo = $data; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getErrors($purge = false) + { + return $this->_stack->getErrors($purge); + } + + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; + } + + /** + * Parse a channel.xml file. Expects the name of + * a channel xml file as input. + * + * @param string $descfile name of channel xml file + * @return bool success of parsing + */ + function fromXmlFile($descfile) + { + if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || + (!$fp = fopen($descfile, 'r'))) { + require_once 'PEAR.php'; + return PEAR::raiseError("Unable to open $descfile"); + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + return $this->fromXmlString($data); + } + + /** + * Parse channel information from different sources + * + * This method is able to extract information about a channel + * from an .xml file or a string + * + * @access public + * @param string Filename of the source or the source itself + * @return bool + */ + function fromAny($info) + { + if (is_string($info) && file_exists($info) && strlen($info) < 255) { + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = $this->fromXmlFile($info); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "<?xml") { + $info = $this->fromXmlFile($info); + } + } + if (PEAR::isError($info)) { + require_once 'PEAR.php'; + return PEAR::raiseError($info); + } + } + if (is_string($info)) { + $info = $this->fromXmlString($info); + } + return $info; + } + + /** + * Return an XML document based on previous parsing and modifications + * + * @return string XML data + * + * @access public + */ + function toXml() + { + if (!$this->_isValid && !$this->validate()) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); + return false; + } + if (!isset($this->_channelInfo['attribs']['version'])) { + $this->_channelInfo['attribs']['version'] = '1.0'; + } + $channelInfo = $this->_channelInfo; + $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"; + $ret .= "<channel version=\"" . + $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\" + xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" + xsi:schemaLocation=\"http://pear.php.net/dtd/channel-" + . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" . + $channelInfo['attribs']['version'] . ".xsd\"> + <name>$channelInfo[name]</name> + <summary>" . htmlspecialchars($channelInfo['summary'])."</summary> +"; + if (isset($channelInfo['suggestedalias'])) { + $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n"; + } + if (isset($channelInfo['validatepackage'])) { + $ret .= ' <validatepackage version="' . + $channelInfo['validatepackage']['attribs']['version']. '">' . + htmlspecialchars($channelInfo['validatepackage']['_content']) . + "</validatepackage>\n"; + } + $ret .= " <servers>\n"; + $ret .= ' <primary'; + if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) { + $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"'; + } + if (isset($channelInfo['servers']['primary']['attribs']['port'])) { + $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"'; + } + $ret .= ">\n"; + if (isset($channelInfo['servers']['primary']['xmlrpc'])) { + $ret .= $this->_makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], ' '); + } + if (isset($channelInfo['servers']['primary']['rest'])) { + $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], ' '); + } + if (isset($channelInfo['servers']['primary']['soap'])) { + $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], ' '); + } + $ret .= " </primary>\n"; + if (isset($channelInfo['servers']['mirror'])) { + $ret .= $this->_makeMirrorsXml($channelInfo); + } + $ret .= " </servers>\n"; + $ret .= "</channel>"; + return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); + } + + /** + * Generate the <xmlrpc> tag + * @access private + */ + function _makeXmlrpcXml($info, $indent) + { + $ret = $indent . "<xmlrpc"; + if (isset($info['attribs']['path'])) { + $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"'; + } + $ret .= ">\n"; + $ret .= $this->_makeFunctionsXml($info['function'], "$indent "); + $ret .= $indent . "</xmlrpc>\n"; + return $ret; + } + + /** + * Generate the <soap> tag + * @access private + */ + function _makeSoapXml($info, $indent) + { + $ret = $indent . "<soap"; + if (isset($info['attribs']['path'])) { + $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"'; + } + $ret .= ">\n"; + $ret .= $this->_makeFunctionsXml($info['function'], "$indent "); + $ret .= $indent . "</soap>\n"; + return $ret; + } + + /** + * Generate the <rest> tag + * @access private + */ + function _makeRestXml($info, $indent) + { + $ret = $indent . "<rest>\n"; + if (!isset($info['baseurl'][0])) { + $info['baseurl'] = array($info['baseurl']); + } + foreach ($info['baseurl'] as $url) { + $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\""; + $ret .= ">" . $url['_content'] . "</baseurl>\n"; + } + $ret .= $indent . "</rest>\n"; + return $ret; + } + + /** + * Generate the <mirrors> tag + * @access private + */ + function _makeMirrorsXml($channelInfo) + { + $ret = ""; + if (!isset($channelInfo['servers']['mirror'][0])) { + $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); + } + foreach ($channelInfo['servers']['mirror'] as $mirror) { + $ret .= ' <mirror host="' . $mirror['attribs']['host'] . '"'; + if (isset($mirror['attribs']['port'])) { + $ret .= ' port="' . $mirror['attribs']['port'] . '"'; + } + if (isset($mirror['attribs']['ssl'])) { + $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"'; + } + $ret .= ">\n"; + if (isset($mirror['xmlrpc']) || isset($mirror['soap'])) { + if (isset($mirror['xmlrpc'])) { + $ret .= $this->_makeXmlrpcXml($mirror['xmlrpc'], ' '); + } + if (isset($mirror['rest'])) { + $ret .= $this->_makeRestXml($mirror['rest'], ' '); + } + if (isset($mirror['soap'])) { + $ret .= $this->_makeSoapXml($mirror['soap'], ' '); + } + $ret .= " </mirror>\n"; + } else { + $ret .= "/>\n"; + } + } + return $ret; + } + + /** + * Generate the <functions> tag + * @access private + */ + function _makeFunctionsXml($functions, $indent, $rest = false) + { + $ret = ''; + if (!isset($functions[0])) { + $functions = array($functions); + } + foreach ($functions as $function) { + $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\""; + if ($rest) { + $ret .= ' uri="' . $function['attribs']['uri'] . '"'; + } + $ret .= ">" . $function['_content'] . "</function>\n"; + } + return $ret; + } + + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params); + $this->_isValid = false; + } + + /** + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params); + } + + /** + * Validate parsed file. + * + * @access public + * @return boolean + */ + function validate() + { + $this->_isValid = true; + $info = $this->_channelInfo; + if (empty($info['name'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); + } elseif (!$this->validChannelServer($info['name'])) { + if ($info['name'] != '__uri') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', + 'name' => $info['name'])); + } + } + if (empty($info['summary'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); + } + if (isset($info['suggestedalias'])) { + if (!$this->validChannelServer($info['suggestedalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); + } + } + if (isset($info['localalias'])) { + if (!$this->validChannelServer($info['localalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'localalias', 'name' =>$info['localalias'])); + } + } + if (isset($info['validatepackage'])) { + if (!isset($info['validatepackage']['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); + } + if (!isset($info['validatepackage']['attribs']['version'])) { + $content = isset($info['validatepackage']['_content']) ? + $info['validatepackage']['_content'] : + null; + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, + array('package' => $content)); + } + } + if (isset($info['servers']['primary']['attribs']['port']) && + !is_numeric($info['servers']['primary']['attribs']['port'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, + array('port' => $info['servers']['primary']['attribs']['port'])); + } + if (isset($info['servers']['primary']['attribs']['ssl']) && + $info['servers']['primary']['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['servers']['primary']['attribs']['ssl'], + 'server' => $info['name'])); + } + + if (isset($info['servers']['primary']['xmlrpc']) && + isset($info['servers']['primary']['xmlrpc']['function'])) { + $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']); + } + if (isset($info['servers']['primary']['soap']) && + isset($info['servers']['primary']['soap']['function'])) { + $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']); + } + if (isset($info['servers']['primary']['rest']) && + isset($info['servers']['primary']['rest']['baseurl'])) { + $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); + } + if (isset($info['servers']['mirror'])) { + if ($this->_channelInfo['name'] == '__uri') { + $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); + } + if (!isset($info['servers']['mirror'][0])) { + $info['servers']['mirror'] = array($info['servers']['mirror']); + } + foreach ($info['servers']['mirror'] as $mirror) { + if (!isset($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, + array('type' => 'mirror')); + } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, + array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); + } + if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); + } + if (isset($mirror['xmlrpc'])) { + $this->_validateFunctions('xmlrpc', + $mirror['xmlrpc']['function'], $mirror['attribs']['host']); + } + if (isset($mirror['soap'])) { + $this->_validateFunctions('soap', $mirror['soap']['function'], + $mirror['attribs']['host']); + } + if (isset($mirror['rest'])) { + $this->_validateFunctions('rest', $mirror['rest']['baseurl'], + $mirror['attribs']['host']); + } + } + } + return $this->_isValid; + } + + /** + * @param string xmlrpc or soap - protocol name this function applies to + * @param array the functions + * @param string the name of the parent element (mirror name, for instance) + */ + function _validateFunctions($protocol, $functions, $parent = '') + { + if (!isset($functions[0])) { + $functions = array($functions); + } + foreach ($functions as $function) { + if (!isset($function['_content']) || empty($function['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, + array('parent' => $parent, 'protocol' => $protocol)); + } + if ($protocol == 'rest') { + if (!isset($function['attribs']['type']) || + empty($function['attribs']['type'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE, + array('parent' => $parent, 'protocol' => $protocol)); + } + } else { + if (!isset($function['attribs']['version']) || + empty($function['attribs']['version'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, + array('parent' => $parent, 'protocol' => $protocol)); + } + } + } + } + + /** + * Test whether a string contains a valid channel server. + * @param string $ver the package version to test + * @return bool + */ + function validChannelServer($server) + { + if ($server == '__uri') { + return true; + } + return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); + } + + /** + * @return string|false + */ + function getName() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } else { + return false; + } + } + + /** + * @return string|false + */ + function getServer() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } else { + return false; + } + } + + /** + * @return int|80 port number to connect to + */ + function getPort($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['port'])) { + return $mir['attribs']['port']; + } else { + if ($this->getSSL($mirror)) { + return 443; + } + return 80; + } + } + return false; + } + if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { + return $this->_channelInfo['servers']['primary']['attribs']['port']; + } + if ($this->getSSL()) { + return 443; + } + return 80; + } + + /** + * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel + */ + function getSSL($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['ssl'])) { + return true; + } else { + return false; + } + } + return false; + } + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + return true; + } + return false; + } + + /** + * @return string|false + */ + function getSummary() + { + if (isset($this->_channelInfo['summary'])) { + return $this->_channelInfo['summary']; + } else { + return false; + } + } + + /** + * @param string xmlrpc or soap + * @param string|false mirror name or false for primary server + */ + function getPath($protocol, $mirror = false) + { + if (!in_array($protocol, array('xmlrpc', 'soap'))) { + return false; + } + if ($mirror) { + if (!($mir = $this->getMirror($mirror))) { + return false; + } + if (isset($mir[$protocol]['attribs']['path'])) { + return $mir[$protocol]['attribs']['path']; + } else { + return $protocol . '.php'; + } + } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) { + return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path']; + } + return $protocol . '.php'; + } + + /** + * @param string protocol type (xmlrpc, soap) + * @param string Mirror name + * @return array|false + */ + function getFunctions($protocol, $mirror = false) + { + if ($this->getName() == '__uri') { + return false; + } + if ($protocol == 'rest') { + $function = 'baseurl'; + } else { + $function = 'function'; + } + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir[$protocol][$function])) { + return $mir[$protocol][$function]; + } + } + return false; + } + if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { + return $this->_channelInfo['servers']['primary'][$protocol][$function]; + } else { + return false; + } + } + + /** + * @param string Protocol type + * @param string Function name (null to return the + * first protocol of the type requested) + * @param string Mirror name, if any + * @return array + */ + function getFunction($type, $name = null, $mirror = false) + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + foreach ($protocols as $protocol) { + if ($name === null) { + return $protocol; + } + if ($protocol['_content'] != $name) { + continue; + } + return $protocol; + } + return false; + } + + /** + * @param string protocol type + * @param string protocol name + * @param string version + * @param string mirror name + * @return boolean + */ + function supports($type, $name = null, $mirror = false, $version = '1.0') + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + foreach ($protocols as $protocol) { + if ($protocol['attribs']['version'] != $version) { + continue; + } + if ($name === null) { + return true; + } + if ($protocol['_content'] != $name) { + continue; + } + return true; + } + return false; + } + + /** + * Determines whether a channel supports Representational State Transfer (REST) protocols + * for retrieving channel information + * @param string + * @return bool + */ + function supportsREST($mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + return isset($mir['rest']); + } + return false; + } + return isset($this->_channelInfo['servers']['primary']['rest']); + } + + /** + * Get the URL to access a base resource. + * + * Hyperlinks in the returned xml will be used to retrieve the proper information + * needed. This allows extreme extensibility and flexibility in implementation + * @param string Resource Type to retrieve + */ + function getBaseURL($resourceType, $mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + $rest = $mir['rest']; + } else { + return false; + } + } else { + $rest = $this->_channelInfo['servers']['primary']['rest']; + } + if (!isset($rest['baseurl'][0])) { + $rest['baseurl'] = array($rest['baseurl']); + } + foreach ($rest['baseurl'] as $baseurl) { + if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { + return $baseurl['_content']; + } + } + return false; + } + + /** + * Since REST does not implement RPC, provide this as a logical wrapper around + * resetFunctions for REST + * @param string|false mirror name, if any + */ + function resetREST($mirror = false) + { + return $this->resetFunctions('rest', $mirror); + } + + /** + * Empty all protocol definitions + * @param string protocol type (xmlrpc, soap) + * @param string|false mirror name, if any + */ + function resetFunctions($type, $mirror = false) + { + if ($mirror) { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + foreach ($mirrors as $i => $mir) { + if ($mir['attribs']['host'] == $mirror) { + if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { + unset($this->_channelInfo['servers']['mirror'][$i][$type]); + } + return true; + } + } + return false; + } else { + return false; + } + } else { + if (isset($this->_channelInfo['servers']['primary'][$type])) { + unset($this->_channelInfo['servers']['primary'][$type]); + } + return true; + } + } + + /** + * Set a channel's protocols to the protocols supported by pearweb + */ + function setDefaultPEARProtocols($version = '1.0', $mirror = false) + { + switch ($version) { + case '1.0' : + $this->resetFunctions('xmlrpc', $mirror); + $this->resetFunctions('soap', $mirror); + $this->resetREST($mirror); + $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror); + $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror); + $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror); + $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror); + $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror); + return true; + break; + default : + return false; + break; + } + } + + /** + * @return array + */ + function getMirrors() + { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + return $mirrors; + } else { + return array(); + } + } + + /** + * Get the unserialized XML representing a mirror + * @return array|false + */ + function getMirror($server) + { + foreach ($this->getMirrors() as $mirror) { + if ($mirror['attribs']['host'] == $server) { + return $mirror; + } + } + return false; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_NAME + * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME + */ + function setName($name) + { + return $this->setServer($name); + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param integer + * @param string|false name of the mirror server, or false for the primary + */ + function setPort($port, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; + return true; + } + } + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + } + $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param bool Determines whether to turn on SSL support or turn it off + * @param string|false name of the mirror server, or false for the primary + */ + function setSSL($ssl = true, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror'][$i] + ['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; + } + return true; + } + } + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; + } + $this->_isValid = false; + return true; + } + } + if ($ssl) { + $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; + } else { + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); + } + } + $this->_isValid = false; + return true; + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param integer + * @param string|false name of the mirror server, or false for the primary + */ + function setPath($protocol, $path, $mirror = false) + { + if (!in_array($protocol, array('xmlrpc', 'soap'))) { + return false; + } + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] = + $path; + return true; + } + } + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path; + $this->_isValid = false; + return true; + } + } + $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path; + $this->_isValid = false; + return true; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_SERVER + * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER + */ + function setServer($server, $mirror = false) + { + if (empty($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); + return false; + } elseif (!$this->validChannelServer($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'name', 'name' => $server)); + return false; + } + if ($mirror) { + $found = false; + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $found = true; + break; + } + } + if (!$found) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; + return true; + } + $this->_channelInfo['name'] = $server; + return true; + } + + /** + * @param string + * @return boolean success + * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY + * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY + */ + function setSummary($summary) + { + if (empty($summary)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + return false; + } elseif (strpos(trim($summary), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $summary)); + } + $this->_channelInfo['summary'] = $summary; + return true; + } + + /** + * @param string + * @param boolean determines whether the alias is in channel.xml or local + * @return boolean success + */ + function setAlias($alias, $local = false) + { + if (!$this->validChannelServer($alias)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' => $alias)); + return false; + } + if ($local) { + $this->_channelInfo['localalias'] = $alias; + } else { + $this->_channelInfo['suggestedalias'] = $alias; + } + return true; + } + + /** + * @return string + */ + function getAlias() + { + if (isset($this->_channelInfo['localalias'])) { + return $this->_channelInfo['localalias']; + } + if (isset($this->_channelInfo['suggestedalias'])) { + return $this->_channelInfo['suggestedalias']; + } + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + return ''; + } + + /** + * Set the package validation object if it differs from PEAR's default + * The class must be includeable via changing _ in the classname to path separator, + * but no checking of this is made. + * @param string|false pass in false to reset to the default packagename regex + * @return boolean success + */ + function setValidationPackage($validateclass, $version) + { + if (empty($validateclass)) { + unset($this->_channelInfo['validatepackage']); + } + $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); + $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); + } + + /** + * Add a protocol to the provides section + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + * @param string mirror name, if this is a mirror's protocol + * @return bool + */ + function addFunction($type, $version, $name = '', $mirror = false) + { + if ($mirror) { + return $this->addMirrorFunction($mirror, $type, $version, $name); + } + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array($type => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array($type => array()); + } + $this->_channelInfo['servers']['primary'][$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { + $this->_channelInfo['servers']['primary'][$type]['function'] = array( + $this->_channelInfo['servers']['primary'][$type]['function']); + } + $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; + return true; + } + /** + * Add a protocol to a mirror's provides section + * @param string mirror name (server) + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + */ + function addMirrorFunction($mirror, $type, $version, $name = '') + { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + if (!$setmirror) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($setmirror[$type]['function'])) { + $setmirror[$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror[$type]['function'][0])) { + $setmirror[$type]['function'] = array($setmirror[$type]['function']); + } + $setmirror[$type]['function'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string Resource Type this url links to + * @param string URL + * @param string|false mirror name, if this is not a primary server REST base URL + */ + function setBaseURL($resourceType, $url, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + } else { + $setmirror = &$this->_channelInfo['servers']['primary']; + } + $set = array('attribs' => array('type' => $resourceType), '_content' => $url); + if (!isset($setmirror['rest'])) { + $setmirror['rest'] = array(); + } + if (!isset($setmirror['rest']['baseurl'])) { + $setmirror['rest']['baseurl'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror['rest']['baseurl'][0])) { + $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); + } + foreach ($setmirror['rest']['baseurl'] as $i => $url) { + if ($url['attribs']['type'] == $resourceType) { + $this->_isValid = false; + $setmirror['rest']['baseurl'][$i] = $set; + return true; + } + } + $setmirror['rest']['baseurl'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string mirror server + * @param int mirror http port + * @return boolean + */ + function addMirror($server, $port = null) + { + if ($this->_channelInfo['name'] == '__uri') { + return false; // the __uri channel cannot have mirrors by definition + } + $set = array('attribs' => array('host' => $server)); + if (is_numeric($port)) { + $set['attribs']['port'] = $port; + } + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_channelInfo['servers']['mirror'] = $set; + return true; + } else { + if (!isset($this->_channelInfo['servers']['mirror'][0])) { + $this->_channelInfo['servers']['mirror'] = + array($this->_channelInfo['servers']['mirror']); + } + } + $this->_channelInfo['servers']['mirror'][] = $set; + return true; + } + + /** + * Retrieve the name of the validation package for this channel + * @return string|false + */ + function getValidationPackage() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + if (!isset($this->_channelInfo['validatepackage'])) { + return array('attribs' => array('version' => 'default'), + '_content' => 'PEAR_Validate'); + } + return $this->_channelInfo['validatepackage']; + } + + /** + * Retrieve the object that can be used for custom validation + * @param string|false the name of the package to validate. If the package is + * the channel validation package, PEAR_Validate is returned + * @return PEAR_Validate|false false is returned if the validation package + * cannot be located + */ + function &getValidationObject($package = false) + { + if (!class_exists('PEAR_Validate')) { + require_once 'PEAR/Validate.php'; + } + if (!$this->_isValid) { + if (!$this->validate()) { + $a = false; + return $a; + } + } + if (isset($this->_channelInfo['validatepackage'])) { + if ($package == $this->_channelInfo['validatepackage']) { + // channel validation packages are always validated by PEAR_Validate + $val = &new PEAR_Validate; + return $val; + } + if (!class_exists(str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']))) { + if ($this->isIncludeable(str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php')) { + include_once str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php'; + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } else { + $a = false; + return $a; + } + } else { + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } + } else { + $val = &new PEAR_Validate; + } + return $val; + } + + function isIncludeable($path) + { + $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($possibilities as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $path) + && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { + return true; + } + } + return false; + } + + /** + * This function is used by the channel updater and retrieves a value set by + * the registry, or the current time if it has not been set + * @return string + */ + function lastModified() + { + if (isset($this->_channelInfo['_lastmodified'])) { + return $this->_channelInfo['_lastmodified']; + } + return time(); + } +} +?> diff --git a/vas/rest/class/PEAR/ChannelFile/Parser.php b/vas/rest/class/PEAR/ChannelFile/Parser.php new file mode 100755 index 0000000000000000000000000000000000000000..884024394a7eb4a0c800fc76aa103149e7edd846 --- /dev/null +++ b/vas/rest/class/PEAR/ChannelFile/Parser.php @@ -0,0 +1,73 @@ +<?php +/** + * PEAR_ChannelFile_Parser for parsing channel.xml + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Parser.php,v 1.5 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base xml parser class + */ +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/ChannelFile.php'; +/** + * Parser for channel.xml + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile_Parser extends PEAR_XMLParser +{ + var $_config; + var $_logger; + var $_registry; + + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + function parse($data, $file) + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; + } + $ret = new PEAR_ChannelFile; + $ret->setConfig($this->_config); + if (isset($this->_logger)) { + $ret->setLogger($this->_logger); + } + $ret->fromArray($this->_unserializedData); + // make sure the filelist is in the easy to read format needed + $ret->flattenFilelist(); + $ret->setPackagefile($file, $archive); + return $ret; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command.php b/vas/rest/class/PEAR/Command.php new file mode 100755 index 0000000000000000000000000000000000000000..38fe69c9eb4548f4aa636275443db88146c45ada --- /dev/null +++ b/vas/rest/class/PEAR/Command.php @@ -0,0 +1,416 @@ +<?php +/** + * PEAR_Command, command pattern class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Command.php,v 1.39 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Frontend.php'; +require_once 'PEAR/XMLParser.php'; + +/** + * List of commands and what classes they are implemented in. + * @var array command => implementing class + */ +$GLOBALS['_PEAR_Command_commandlist'] = array(); + +/** + * List of commands and their descriptions + * @var array command => description + */ +$GLOBALS['_PEAR_Command_commanddesc'] = array(); + +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + +/** + * Array of command objects + * @var array class => object + */ +$GLOBALS['_PEAR_Command_objects'] = array(); + +/** + * PEAR command class, a simple factory class for administrative + * commands. + * + * How to implement command classes: + * + * - The class must be called PEAR_Command_Nnn, installed in the + * "PEAR/Common" subdir, with a method called getCommands() that + * returns an array of the commands implemented by the class (see + * PEAR/Command/Install.php for an example). + * + * - The class must implement a run() function that is called with three + * params: + * + * (string) command name + * (array) assoc array with options, freely defined by each + * command, for example: + * array('force' => true) + * (array) list of the other parameters + * + * The run() function returns a PEAR_CommandResponse object. Use + * these methods to get information: + * + * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) + * *_PARTIAL means that you need to issue at least + * one more command to complete the operation + * (used for example for validation steps). + * + * string getMessage() Returns a message for the user. Remember, + * no HTML or other interface-specific markup. + * + * If something unexpected happens, run() returns a PEAR error. + * + * - DON'T OUTPUT ANYTHING! Return text for output instead. + * + * - DON'T USE HTML! The text you return will be used from both Gtk, + * web and command-line interfaces, so for now, keep everything to + * plain text. + * + * - DON'T USE EXIT OR DIE! Always use pear errors. From static + * classes do PEAR::raiseError(), from other classes do + * $this->raiseError(). + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command +{ + // {{{ factory() + + /** + * Get the right object for executing a command. + * + * @param string $command The name of the command + * @param object $config Instance of PEAR_Config object + * + * @return object the command object or a PEAR error + * + * @access public + * @static + */ + function &factory($command, &$config) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $ui =& PEAR_Command::getFrontendObject(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getObject() + function &getObject($command) + { + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + return PEAR::raiseError("unknown command `$command'"); + } + $ui =& PEAR_Command::getFrontendObject(); + $config = &PEAR_Config::singleton(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getFrontendObject() + + /** + * Get instance of frontend object. + * + * @return object|PEAR_Error + * @static + */ + function &getFrontendObject() + { + $a = &PEAR_Frontend::singleton(); + return $a; + } + + // }}} + // {{{ & setFrontendClass() + + /** + * Load current frontend class. + * + * @param string $uiclass Name of class implementing the frontend + * + * @return object the frontend object, or a PEAR error + * @static + */ + function &setFrontendClass($uiclass) + { + $a = &PEAR_Frontend::setFrontendClass($uiclass); + return $a; + } + + // }}} + // {{{ setFrontendType() + + /** + * Set current frontend. + * + * @param string $uitype Name of the frontend type (for example "CLI") + * + * @return object the frontend object, or a PEAR error + * @static + */ + function setFrontendType($uitype) + { + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); + } + + // }}} + // {{{ registerCommands() + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * + * @param bool (optional) if FALSE (default), the new list of + * commands should replace the current one. If TRUE, + * new entries will be merged with old. + * + * @param string (optional) where (what directory) to look for + * classes, defaults to the Command subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * + * @access public + * @static + */ + function registerCommands($merge = false, $dir = null) + { + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Command'; + } + if (!is_dir($dir)) { + return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); + } + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerCommands: opendir($dir) failed"); + } + if (!$merge) { + $GLOBALS['_PEAR_Command_commandlist'] = array(); + } + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + continue; + } + $class = "PEAR_Command_".substr($entry, 0, -4); + $file = "$dir/$entry"; + $parser->parse(file_get_contents($file)); + $implements = $parser->getData(); + // List of commands + if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { + $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) . + '.php'; + } + foreach ($implements as $command => $desc) { + if ($command == 'attribs') { + continue; + } + if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return PEAR::raiseError('Command "' . $command . '" already registered in ' . + 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; + $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; + if (isset($desc['shortcut'])) { + $shortcut = $desc['shortcut']; + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { + return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . + 'registered to command "' . $command . '" in class "' . + $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } + if (isset($desc['options']) && $desc['options']) { + foreach ($desc['options'] as $oname => $option) { + if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { + return PEAR::raiseError('Option "' . $oname . '" short option "' . + $option['shortopt'] . '" must be ' . + 'only 1 character in Command "' . $command . '" in class "' . + $class . '"'); + } + } + } + } + } + ksort($GLOBALS['_PEAR_Command_shortcuts']); + ksort($GLOBALS['_PEAR_Command_commandlist']); + @closedir($dp); + return true; + } + + // }}} + // {{{ getCommands() + + /** + * Get the list of currently supported commands, and what + * classes implement them. + * + * @return array command => implementing class + * + * @access public + * @static + */ + function getCommands() + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandlist']; + } + + // }}} + // {{{ getShortcuts() + + /** + * Get the list of command shortcuts. + * + * @return array shortcut => command + * + * @access public + * @static + */ + function getShortcuts() + { + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_shortcuts']; + } + + // }}} + // {{{ getGetoptArgs() + + /** + * Compiles arguments for getopt. + * + * @param string $command command to get optstring for + * @param string $short_args (reference) short getopt format + * @param array $long_args (reference) long getopt format + * + * @return void + * + * @access public + * @static + */ + function getGetoptArgs($command, &$short_args, &$long_args) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return null; + } + $obj = &PEAR_Command::getObject($command); + return $obj->getGetoptArgs($command, $short_args, $long_args); + } + + // }}} + // {{{ getDescription() + + /** + * Get description for a command. + * + * @param string $command Name of the command + * + * @return string command description + * + * @access public + * @static + */ + function getDescription($command) + { + if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { + return null; + } + return $GLOBALS['_PEAR_Command_commanddesc'][$command]; + } + + // }}} + // {{{ getHelp() + + /** + * Get help for command. + * + * @param string $command Name of the command to return help for + * + * @access public + * @static + */ + function getHelp($command) + { + $cmds = PEAR_Command::getCommands(); + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (isset($cmds[$command])) { + $obj = &PEAR_Command::getObject($command); + return $obj->getHelp($command); + } + return false; + } + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Command/Auth.php b/vas/rest/class/PEAR/Command/Auth.php new file mode 100755 index 0000000000000000000000000000000000000000..005235b63b4906ca7181f6976da920ed2f6ce2d0 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Auth.php @@ -0,0 +1,203 @@ +<?php +/** + * PEAR_Command_Auth (login, logout commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Auth.php,v 1.31 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; +require_once 'PEAR/Config.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Auth extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'login' => array( + 'summary' => 'Connects and authenticates to remote server', + 'shortcut' => 'li', + 'function' => 'doLogin', + 'options' => array(), + 'doc' => '<channel name> +Log in to a remote channel server. If <channel name> is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.', + ), + 'logout' => array( + 'summary' => 'Logs out from the remote server', + 'shortcut' => 'lo', + 'function' => 'doLogout', + 'options' => array(), + 'doc' => ' +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration.', + ) + + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Auth constructor. + * + * @access public + */ + function PEAR_Command_Auth(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doLogin() + + /** + * Execute the 'login' command. + * + * @param string $command command name + * + * @param array $options option_name => value + * + * @param array $params list of additional parameters + * + * @return bool TRUE on success or + * a PEAR error on failure + * + * @access public + */ + function doLogin($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + + // If a parameter is supplied, use that as the channel to log in to + if (isset($params[0])) { + $channel = $params[0]; + } else { + $channel = $this->config->get('default_channel'); + } + + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + $server = $this->config->get('preferred_mirror', null, $channel); + $remote = &$this->config->getRemote(); + $username = $this->config->get('username', null, $channel); + if (empty($username)) { + $username = isset($_ENV['USER']) ? $_ENV['USER'] : null; + } + $this->ui->outputData("Logging in to $server.", $command); + + list($username, $password) = $this->ui->userDialog( + $command, + array('Username', 'Password'), + array('text', 'password'), + array($username, '') + ); + $username = trim($username); + $password = trim($password); + + $ourfile = $this->config->getConfFile('user'); + if (!$ourfile) { + $ourfile = $this->config->getConfFile('system'); + } + + $this->config->set('username', $username, 'user', $channel); + $this->config->set('password', $password, 'user', $channel); + + if ($chan->supportsREST()) { + $ok = true; + } else { + $remote->expectError(401); + $ok = $remote->call('logintest'); + $remote->popExpect(); + } + if ($ok === true) { + $this->ui->outputData("Logged in.", $command); + // avoid changing any temporary settings changed with -d + $ourconfig = new PEAR_Config($ourfile, $ourfile); + $ourconfig->set('username', $username, 'user', $channel); + $ourconfig->set('password', $password, 'user', $channel); + $ourconfig->store(); + } else { + return $this->raiseError("Login failed!"); + } + return true; + } + + // }}} + // {{{ doLogout() + + /** + * Execute the 'logout' command. + * + * @param string $command command name + * + * @param array $options option_name => value + * + * @param array $params list of additional parameters + * + * @return bool TRUE on success or + * a PEAR error on failure + * + * @access public + */ + function doLogout($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $channel = $this->config->get('default_channel'); + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + $server = $this->config->get('preferred_mirror'); + $this->ui->outputData("Logging out from $server.", $command); + $this->config->remove('username'); + $this->config->remove('password'); + $this->config->store(); + return true; + } + + // }}} +} + +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Auth.xml b/vas/rest/class/PEAR/Command/Auth.xml new file mode 100755 index 0000000000000000000000000000000000000000..17e3b34cf5b1b057cd733a2df00252d664f926bc --- /dev/null +++ b/vas/rest/class/PEAR/Command/Auth.xml @@ -0,0 +1,26 @@ +<commands version="1.0"> + <login> + <summary>Connects and authenticates to remote server</summary> + <shortcut>li</shortcut> + <function>doLogin</function> + <options /> + <doc><channel name> +Log in to a remote channel server. <channel name> is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.</doc> + </login> + <logout> + <summary>Logs out from the remote server</summary> + <shortcut>lo</shortcut> + <function>doLogout</function> + <options /> + <doc> +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration.</doc> + </logout> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Build.php b/vas/rest/class/PEAR/Command/Build.php new file mode 100755 index 0000000000000000000000000000000000000000..d6773100e46c5853e0df549cb84a18132632b6c2 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Build.php @@ -0,0 +1,104 @@ +<?php +/** + * PEAR_Command_Auth (build command) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Build.php,v 1.14 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for building extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Build extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'build' => array( + 'summary' => 'Build an Extension From C Source', + 'function' => 'doBuild', + 'shortcut' => 'b', + 'options' => array(), + 'doc' => '[package.xml] +Builds one or more extensions contained in a package.' + ), + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Build constructor. + * + * @access public + */ + function PEAR_Command_Build(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doBuild() + + function doBuild($command, $options, $params) + { + require_once 'PEAR/Builder.php'; + if (sizeof($params) < 1) { + $params[0] = 'package.xml'; + } + $builder = &new PEAR_Builder($this->ui); + $this->debug = $this->config->get('verbose'); + $err = $builder->build($params[0], array(&$this, 'buildCallback')); + if (PEAR::isError($err)) { + return $err; + } + return true; + } + + // }}} + // {{{ buildCallback() + + function buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } + + // }}} +} diff --git a/vas/rest/class/PEAR/Command/Build.xml b/vas/rest/class/PEAR/Command/Build.xml new file mode 100755 index 0000000000000000000000000000000000000000..ec4e6f554ca148bf583c77642aa087620a4a46cd --- /dev/null +++ b/vas/rest/class/PEAR/Command/Build.xml @@ -0,0 +1,10 @@ +<commands version="1.0"> + <build> + <summary>Build an Extension From C Source</summary> + <function>doBuild</function> + <shortcut>b</shortcut> + <options /> + <doc>[package.xml] +Builds one or more extensions contained in a package.</doc> + </build> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Channels.php b/vas/rest/class/PEAR/Command/Channels.php new file mode 100755 index 0000000000000000000000000000000000000000..5de0d39b9c25fb65539e983eaa92a5c4ebd57d82 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Channels.php @@ -0,0 +1,737 @@ +<?php +// /* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** + * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add, + * channel-update, channel-info, channel-alias, channel-discover commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Channels.php,v 1.57 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for managing channels. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Command_Channels extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'list-channels' => array( + 'summary' => 'List Available Channels', + 'function' => 'doList', + 'shortcut' => 'lc', + 'options' => array(), + 'doc' => ' +List all available channels for installation. +', + ), + 'update-channels' => array( + 'summary' => 'Update the Channel List', + 'function' => 'doUpdateAll', + 'shortcut' => 'uc', + 'options' => array(), + 'doc' => ' +List all installed packages in all channels. +' + ), + 'channel-delete' => array( + 'summary' => 'Remove a Channel From the List', + 'function' => 'doDelete', + 'shortcut' => 'cde', + 'options' => array(), + 'doc' => '<channel name> +Delete a channel from the registry. You may not +remove any channel that has installed packages. +' + ), + 'channel-add' => array( + 'summary' => 'Add a Channel', + 'function' => 'doAdd', + 'shortcut' => 'ca', + 'options' => array(), + 'doc' => '<channel.xml> +Add a private channel to the channel list. Note that all +public channels should be synced using "update-channels". +Parameter may be either a local file or remote URL to a +channel.xml. +' + ), + 'channel-update' => array( + 'summary' => 'Update an Existing Channel', + 'function' => 'doUpdate', + 'shortcut' => 'cu', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will force download of new channel.xml if an existing channel name is used', + ), + 'channel' => array( + 'shortopt' => 'c', + 'arg' => 'CHANNEL', + 'doc' => 'will force download of new channel.xml if an existing channel name is used', + ), +), + 'doc' => '[<channel.xml>|<channel name>] +Update a channel in the channel list directly. Note that all +public channels can be synced using "update-channels". +Parameter may be a local or remote channel.xml, or the name of +an existing channel. +' + ), + 'channel-info' => array( + 'summary' => 'Retrieve Information on a Channel', + 'function' => 'doInfo', + 'shortcut' => 'ci', + 'options' => array(), + 'doc' => '<package> +List the files in an installed package. +' + ), + 'channel-alias' => array( + 'summary' => 'Specify an alias to a channel name', + 'function' => 'doAlias', + 'shortcut' => 'cha', + 'options' => array(), + 'doc' => '<channel> <alias> +Specify a specific alias to use for a channel name. +The alias may not be an existing channel name or +alias. +' + ), + 'channel-discover' => array( + 'summary' => 'Initialize a Channel from its server', + 'function' => 'doDiscover', + 'shortcut' => 'di', + 'options' => array(), + 'doc' => '[<channel.xml>|<channel name>] +Initialize a channel from its server and create a local channel.xml. +If <channel name> is in the format "<username>:<password>@<channel>" then +<username> and <password> will be set as the login username/password for +<channel>. Use caution when passing the username/password in this way, as +it may allow other users on your computer to briefly view your username/ +password via the system\'s process list. +' + ), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Channels(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doList() + + function _sortChannels($a, $b) + { + return strnatcasecmp($a->getName(), $b->getName()); + } + + function doList($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $registered = $reg->getChannels(); + usort($registered, array(&$this, '_sortchannels')); + $i = $j = 0; + $data = array( + 'caption' => 'Registered Channels:', + 'border' => true, + 'headline' => array('Channel', 'Summary') + ); + foreach ($registered as $channel) { + $data['data'][] = array($channel->getName(), + $channel->getSummary()); + } + if (count($registered)==0) { + $data = '(no registered channels)'; + } + $this->ui->outputData($data, $command); + return true; + } + + function doUpdateAll($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $channels = $reg->getChannels(); + + $success = true; + foreach ($channels as $channel) { + if ($channel->getName() != '__uri') { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->doUpdate('channel-update', + $options, + array($channel->getName())); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + $success = false; + } else { + $success &= $err; + } + } + } + return $success; + } + + function doInfo($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError("No channel specified"); + } + $reg = &$this->config->getRegistry(); + $channel = strtolower($params[0]); + if ($reg->channelExists($channel)) { + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + } else { + if (strpos($channel, '://')) { + $downloader = &$this->getDownloader(); + $tmpdir = $this->config->get('temp_dir'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError('Cannot open "' . $channel . + '" (' . $loc->getMessage() . ')'); + } else { + $contents = implode('', file($loc)); + } + } else { + if (file_exists($params[0])) { + $fp = fopen($params[0], 'r'); + if (!$fp) { + return $this->raiseError('Cannot open "' . $params[0] . '"'); + } + } else { + return $this->raiseError('Unknown channel "' . $channel . '"'); + } + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $chan = new PEAR_ChannelFile; + $chan->fromXmlString($contents); + $chan->validate(); + if ($errs = $chan->getErrors(true)) { + foreach ($errs as $err) { + $this->ui->outputData($err['level'] . ': ' . $err['message']); + } + return $this->raiseError('Channel file "' . $params[0] . '" is not valid'); + } + } + if ($chan) { + $channel = $chan->getName(); + $caption = 'Channel ' . $channel . ' Information:'; + $data1 = array( + 'caption' => $caption, + 'border' => true); + $data1['data']['server'] = array('Name and Server', $chan->getName()); + if ($chan->getAlias() != $chan->getName()) { + $data1['data']['alias'] = array('Alias', $chan->getAlias()); + } + $data1['data']['summary'] = array('Summary', $chan->getSummary()); + $validate = $chan->getValidationPackage(); + $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']); + $data1['data']['vpackageversion'] = + array('Validation Package Version', $validate['attribs']['version']); + $d = array(); + $d['main'] = $data1; + + $data['data'] = array(); + $data['caption'] = 'Server Capabilities'; + $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); + $capabilities = $chan->getFunctions('xmlrpc'); + $soaps = $chan->getFunctions('soap'); + if ($capabilities || $soaps || $chan->supportsREST()) { + if ($capabilities) { + if (!isset($capabilities[0])) { + $capabilities = array($capabilities); + } + foreach ($capabilities as $protocol) { + $data['data'][] = array('xmlrpc', $protocol['attribs']['version'], + $protocol['_content']); + } + } + if ($soaps) { + if (!isset($soaps[0])) { + $soaps = array($soaps); + } + foreach ($soaps as $protocol) { + $data['data'][] = array('soap', $protocol['attribs']['version'], + $protocol['_content']); + } + } + if ($chan->supportsREST()) { + $funcs = $chan->getFunctions('rest'); + if (!isset($funcs[0])) { + $funcs = array($funcs); + } + foreach ($funcs as $protocol) { + $data['data'][] = array('rest', $protocol['attribs']['type'], + $protocol['_content']); + } + } + } else { + $data['data'][] = array('No supported protocols'); + } + $d['protocols'] = $data; + $data['data'] = array(); + $mirrors = $chan->getMirrors(); + if ($mirrors) { + $data['caption'] = 'Channel ' . $channel . ' Mirrors:'; + unset($data['headline']); + foreach ($mirrors as $mirror) { + $data['data'][] = array($mirror['attribs']['host']); + $d['mirrors'] = $data; + } + foreach ($mirrors as $i => $mirror) { + $data['data'] = array(); + $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities'; + $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); + $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']); + $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']); + if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) { + if ($capabilities) { + if (!isset($capabilities[0])) { + $capabilities = array($capabilities); + } + foreach ($capabilities as $protocol) { + $data['data'][] = array('xmlrpc', $protocol['attribs']['version'], + $protocol['_content']); + } + } + if ($soaps) { + if (!isset($soaps[0])) { + $soaps = array($soaps); + } + foreach ($soaps as $protocol) { + $data['data'][] = array('soap', $protocol['attribs']['version'], + $protocol['_content']); + } + } + if ($chan->supportsREST($mirror['attribs']['host'])) { + $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']); + if (!isset($funcs[0])) { + $funcs = array($funcs); + } + foreach ($funcs as $protocol) { + $data['data'][] = array('rest', $protocol['attribs']['type'], + $protocol['_content']); + } + } + } else { + $data['data'][] = array('No supported protocols'); + } + $d['mirrorprotocols' . $i] = $data; + } + } + $this->ui->outputData($d, 'channel-info'); + } else { + return $this->raiseError('Serious error: Channel "' . $params[0] . + '" has a corrupted registry entry'); + } + } + + // }}} + + function doDelete($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError('channel-delete: no channel specified'); + } + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($params[0])) { + return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist'); + } + $channel = $reg->channelName($params[0]); + if ($channel == 'pear.php.net') { + return $this->raiseError('Cannot delete the pear.php.net channel'); + } + if ($channel == 'pecl.php.net') { + return $this->raiseError('Cannot delete the pecl.php.net channel'); + } + if ($channel == '__uri') { + return $this->raiseError('Cannot delete the __uri pseudo-channel'); + } + if (PEAR::isError($err = $reg->listPackages($channel))) { + return $err; + } + if (count($err)) { + return $this->raiseError('Channel "' . $channel . + '" has installed packages, cannot delete'); + } + if (!$reg->deleteChannel($channel)) { + return $this->raiseError('Channel "' . $channel . '" deletion failed'); + } else { + $this->config->deleteChannel($channel); + $this->ui->outputData('Channel "' . $channel . '" deleted', $command); + } + } + + function doAdd($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError('channel-add: no channel file specified'); + } + if (strpos($params[0], '://')) { + $downloader = &$this->getDownloader(); + $tmpdir = $this->config->get('temp_dir'); + if (!file_exists($tmpdir)) { + require_once 'System.php'; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = System::mkdir(array('-p', $tmpdir)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError('channel-add: temp_dir does not exist: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + } + if (!is_writable($tmpdir)) { + return $this->raiseError('channel-add: temp_dir is not writable: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError('channel-add: Cannot open "' . $params[0] . + '" (' . $loc->getMessage() . ')'); + } else { + list($loc, $lastmodified) = $loc; + $contents = implode('', file($loc)); + } + } else { + $lastmodified = $fp = false; + if (file_exists($params[0])) { + $fp = fopen($params[0], 'r'); + } + if (!$fp) { + return $this->raiseError('channel-add: cannot open "' . $params[0] . '"'); + } + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $channel = new PEAR_ChannelFile; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $result = $channel->fromXmlString($contents); + PEAR::staticPopErrorHandling(); + if (!$result) { + $exit = false; + if (count($errors = $channel->getErrors(true))) { + foreach ($errors as $error) { + $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); + if (!$exit) { + $exit = $error['level'] == 'error' ? true : false; + } + } + if ($exit) { + return $this->raiseError('channel-add: invalid channel.xml file'); + } + } + } + $reg = &$this->config->getRegistry(); + if ($reg->channelExists($channel->getName())) { + return $this->raiseError('channel-add: Channel "' . $channel->getName() . + '" exists, use channel-update to update entry'); + } + $ret = $reg->addChannel($channel, $lastmodified); + if (PEAR::isError($ret)) { + return $ret; + } + if (!$ret) { + return $this->raiseError('channel-add: adding Channel "' . $channel->getName() . + '" to registry failed'); + } + $this->config->setChannels($reg->listChannels()); + $this->config->writeConfigFile(); + $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command); + } + + function doUpdate($command, $options, $params) + { + $tmpdir = $this->config->get('temp_dir'); + if (!file_exists($tmpdir)) { + require_once 'System.php'; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = System::mkdir(array('-p', $tmpdir)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError('channel-add: temp_dir does not exist: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + } + if (!is_writable($tmpdir)) { + return $this->raiseError('channel-add: temp_dir is not writable: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + $reg = &$this->config->getRegistry(); + if (sizeof($params) != 1) { + return $this->raiseError("No channel file specified"); + } + $lastmodified = false; + if ((!file_exists($params[0]) || is_dir($params[0])) + && $reg->channelExists(strtolower($params[0]))) { + $c = $reg->getChannel(strtolower($params[0])); + if (PEAR::isError($c)) { + return $this->raiseError($c); + } + $this->ui->outputData("Updating channel \"$params[0]\"", $command); + $dl = &$this->getDownloader(array()); + // if force is specified, use a timestamp of "1" to force retrieval + $lastmodified = isset($options['force']) ? false : $c->lastModified(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml', + $this->ui, $tmpdir, null, $lastmodified); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($contents)) { + return $this->raiseError('Cannot retrieve channel.xml for channel "' . + $c->getName() . '" (' . $contents->getMessage() . ')'); + } + list($contents, $lastmodified) = $contents; + if (!$contents) { + $this->ui->outputData("Channel \"$params[0]\" is up to date"); + return; + } + $contents = implode('', file($contents)); + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $channel = new PEAR_ChannelFile; + $channel->fromXmlString($contents); + if (!$channel->getErrors()) { + // security check: is the downloaded file for the channel we got it from? + if (strtolower($channel->getName()) != strtolower($c->getName())) { + if (isset($options['force'])) { + $this->ui->log(0, 'WARNING: downloaded channel definition file' . + ' for channel "' . $channel->getName() . '" from channel "' . + strtolower($c->getName()) . '"'); + } else { + return $this->raiseError('ERROR: downloaded channel definition file' . + ' for channel "' . $channel->getName() . '" from channel "' . + strtolower($c->getName()) . '"'); + } + } + } + } else { + if (strpos($params[0], '://')) { + $dl = &$this->getDownloader(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $dl->downloadHttp($params[0], + $this->ui, $tmpdir, null, $lastmodified); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError("Cannot open " . $params[0] . + ' (' . $loc->getMessage() . ')'); + } else { + list($loc, $lastmodified) = $loc; + $contents = implode('', file($loc)); + } + } else { + $fp = false; + if (file_exists($params[0])) { + $fp = fopen($params[0], 'r'); + } + if (!$fp) { + return $this->raiseError("Cannot open " . $params[0]); + } + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $channel = new PEAR_ChannelFile; + $channel->fromXmlString($contents); + } + $exit = false; + if (count($errors = $channel->getErrors(true))) { + foreach ($errors as $error) { + $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); + if (!$exit) { + $exit = $error['level'] == 'error' ? true : false; + } + } + if ($exit) { + return $this->raiseError('Invalid channel.xml file'); + } + } + if (!$reg->channelExists($channel->getName())) { + return $this->raiseError('Error: Channel "' . $channel->getName() . + '" does not exist, use channel-add to add an entry'); + } + $ret = $reg->updateChannel($channel, $lastmodified); + if (PEAR::isError($ret)) { + return $ret; + } + if (!$ret) { + return $this->raiseError('Updating Channel "' . $channel->getName() . + '" in registry failed'); + } + $this->config->setChannels($reg->listChannels()); + $this->config->writeConfigFile(); + $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded'); + } + + function &getDownloader() + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = new PEAR_Downloader($this->ui, array(), $this->config); + return $a; + } + + function doAlias($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + if (sizeof($params) == 1) { + return $this->raiseError('No channel alias specified'); + } + if (sizeof($params) != 2) { + return $this->raiseError( + 'Invalid format, correct is: channel-alias channel alias'); + } + if (!$reg->channelExists($params[0], true)) { + if ($reg->isAlias($params[0])) { + $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' . + strtolower($params[1]) . '")'; + } else { + $extra = ''; + } + return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra); + } + if ($reg->isAlias($params[1])) { + return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' . + 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias'); + } + $chan = &$reg->getChannel($params[0]); + if (PEAR::isError($chan)) { + return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] . + '" information (' . $chan->getMessage() . ')'); + } + // make it a local alias + if (!$chan->setAlias(strtolower($params[1]), true)) { + return $this->raiseError('Alias "' . strtolower($params[1]) . + '" is not a valid channel alias'); + } + $reg->updateChannel($chan); + $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' . + strtolower($params[1]) . '"'); + } + + /** + * The channel-discover command + * + * @param string $command command name + * @param array $options option_name => value + * @param array $params list of additional parameters. + * $params[0] should contain a string with either: + * - <channel name> or + * - <username>:<password>@<channel name> + * @return null|PEAR_Error + */ + function doDiscover($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + if (sizeof($params) != 1) { + return $this->raiseError("No channel server specified"); + } + + // Look for the possible input format "<username>:<password>@<channel>" + if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) { + $username = $matches[1]; + $password = $matches[2]; + $channel = $matches[3]; + } else { + $channel = $params[0]; + } + + if ($reg->channelExists($channel)) { + if ($reg->isAlias($channel)) { + return $this->raiseError("A channel alias named \"$channel\" " . + 'already exists, aliasing channel "' . $reg->channelName($channel) + . '"'); + } else { + return $this->raiseError("Channel \"$channel\" is already initialized"); + } + } + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml')); + $this->popErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError("Discovery of channel \"$channel\" failed (" . + $err->getMessage() . ')'); + } + + // Store username/password if they were given + // Arguably we should do a logintest on the channel here, but since + // that's awkward on a REST-based channel (even "pear login" doesn't + // do it for those), and XML-RPC is deprecated, it's fairly pointless. + if (isset($username)) { + $this->config->set('username', $username, 'user', $channel); + $this->config->set('password', $password, 'user', $channel); + $this->config->store(); + $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command); + } + + $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command); + } +} +?> diff --git a/vas/rest/class/PEAR/Command/Channels.xml b/vas/rest/class/PEAR/Command/Channels.xml new file mode 100755 index 0000000000000000000000000000000000000000..e7c7b7fe67f5f52ce4f8499856908834f68c4df4 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Channels.xml @@ -0,0 +1,98 @@ +<commands version="1.0"> + <list-channels> + <summary>List Available Channels</summary> + <function>doList</function> + <shortcut>lc</shortcut> + <options /> + <doc> +List all available channels for installation. +</doc> + </list-channels> + <update-channels> + <summary>Update the Channel List</summary> + <function>doUpdateAll</function> + <shortcut>uc</shortcut> + <options /> + <doc> +List all installed packages in all channels. +</doc> + </update-channels> + <channel-delete> + <summary>Remove a Channel From the List</summary> + <function>doDelete</function> + <shortcut>cde</shortcut> + <options /> + <doc><channel name> +Delete a channel from the registry. You may not +remove any channel that has installed packages. +</doc> + </channel-delete> + <channel-add> + <summary>Add a Channel</summary> + <function>doAdd</function> + <shortcut>ca</shortcut> + <options /> + <doc><channel.xml> +Add a private channel to the channel list. Note that all +public channels should be synced using "update-channels". +Parameter may be either a local file or remote URL to a +channel.xml. +</doc> + </channel-add> + <channel-update> + <summary>Update an Existing Channel</summary> + <function>doUpdate</function> + <shortcut>cu</shortcut> + <options> + <force> + <shortopt>f</shortopt> + <doc>will force download of new channel.xml if an existing channel name is used</doc> + </force> + <channel> + <shortopt>c</shortopt> + <arg>CHANNEL</arg> + <doc>will force download of new channel.xml if an existing channel name is used</doc> + </channel> + </options> + <doc>[<channel.xml>|<channel name>] +Update a channel in the channel list directly. Note that all +public channels can be synced using "update-channels". +Parameter may be a local or remote channel.xml, or the name of +an existing channel. +</doc> + </channel-update> + <channel-info> + <summary>Retrieve Information on a Channel</summary> + <function>doInfo</function> + <shortcut>ci</shortcut> + <options /> + <doc><package> +List the files in an installed package. +</doc> + </channel-info> + <channel-alias> + <summary>Specify an alias to a channel name</summary> + <function>doAlias</function> + <shortcut>cha</shortcut> + <options /> + <doc><channel> <alias> +Specify a specific alias to use for a channel name. +The alias may not be an existing channel name or +alias. +</doc> + </channel-alias> + <channel-discover> + <summary>Initialize a Channel from its server</summary> + <function>doDiscover</function> + <shortcut>di</shortcut> + <options /> + <doc>[<channel.xml>|<channel name>] +Initialize a channel from its server and create a local channel.xml. +If <channel name> is in the format "<username>:<password>@<channel>" then +<username> and <password> will be set as the login username/password for +<channel>. Use caution when passing the username/password in this way, as +it may allow other users on your computer to briefly view your username/ +password via the system's process list. +</doc> + </channel-discover> +</commands> diff --git a/vas/rest/class/PEAR/Command/Common.php b/vas/rest/class/PEAR/Command/Common.php new file mode 100755 index 0000000000000000000000000000000000000000..41595403bd28e74cc40def43e6e817f0b5eeb556 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Common.php @@ -0,0 +1,291 @@ +<?php +/** + * PEAR_Command_Common base class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Common.php,v 1.36 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR.php'; + +/** + * PEAR commands base class + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Common extends PEAR +{ + // {{{ properties + + /** + * PEAR_Config object used to pass user system and configuration + * on when executing commands + * + * @var PEAR_Config + */ + var $config; + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; + + /** + * User Interface object, for all interaction with the user. + * @var object + */ + var $ui; + + var $_deps_rel_trans = array( + 'lt' => '<', + 'le' => '<=', + 'eq' => '=', + 'ne' => '!=', + 'gt' => '>', + 'ge' => '>=', + 'has' => '==' + ); + + var $_deps_type_trans = array( + 'pkg' => 'package', + 'ext' => 'extension', + 'php' => 'PHP', + 'prog' => 'external program', + 'ldlib' => 'external library for linking', + 'rtlib' => 'external runtime library', + 'os' => 'operating system', + 'websrv' => 'web server', + 'sapi' => 'SAPI backend' + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Common constructor. + * + * @access public + */ + function PEAR_Command_Common(&$ui, &$config) + { + parent::PEAR(); + $this->config = &$config; + $this->ui = &$ui; + } + + // }}} + + // {{{ getCommands() + + /** + * Return a list of all the commands defined by this class. + * @return array list of commands + * @access public + */ + function getCommands() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + $ret[$command] = $this->commands[$command]['summary']; + } + return $ret; + } + + // }}} + // {{{ getShortcuts() + + /** + * Return a list of all the command shortcuts defined by this class. + * @return array shortcut => command + * @access public + */ + function getShortcuts() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + if (isset($this->commands[$command]['shortcut'])) { + $ret[$this->commands[$command]['shortcut']] = $command; + } + } + return $ret; + } + + // }}} + // {{{ getOptions() + + function getOptions($command) + { + $shortcuts = $this->getShortcuts(); + if (isset($shortcuts[$command])) { + $command = $shortcuts[$command]; + } + if (isset($this->commands[$command]) && + isset($this->commands[$command]['options'])) { + return $this->commands[$command]['options']; + } else { + return null; + } + } + + // }}} + // {{{ getGetoptArgs() + + function getGetoptArgs($command, &$short_args, &$long_args) + { + $short_args = ""; + $long_args = array(); + if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { + return; + } + reset($this->commands[$command]['options']); + while (list($option, $info) = each($this->commands[$command]['options'])) { + $larg = $sarg = ''; + if (isset($info['arg'])) { + if ($info['arg']{0} == '(') { + $larg = '=='; + $sarg = '::'; + $arg = substr($info['arg'], 1, -1); + } else { + $larg = '='; + $sarg = ':'; + $arg = $info['arg']; + } + } + if (isset($info['shortopt'])) { + $short_args .= $info['shortopt'] . $sarg; + } + $long_args[] = $option . $larg; + } + } + + // }}} + // {{{ getHelp() + /** + * Returns the help message for the given command + * + * @param string $command The command + * @return mixed A fail string if the command does not have help or + * a two elements array containing [0]=>help string, + * [1]=> help string for the accepted cmd args + */ + function getHelp($command) + { + $config = &PEAR_Config::singleton(); + if (!isset($this->commands[$command])) { + return "No such command \"$command\""; + } + $help = null; + if (isset($this->commands[$command]['doc'])) { + $help = $this->commands[$command]['doc']; + } + if (empty($help)) { + // XXX (cox) Fallback to summary if there is no doc (show both?) + if (!isset($this->commands[$command]['summary'])) { + return "No help for command \"$command\""; + } + $help = $this->commands[$command]['summary']; + } + if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { + foreach($matches[0] as $k => $v) { + $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); + } + } + return array($help, $this->getHelpArgs($command)); + } + + // }}} + // {{{ getHelpArgs() + /** + * Returns the help for the accepted arguments of a command + * + * @param string $command + * @return string The help string + */ + function getHelpArgs($command) + { + if (isset($this->commands[$command]['options']) && + count($this->commands[$command]['options'])) + { + $help = "Options:\n"; + foreach ($this->commands[$command]['options'] as $k => $v) { + if (isset($v['arg'])) { + if ($v['arg'][0] == '(') { + $arg = substr($v['arg'], 1, -1); + $sapp = " [$arg]"; + $lapp = "[=$arg]"; + } else { + $sapp = " $v[arg]"; + $lapp = "=$v[arg]"; + } + } else { + $sapp = $lapp = ""; + } + if (isset($v['shortopt'])) { + $s = $v['shortopt']; + $help .= " -$s$sapp, --$k$lapp\n"; + } else { + $help .= " --$k$lapp\n"; + } + $p = " "; + $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); + $help .= " $doc\n"; + } + return $help; + } + return null; + } + + // }}} + // {{{ run() + + function run($command, $options, $params) + { + if (empty($this->commands[$command]['function'])) { + // look for shortcuts + foreach (array_keys($this->commands) as $cmd) { + if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { + if (empty($this->commands[$cmd]['function'])) { + return $this->raiseError("unknown command `$command'"); + } else { + $func = $this->commands[$cmd]['function']; + } + $command = $cmd; + break; + } + } + } else { + $func = $this->commands[$command]['function']; + } + return $this->$func($command, $options, $params); + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Command/Config.php b/vas/rest/class/PEAR/Command/Config.php new file mode 100755 index 0000000000000000000000000000000000000000..d8179d3aa235aa65ce3f838e692bf2c0711ef001 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Config.php @@ -0,0 +1,422 @@ +<?php +/** + * PEAR_Command_Config (config-show, config-get, config-set, config-help, config-create commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Config.php,v 1.56 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for managing configuration data. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Config extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'config-show' => array( + 'summary' => 'Show All Settings', + 'function' => 'doConfigShow', + 'shortcut' => 'csh', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => '[layer] +Displays all configuration values. An optional argument +may be used to tell which configuration layer to display. Valid +configuration layers are "user", "system" and "default". To display +configurations for different channels, set the default_channel +configuration variable and run config-show again. +', + ), + 'config-get' => array( + 'summary' => 'Show One Setting', + 'function' => 'doConfigGet', + 'shortcut' => 'cg', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => '<parameter> [layer] +Displays the value of one configuration parameter. The +first argument is the name of the parameter, an optional second argument +may be used to tell which configuration layer to look in. Valid configuration +layers are "user", "system" and "default". If no layer is specified, a value +will be picked from the first layer that defines the parameter, in the order +just specified. The configuration value will be retrieved for the channel +specified by the default_channel configuration variable. +', + ), + 'config-set' => array( + 'summary' => 'Change Setting', + 'function' => 'doConfigSet', + 'shortcut' => 'cs', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => '<parameter> <value> [layer] +Sets the value of one configuration parameter. The first argument is +the name of the parameter, the second argument is the new value. Some +parameters are subject to validation, and the command will fail with +an error message if the new value does not make sense. An optional +third argument may be used to specify in which layer to set the +configuration parameter. The default layer is "user". The +configuration value will be set for the current channel, which +is controlled by the default_channel configuration variable. +', + ), + 'config-help' => array( + 'summary' => 'Show Information About Setting', + 'function' => 'doConfigHelp', + 'shortcut' => 'ch', + 'options' => array(), + 'doc' => '[parameter] +Displays help for a configuration parameter. Without arguments it +displays help for all configuration parameters. +', + ), + 'config-create' => array( + 'summary' => 'Create a Default configuration file', + 'function' => 'doConfigCreate', + 'shortcut' => 'coc', + 'options' => array( + 'windows' => array( + 'shortopt' => 'w', + 'doc' => 'create a config file for a windows install', + ), + ), + 'doc' => '<root path> <filename> +Create a default configuration file with all directory configuration +variables set to subdirectories of <root path>, and save it as <filename>. +This is useful especially for creating a configuration file for a remote +PEAR installation (using the --remoteconfig option of install, upgrade, +and uninstall). +', + ), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Config constructor. + * + * @access public + */ + function PEAR_Command_Config(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doConfigShow() + + function doConfigShow($command, $options, $params) + { + if (is_array($params)) { + $layer = isset($params[0]) ? $params[0] : NULL; + } else { + $layer = NULL; + } + + // $params[0] -> the layer + if ($error = $this->_checkLayer($layer)) { + return $this->raiseError("config-show:$error"); + } + $keys = $this->config->getKeys(); + sort($keys); + $channel = isset($options['channel']) ? $options['channel'] : + $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + $data = array('caption' => 'Configuration (channel ' . $channel . '):'); + foreach ($keys as $key) { + $type = $this->config->getType($key); + $value = $this->config->get($key, $layer, $channel); + if ($type == 'password' && $value) { + $value = '********'; + } + if ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value); + } + foreach ($this->config->getLayers() as $layer) { + $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer)); + } + + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doConfigGet() + + function doConfigGet($command, $options, $params) + { + if (!is_array($params)) { + $args_cnt = 0; + } else { + $args_cnt = count($params); + } + + switch ($args_cnt) { + case 1: + $config_key = $params[0]; + $layer = NULL; + break; + case 2: + $config_key = $params[0]; + $layer = $params[1]; + if ($error = $this->_checkLayer($layer)) { + return $this->raiseError("config-get:$error"); + } + break; + case 0: + default: + return $this->raiseError("config-get expects 1 or 2 parameters"); + } + + $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command); + + return true; + } + + // }}} + // {{{ doConfigSet() + + function doConfigSet($command, $options, $params) + { + // $param[0] -> a parameter to set + // $param[1] -> the value for the parameter + // $param[2] -> the layer + $failmsg = ''; + if (sizeof($params) < 2 || sizeof($params) > 3) { + $failmsg .= "config-set expects 2 or 3 parameters"; + return PEAR::raiseError($failmsg); + } + if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) { + $failmsg .= $error; + return PEAR::raiseError("config-set:$failmsg"); + } + $channel = isset($options['channel']) ? $options['channel'] : + $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + if ($params[0] == 'default_channel') { + if (!$reg->channelExists($params[1])) { + return $this->raiseError('Channel "' . $params[1] . '" does not exist'); + } + } + if (count($params) == 2) { + array_push($params, 'user'); + $layer = 'user'; + } else { + $layer = $params[2]; + } + array_push($params, $channel); + if (!call_user_func_array(array(&$this->config, 'set'), $params)) + { + array_pop($params); + $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel"; + } else { + $this->config->store($layer); + } + if ($failmsg) { + return $this->raiseError($failmsg); + } + $this->ui->outputData('config-set succeeded', $command); + return true; + } + + // }}} + // {{{ doConfigHelp() + + function doConfigHelp($command, $options, $params) + { + if (empty($params)) { + $params = $this->config->getKeys(); + } + $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : ''); + $data['headline'] = array('Name', 'Type', 'Description'); + $data['border'] = true; + foreach ($params as $name) { + $type = $this->config->getType($name); + $docs = $this->config->getDocs($name); + if ($type == 'set') { + $docs = rtrim($docs) . "\nValid set: " . + implode(' ', $this->config->getSetValues($name)); + } + $data['data'][] = array($name, $type, $docs); + } + $this->ui->outputData($data, $command); + } + + // }}} + // {{{ doConfigCreate() + + function doConfigCreate($command, $options, $params) + { + if (count($params) != 2) { + return PEAR::raiseError('config-create: must have 2 parameters, root path and ' . + 'filename to save as'); + } + $root = $params[0]; + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"), + array('/', '/', '/'), + $root); + if ($root{0} != '/') { + if (isset($options['windows'])) { + if (!preg_match('/^[A-Za-z]:/', $root)) { + return PEAR::raiseError('Root directory must be an absolute path beginning ' . + 'with "\\" or "C:\\", was: "' . $root . '"'); + } + } else { + return PEAR::raiseError('Root directory must be an absolute path beginning ' . + 'with "/", was: "' . $root . '"'); + } + } + $windows = isset($options['windows']); + if ($windows) { + $root = str_replace('/', '\\', $root); + } + if (!file_exists($params[1])) { + if (!@touch($params[1])) { + return PEAR::raiseError('Could not create "' . $params[1] . '"'); + } + } + $params[1] = realpath($params[1]); + $config = &new PEAR_Config($params[1], '#no#system#config#', false, false); + if ($root{strlen($root) - 1} == '/') { + $root = substr($root, 0, strlen($root) - 1); + } + $config->noRegistry(); + $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user'); + $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data"); + $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www"); + $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg"); + $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext"); + $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs"); + $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests"); + $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache"); + $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download"); + $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp"); + $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear"); + $config->writeConfigFile(); + $this->_showConfig($config); + $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"', + $command); + } + + // }}} + + function _showConfig(&$config) + { + $params = array('user'); + $keys = $config->getKeys(); + sort($keys); + $channel = 'pear.php.net'; + $data = array('caption' => 'Configuration (channel ' . $channel . '):'); + foreach ($keys as $key) { + $type = $config->getType($key); + $value = $config->get($key, 'user', $channel); + if ($type == 'password' && $value) { + $value = '********'; + } + if ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + $data['data'][$config->getGroup($key)][] = + array($config->getPrompt($key) , $key, $value); + } + foreach ($config->getLayers() as $layer) { + $data['data']['Config Files'][] = + array(ucfirst($layer) . ' Configuration File', 'Filename' , + $config->getConfFile($layer)); + } + + $this->ui->outputData($data, 'config-show'); + return true; + } + // {{{ _checkLayer() + + /** + * Checks if a layer is defined or not + * + * @param string $layer The layer to search for + * @return mixed False on no error or the error message + */ + function _checkLayer($layer = null) + { + if (!empty($layer) && $layer != 'default') { + $layers = $this->config->getLayers(); + if (!in_array($layer, $layers)) { + return " only the layers: \"" . implode('" or "', $layers) . "\" are supported"; + } + } + return false; + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Command/Config.xml b/vas/rest/class/PEAR/Command/Config.xml new file mode 100755 index 0000000000000000000000000000000000000000..f64a925f52c38a43c428f471b7b8ac8e6249ea82 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Config.xml @@ -0,0 +1,92 @@ +<commands version="1.0"> + <config-show> + <summary>Show All Settings</summary> + <function>doConfigShow</function> + <shortcut>csh</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>show configuration variables for another channel</doc> + <arg>CHAN</arg> + </channel> + </options> + <doc>[layer] +Displays all configuration values. An optional argument +may be used to tell which configuration layer to display. Valid +configuration layers are "user", "system" and "default". To display +configurations for different channels, set the default_channel +configuration variable and run config-show again. +</doc> + </config-show> + <config-get> + <summary>Show One Setting</summary> + <function>doConfigGet</function> + <shortcut>cg</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>show configuration variables for another channel</doc> + <arg>CHAN</arg> + </channel> + </options> + <doc><parameter> [layer] +Displays the value of one configuration parameter. The +first argument is the name of the parameter, an optional second argument +may be used to tell which configuration layer to look in. Valid configuration +layers are "user", "system" and "default". If no layer is specified, a value +will be picked from the first layer that defines the parameter, in the order +just specified. The configuration value will be retrieved for the channel +specified by the default_channel configuration variable. +</doc> + </config-get> + <config-set> + <summary>Change Setting</summary> + <function>doConfigSet</function> + <shortcut>cs</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>show configuration variables for another channel</doc> + <arg>CHAN</arg> + </channel> + </options> + <doc><parameter> <value> [layer] +Sets the value of one configuration parameter. The first argument is +the name of the parameter, the second argument is the new value. Some +parameters are subject to validation, and the command will fail with +an error message if the new value does not make sense. An optional +third argument may be used to specify in which layer to set the +configuration parameter. The default layer is "user". The +configuration value will be set for the current channel, which +is controlled by the default_channel configuration variable. +</doc> + </config-set> + <config-help> + <summary>Show Information About Setting</summary> + <function>doConfigHelp</function> + <shortcut>ch</shortcut> + <options /> + <doc>[parameter] +Displays help for a configuration parameter. Without arguments it +displays help for all configuration parameters. +</doc> + </config-help> + <config-create> + <summary>Create a Default configuration file</summary> + <function>doConfigCreate</function> + <shortcut>coc</shortcut> + <options> + <windows> + <shortopt>w</shortopt> + <doc>create a config file for a windows install</doc> + </windows> + </options> + <doc><root path> <filename> +Create a default configuration file with all directory configuration +variables set to subdirectories of <root path>, and save it as <filename>. +This is useful especially for creating a configuration file for a remote +PEAR installation (using the --remoteconfig option of install, upgrade, +and uninstall). +</doc> + </config-create> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Install.php b/vas/rest/class/PEAR/Command/Install.php new file mode 100755 index 0000000000000000000000000000000000000000..fba43820f5261a82a09381122bba9cfb50dd10b3 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Install.php @@ -0,0 +1,1188 @@ +<?php +/** + * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Install.php,v 1.141 2008/05/13 18:32:29 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for installation or deinstallation/upgrading of + * packages. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Install extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'install' => array( + 'summary' => 'Install Package', + 'function' => 'doInstall', + 'shortcut' => 'i', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, install anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as installed', + ), + 'soft' => array( + 'shortopt' => 's', + 'doc' => 'soft install, fail silently, or upgrade if already installed', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'packagingroot' => array( + 'shortopt' => 'P', + 'arg' => 'DIR', + 'doc' => 'root directory used when packaging files, like RPM packaging', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => '[channel/]<package> ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package[-version/state][.tar]" : queries your default channel\'s server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) + +To download a package from another channel, prefix with the channel name like +"channel/Package" + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. +'), + 'upgrade' => array( + 'summary' => 'Upgrade Package', + 'function' => 'doInstall', + 'shortcut' => 'up', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => '<package> ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. +'), + 'upgrade-all' => array( + 'summary' => 'Upgrade All Packages', + 'function' => 'doUpgradeAll', + 'shortcut' => 'ua', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'loose' => array( + 'doc' => 'do not check for recommended dependency version', + ), + ), + 'doc' => ' +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. +'), + 'uninstall' => array( + 'summary' => 'Un-install Package', + 'function' => 'doUninstall', + 'shortcut' => 'un', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, uninstall anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not remove files, only register the packages as not installed', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to uninstall remotely', + ), + ), + 'doc' => '[channel/]<package> ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) +'), + 'bundle' => array( + 'summary' => 'Unpacks a Pecl Package', + 'function' => 'doBundle', + 'shortcut' => 'bun', + 'options' => array( + 'destination' => array( + 'shortopt' => 'd', + 'arg' => 'DIR', + 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'Force the unpacking even if there were errors in the package', + ), + ), + 'doc' => '<package> +Unpacks a Pecl Package into the selected location. It will download the +package if needed. +'), + 'run-scripts' => array( + 'summary' => 'Run Post-Install Scripts bundled with a package', + 'function' => 'doRunScripts', + 'shortcut' => 'rs', + 'options' => array( + ), + 'doc' => '<package> +Run post-installation scripts in package <package>, if any exist. +'), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Install constructor. + * + * @access public + */ + function PEAR_Command_Install(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + /** + * For unit testing purposes + */ + function &getDownloader(&$ui, $options, &$config) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = &new PEAR_Downloader($ui, $options, $config); + return $a; + } + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + function enableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + // already enabled - assume if one is, all are + return true; + } + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + } else { + $newini = array(); + } + foreach ($binaries as $binary) { + if ($ini['extension_dir']) { + $binary = basename($binary); + } + $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); + } + $newini = array_merge($newini, array_slice($ini['all'], $line)); + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function disableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + $found = false; + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + $found = true; + break; + } + } + if (!$found) { + // not enabled + return true; + } + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + // delete the enable line + $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); + } else { + $newini = array_slice($ini['all'], 1); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function _parseIni($filename) + { + if (file_exists($filename)) { + if (filesize($filename) > 300000) { + return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); + } + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $zend_extension_line = 'zend_extension' . $debug . $ts; + $all = @file($filename); + if (!$all) { + return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); + } + $zend_extensions = $extensions = array(); + // assume this is right, but pull from the php.ini if it is found + $extension_dir = ini_get('extension_dir'); + foreach ($all as $linenum => $line) { + $line = trim($line); + if (!$line) { + continue; + } + if ($line[0] == ';') { + continue; + } + if (strtolower(substr($line, 0, 13)) == 'extension_dir') { + $line = trim(substr($line, 13)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extension_dir = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, 9)) == 'extension') { + $line = trim(substr($line, 9)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, strlen($zend_extension_line))) == + $zend_extension_line) { + $line = trim(substr($line, strlen($zend_extension_line))); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + } + return array( + 'extensions' => $extensions, + 'zend_extensions' => $zend_extensions, + 'extension_dir' => $extension_dir, + 'all' => $all, + ); + } else { + return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); + } + } + + // {{{ doInstall() + + function doInstall($command, $options, $params) + { + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + if ($command == 'upgrade' || $command == 'upgrade-all') { + $options['upgrade'] = true; + } else { + $packages = $params; + } + if (isset($options['installroot']) && isset($options['packagingroot'])) { + return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); + } + $reg = &$this->config->getRegistry(); + $instreg = &$reg; // instreg used to check if package is installed + if (isset($options['packagingroot']) && !isset($options['upgrade'])) { + $packrootphp_dir = $this->installer->_prependPath( + $this->config->get('php_dir', null, 'pear.php.net'), + $options['packagingroot']); + $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! + + if ($this->config->get('verbose') > 2) { + $this->ui->outputData('using package root: ' . $options['packagingroot']); + } + } + $abstractpackages = array(); + $otherpackages = array(); + // parse params + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + foreach($params as $param) { + if (strpos($param, 'http://') === 0) { + $otherpackages[] = $param; + continue; + } + if (strpos($param, 'channel://') === false && @file_exists($param)) { + if (isset($options['force'])) { + $otherpackages[] = $param; + continue; + } + $pkg = new PEAR_PackageFile($this->config); + $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); + if (PEAR::isError($pf)) { + $otherpackages[] = $param; + continue; + } + if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) && + version_compare($pf->getVersion(), + $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()), + '<=')) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString( + array('package' => $pf->getPackage(), + 'channel' => $pf->getChannel()), true)); + } + continue; + } + $otherpackages[] = $param; + continue; + } + $e = $reg->parsePackageName($param, $this->config->get('default_channel')); + if (PEAR::isError($e)) { + $otherpackages[] = $param; + } else { + $abstractpackages[] = $e; + } + } + PEAR::staticPopErrorHandling(); + + // if there are any local package .tgz or remote static url, we can't + // filter. The filter only works for abstract packages + if (count($abstractpackages) && !isset($options['force'])) { + // when not being forced, only do necessary upgrades/installs + if (isset($options['upgrade'])) { + $abstractpackages = $this->_filterUptodatePackages($abstractpackages, + $command); + } else { + foreach ($abstractpackages as $i => $package) { + if (isset($package['group'])) { + // do not filter out install groups + continue; + } + if ($instreg->packageExists($package['package'], $package['channel'])) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString($package, true)); + } + unset($abstractpackages[$i]); + } + } + } + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } elseif (count($abstractpackages)) { + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } + + + $packages = array_merge($abstractpackages, $otherpackages); + if (!count($packages)) { + $this->ui->outputData('Nothing to ' . $command); + return true; + } + + $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); + $errors = array(); + $binaries = array(); + $downloaded = array(); + $downloaded = &$this->downloader->download($packages); + if (PEAR::isError($downloaded)) { + return $this->raiseError($downloaded); + } + $errors = $this->downloader->getErrorMsgs(); + if (count($errors)) { + $err = array(); + $err['data'] = array(); + foreach ($errors as $error) { + $err['data'][] = array($error); + } + $err['headline'] = 'Install Errors'; + $this->ui->outputData($err); + if (!count($downloaded)) { + return $this->raiseError("$command failed"); + } + } + $data = array( + 'headline' => 'Packages that would be Installed' + ); + if (isset($options['pretend'])) { + foreach ($downloaded as $package) { + $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); + } + $this->ui->outputData($data, 'pretend'); + return true; + } + $this->installer->setOptions($options); + $this->installer->sortPackagesForInstall($downloaded); + if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { + $this->raiseError($err->getMessage()); + return true; + } + $extrainfo = array(); + $binaries = array(); + foreach ($downloaded as $param) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->install($param, $options); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $oldinfo = $info; + $pkg = &$param->getPackageFile(); + if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { + if (!($info = $pkg->installBinary($this->installer))) { + $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); + continue; + } + // we just installed a different package than requested, + // let's change the param and info so that the rest of this works + $param = $info[0]; + $info = $info[1]; + } + } + if (is_array($info)) { + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin' || + $param->getPackageType() == 'zendextsrc' || + $param->getPackageType() == 'zendextbin') { + $pkg = &$param->getPackageFile(); + if ($instbin = $pkg->getInstalledBinary()) { + $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); + } else { + $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); + } + + foreach ($instpkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h'))) { + continue; // make sure we don't match php_blah.h + } + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $extrainfo[] = 'You should add "' . $exttype . '=' . + $pinfo[1]['basename'] . '" to php.ini'; + } else { + $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . + ' enabled in php.ini'; + } + } + } + } + if ($this->config->get('verbose') > 0) { + $channel = $param->getChannel(); + $label = $reg->parsedPackageNameToString( + array( + 'channel' => $channel, + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + )); + $out = array('data' => "$command ok: $label"); + if (isset($info['release_warnings'])) { + $out['release_warnings'] = $info['release_warnings']; + } + $this->ui->outputData($out, $command); + if (!isset($options['register-only']) && !isset($options['offline'])) { + if ($this->config->isDefinedLayer('ftp')) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpInstall($param); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote install failed: $label"); + } else { + $this->ui->outputData("remote install ok: $label"); + } + } + } + } + $deps = $param->getDeps(); + if ($deps) { + if (isset($deps['group'])) { + $groups = $deps['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + foreach ($groups as $group) { + if ($group['attribs']['name'] == 'default') { + // default group is always installed, unless the user + // explicitly chooses to install another group + continue; + } + $extrainfo[] = $param->getPackage() . ': Optional feature ' . + $group['attribs']['name'] . ' available (' . + $group['attribs']['hint'] . ')'; + } + $extrainfo[] = $param->getPackage() . + ': To install optional features use "pear install ' . + $reg->parsedPackageNameToString( + array('package' => $param->getPackage(), + 'channel' => $param->getChannel()), true) . + '#featurename"'; + } + } + $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); + // $pkg may be NULL if install is a 'fake' install via --packagingroot + if (is_object($pkg)) { + $pkg->setConfig($this->config); + if ($list = $pkg->listPostinstallScripts()) { + $pn = $reg->parsedPackageNameToString(array('channel' => + $param->getChannel(), 'package' => $param->getPackage()), true); + $extrainfo[] = $pn . ' has post-install scripts:'; + foreach ($list as $file) { + $extrainfo[] = $file; + } + $extrainfo[] = $param->getPackage() . + ': Use "pear run-scripts ' . $pn . '" to finish setup.'; + $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; + } + } + } else { + return $this->raiseError("$command failed"); + } + } + if (count($extrainfo)) { + foreach ($extrainfo as $info) { + $this->ui->outputData($info); + } + } + return true; + } + + // }}} + // {{{ doUpgradeAll() + + function doUpgradeAll($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $toUpgrade = array(); + foreach ($reg->listChannels() as $channel) { + if ($channel == '__uri') { + continue; + } + + // parse name with channel + foreach ($reg->listPackages($channel) as $name) { + $toUpgrade[] = $reg->parsedPackageNameToString(array( + 'channel' => $channel, + 'package' => $name + )); + } + } + + $err = $this->doInstall('upgrade-all', $options, $toUpgrade); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + } + } + + // }}} + // {{{ doUninstall() + + function doUninstall($command, $options, $params) + { + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + if (isset($options['remoteconfig'])) { + $e = $this->config->readFTPConfigFile($options['remoteconfig']); + if (!PEAR::isError($e)) { + $this->installer->setConfig($this->config); + } + } + if (sizeof($params) < 1) { + return $this->raiseError("Please supply the package(s) you want to uninstall"); + } + $reg = &$this->config->getRegistry(); + $newparams = array(); + $binaries = array(); + $badparams = array(); + foreach ($params as $pkg) { + $channel = $this->config->get('default_channel'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($pkg, $channel); + PEAR::staticPopErrorHandling(); + if (!$parsed || PEAR::isError($parsed)) { + $badparams[] = $pkg; + continue; + } + $package = $parsed['package']; + $channel = $parsed['channel']; + $info = &$reg->getPackage($package, $channel); + if ($info === null && + ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { + // make sure this isn't a package that has flipped from pear to pecl but + // used a package.xml 1.0 + $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; + $info = &$reg->getPackage($package, $testc); + if ($info !== null) { + $channel = $testc; + } + } + if ($info === null) { + $badparams[] = $pkg; + } else { + $newparams[] = &$info; + // check for binary packages (this is an alias for those packages if so) + if ($installedbinary = $info->getInstalledBinary()) { + $this->ui->log('adding binary package ' . + $reg->parsedPackageNameToString(array('channel' => $channel, + 'package' => $installedbinary), true)); + $newparams[] = &$reg->getPackage($installedbinary, $channel); + } + // add the contents of a dependency group to the list of installed packages + if (isset($parsed['group'])) { + $group = $info->getDependencyGroup($parsed['group']); + if ($group) { + $installed = $reg->getInstalledGroup($group); + if ($installed) { + foreach ($installed as $i => $p) { + $newparams[] = &$installed[$i]; + } + } + } + } + } + } + $err = $this->installer->sortPackagesForUninstall($newparams); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + return true; + } + $params = $newparams; + // twist this to use it to check on whether dependent packages are also being uninstalled + // for circular dependencies like subpackages + $this->installer->setUninstallPackages($newparams); + $params = array_merge($params, $badparams); + $binaries = array(); + foreach ($params as $pkg) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + if ($err = $this->installer->uninstall($pkg, $options)) { + $this->installer->popErrorHandling(); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + continue; + } + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin' || + $pkg->getPackageType() == 'zendextsrc' || + $pkg->getPackageType() == 'zendextbin') { + if ($instbin = $pkg->getInstalledBinary()) { + continue; // this will be uninstalled later + } + + foreach ($pkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h'))) { + continue; // make sure we don't match php_blah.h + } + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $this->ui->outputData('Unable to remove "' . $exttype . '=' . + $pinfo[1]['basename'] . '" from php.ini', $command); + } else { + $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . + ' disabled in php.ini', $command); + } + } + } + } + $savepkg = $pkg; + if ($this->config->get('verbose') > 0) { + if (is_object($pkg)) { + $pkg = $reg->parsedPackageNameToString($pkg); + } + $this->ui->outputData("uninstall ok: $pkg", $command); + } + if (!isset($options['offline']) && is_object($savepkg) && + defined('PEAR_REMOTEINSTALL_OK')) { + if ($this->config->isDefinedLayer('ftp')) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpUninstall($savepkg); + $this->installer->popErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote uninstall failed: $pkg"); + } else { + $this->ui->outputData("remote uninstall ok: $pkg"); + } + } + } + } else { + $this->installer->popErrorHandling(); + if (is_object($pkg)) { + $pkg = $reg->parsedPackageNameToString($pkg); + } + return $this->raiseError("uninstall failed: $pkg"); + } + } + return true; + } + + // }}} + + + // }}} + // {{{ doBundle() + /* + (cox) It just downloads and untars the package, does not do + any check that the PEAR_Installer::_installFile() does. + */ + + function doBundle($command, $options, $params) + { + $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true, + 'soft' => true, 'downloadonly' => true), $this->config); + $reg = &$this->config->getRegistry(); + if (sizeof($params) < 1) { + return $this->raiseError("Please supply the package you want to bundle"); + } + + if (isset($options['destination'])) { + if (!is_dir($options['destination'])) { + System::mkdir('-p ' . $options['destination']); + } + $dest = realpath($options['destination']); + } else { + $pwd = getcwd(); + if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) { + $dest = $pwd . DIRECTORY_SEPARATOR . 'ext'; + } else { + $dest = $pwd; + } + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $downloader->setDownloadDir($dest); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('download directory "' . $dest . + '" is not writeable.'); + } + $result = &$downloader->download(array($params[0])); + if (PEAR::isError($result)) { + return $result; + } + if (!isset($result[0])) { + return $this->raiseError('unable to unpack ' . $params[0]); + } + $pkgfile = &$result[0]->getPackageFile(); + $pkgname = $pkgfile->getName(); + $pkgversion = $pkgfile->getVersion(); + + // Unpacking ------------------------------------------------- + $dest .= DIRECTORY_SEPARATOR . $pkgname; + $orig = $pkgname . '-' . $pkgversion; + + $tar = &new Archive_Tar($pkgfile->getArchiveFile()); + if (!$tar->extractModify($dest, $orig)) { + return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); + } + $this->ui->outputData("Package ready at '$dest'"); + // }}} + } + + // }}} + + function doRunScripts($command, $options, $params) + { + if (!isset($params[0])) { + return $this->raiseError('run-scripts expects 1 parameter: a package name'); + } + $reg = &$this->config->getRegistry(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + $package = &$reg->getPackage($parsed['package'], $parsed['channel']); + if (is_object($package)) { + $package->setConfig($this->config); + $package->runPostinstallScripts(); + } else { + return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); + } + $this->ui->outputData('Install scripts complete', $command); + return true; + } + + /** + * Given a list of packages, filter out those ones that are already up to date + * + * @param $packages: packages, in parsed array format ! + * @return list of packages that can be upgraded + */ + function _filterUptodatePackages($packages, $command) + { + $reg = &$this->config->getRegistry(); + $latestReleases = array(); + + $ret = array(); + foreach($packages as $package) { + if (isset($package['group'])) { + $ret[] = $package; + continue; + } + $channel = $package['channel']; + $name = $package['package']; + + if (!$reg->packageExists($name, $channel)) { + $ret[] = $package; + continue; + } + if (!isset($latestReleases[$channel])) { + // fill in cache for this channel + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + if ($chan->supportsREST($this->config->get('preferred_mirror', + null, $channel)) && + $base = $chan->getBaseURL('REST1.0', + $this->config->get('preferred_mirror', + null, $channel))) + { + $dorest = true; + } else { + $dorest = false; + $remote = &$this->config->getRemote($this->config); + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if ($dorest) { + $rest = &$this->config->getREST('1.0', array()); + $installed = array_flip($reg->listPackages($channel)); + $latest = $rest->listLatestUpgrades($base, + $this->config->get('preferred_state', null, $channel), $installed, + $channel, $reg); + } else { + $latest = $remote->call("package.listLatestReleases", + $this->config->get('preferred_state', null, $channel)); + unset($remote); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($latest)) { + $this->ui->outputData('Error getting channel info from ' . $channel . + ': ' . $latest->getMessage()); + continue; + } + + $latestReleases[$channel] = array_change_key_case($latest); + } + + // check package for latest release + if (isset($latestReleases[$channel][strtolower($name)])) { + // if not set, up to date + $inst_version = $reg->packageInfo($name, 'version', $channel); + $channel_version = $latestReleases[$channel][strtolower($name)]['version']; + if (version_compare($channel_version, $inst_version, "le")) { + // installed version is up-to-date + continue; + } + // maintain BC + if ($command == 'upgrade-all') { + $this->ui->outputData(array('data' => 'Will upgrade ' . + $reg->parsedPackageNameToString($package)), $command); + } + $ret[] = $package; + } + } + + return $ret; + } + +} +?> diff --git a/vas/rest/class/PEAR/Command/Install.xml b/vas/rest/class/PEAR/Command/Install.xml new file mode 100755 index 0000000000000000000000000000000000000000..94044c26f0b3169a26f14095aa8a8e99801adb6f --- /dev/null +++ b/vas/rest/class/PEAR/Command/Install.xml @@ -0,0 +1,259 @@ +<commands version="1.0"> + <install> + <summary>Install Package</summary> + <function>doInstall</function> + <shortcut>i</shortcut> + <options> + <force> + <shortopt>f</shortopt> + <doc>will overwrite newer installed packages</doc> + </force> + <loose> + <shortopt>l</shortopt> + <doc>do not check for recommended dependency version</doc> + </loose> + <nodeps> + <shortopt>n</shortopt> + <doc>ignore dependencies, install anyway</doc> + </nodeps> + <register-only> + <shortopt>r</shortopt> + <doc>do not install files, only register the package as installed</doc> + </register-only> + <soft> + <shortopt>s</shortopt> + <doc>soft install, fail silently, or upgrade if already installed</doc> + </soft> + <nobuild> + <shortopt>B</shortopt> + <doc>don't build C extensions</doc> + </nobuild> + <nocompress> + <shortopt>Z</shortopt> + <doc>request uncompressed files when downloading</doc> + </nocompress> + <installroot> + <shortopt>R</shortopt> + <arg>DIR</arg> + <doc>root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM</doc> + </installroot> + <packagingroot> + <shortopt>P</shortopt> + <arg>DIR</arg> + <doc>root directory used when packaging files, like RPM packaging</doc> + </packagingroot> + <ignore-errors> + <doc>force install even if there were errors</doc> + </ignore-errors> + <alldeps> + <shortopt>a</shortopt> + <doc>install all required and optional dependencies</doc> + </alldeps> + <onlyreqdeps> + <shortopt>o</shortopt> + <doc>install all required dependencies</doc> + </onlyreqdeps> + <offline> + <shortopt>O</shortopt> + <doc>do not attempt to download any urls or contact channels</doc> + </offline> + <pretend> + <shortopt>p</shortopt> + <doc>Only list the packages that would be downloaded</doc> + </pretend> + </options> + <doc>[channel/]<package> ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package[-version/state][.tar]" : queries your default channel's server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) + +To download a package from another channel, prefix with the channel name like +"channel/Package" + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. +</doc> + </install> + <upgrade> + <summary>Upgrade Package</summary> + <function>doInstall</function> + <shortcut>up</shortcut> + <options> + <force> + <shortopt>f</shortopt> + <doc>overwrite newer installed packages</doc> + </force> + <loose> + <shortopt>l</shortopt> + <doc>do not check for recommended dependency version</doc> + </loose> + <nodeps> + <shortopt>n</shortopt> + <doc>ignore dependencies, upgrade anyway</doc> + </nodeps> + <register-only> + <shortopt>r</shortopt> + <doc>do not install files, only register the package as upgraded</doc> + </register-only> + <nobuild> + <shortopt>B</shortopt> + <doc>don't build C extensions</doc> + </nobuild> + <nocompress> + <shortopt>Z</shortopt> + <doc>request uncompressed files when downloading</doc> + </nocompress> + <installroot> + <shortopt>R</shortopt> + <arg>DIR</arg> + <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc> + </installroot> + <ignore-errors> + <doc>force install even if there were errors</doc> + </ignore-errors> + <alldeps> + <shortopt>a</shortopt> + <doc>install all required and optional dependencies</doc> + </alldeps> + <onlyreqdeps> + <shortopt>o</shortopt> + <doc>install all required dependencies</doc> + </onlyreqdeps> + <offline> + <shortopt>O</shortopt> + <doc>do not attempt to download any urls or contact channels</doc> + </offline> + <pretend> + <shortopt>p</shortopt> + <doc>Only list the packages that would be downloaded</doc> + </pretend> + </options> + <doc><package> ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. +</doc> + </upgrade> + <upgrade-all> + <summary>Upgrade All Packages</summary> + <function>doInstall</function> + <shortcut>ua</shortcut> + <options> + <nodeps> + <shortopt>n</shortopt> + <doc>ignore dependencies, upgrade anyway</doc> + </nodeps> + <register-only> + <shortopt>r</shortopt> + <doc>do not install files, only register the package as upgraded</doc> + </register-only> + <nobuild> + <shortopt>B</shortopt> + <doc>don't build C extensions</doc> + </nobuild> + <nocompress> + <shortopt>Z</shortopt> + <doc>request uncompressed files when downloading</doc> + </nocompress> + <installroot> + <shortopt>R</shortopt> + <arg>DIR</arg> + <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc> + </installroot> + <ignore-errors> + <doc>force install even if there were errors</doc> + </ignore-errors> + <loose> + <doc>do not check for recommended dependency version</doc> + </loose> + </options> + <doc> +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. +</doc> + </upgrade-all> + <uninstall> + <summary>Un-install Package</summary> + <function>doUninstall</function> + <shortcut>un</shortcut> + <options> + <nodeps> + <shortopt>n</shortopt> + <doc>ignore dependencies, uninstall anyway</doc> + </nodeps> + <register-only> + <shortopt>r</shortopt> + <doc>do not remove files, only register the packages as not installed</doc> + </register-only> + <installroot> + <shortopt>R</shortopt> + <arg>DIR</arg> + <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc> + </installroot> + <ignore-errors> + <doc>force install even if there were errors</doc> + </ignore-errors> + <offline> + <shortopt>O</shortopt> + <doc>do not attempt to uninstall remotely</doc> + </offline> + </options> + <doc>[channel/]<package> ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) +</doc> + </uninstall> + <bundle> + <summary>Unpacks a Pecl Package</summary> + <function>doBundle</function> + <shortcut>bun</shortcut> + <options> + <destination> + <shortopt>d</shortopt> + <arg>DIR</arg> + <doc>Optional destination directory for unpacking (defaults to current path or "ext" if exists)</doc> + </destination> + <force> + <shortopt>f</shortopt> + <doc>Force the unpacking even if there were errors in the package</doc> + </force> + </options> + <doc><package> +Unpacks a Pecl Package into the selected location. It will download the +package if needed. +</doc> + </bundle> + <run-scripts> + <summary>Run Post-Install Scripts bundled with a package</summary> + <function>doRunScripts</function> + <shortcut>rs</shortcut> + <options /> + <doc><package> +Run post-installation scripts in package <package>, if any exist. +</doc> + </run-scripts> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Mirror.php b/vas/rest/class/PEAR/Command/Mirror.php new file mode 100755 index 0000000000000000000000000000000000000000..f1256e0a5a30c38f49ca5cc1d7697c7b98255993 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Mirror.php @@ -0,0 +1,153 @@ +<?php +/** + * PEAR_Command_Mirror (download-all command) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Alexander Merz <alexmerz@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Mirror.php,v 1.20 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.2.0 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for providing file mirrors + * + * @category pear + * @package PEAR + * @author Alexander Merz <alexmerz@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.2.0 + */ +class PEAR_Command_Mirror extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'download-all' => array( + 'summary' => 'Downloads each available package from the default channel', + 'function' => 'doDownloadAll', + 'shortcut' => 'da', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + ), + 'doc' => ' +Requests a list of available packages from the default channel ({config default_channel}) +and downloads them to current working directory. Note: only +packages within preferred_state ({config preferred_state}) will be downloaded' + ), + ); + + // }}} + + // {{{ constructor + + /** + * PEAR_Command_Mirror constructor. + * + * @access public + * @param object PEAR_Frontend a reference to an frontend + * @param object PEAR_Config a reference to the configuration data + */ + function PEAR_Command_Mirror(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + /** + * For unit-testing + */ + function &factory($a) + { + $a = &PEAR_Command::factory($a, $this->config); + return $a; + } + + // {{{ doDownloadAll() + /** + * retrieves a list of avaible Packages from master server + * and downloads them + * + * @access public + * @param string $command the command + * @param array $options the command options before the command + * @param array $params the stuff after the command name + * @return bool true if succesful + * @throw PEAR_Error + */ + function doDownloadAll($command, $options, $params) + { + $savechannel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + $channel = isset($options['channel']) ? $options['channel'] : + $this->config->get('default_channel'); + if (!$reg->channelExists($channel)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + $this->config->set('default_channel', $channel); + $this->ui->outputData('Using Channel ' . $this->config->get('default_channel')); + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $remoteInfo = array_flip($rest->listPackages($base, $channel)); + } else { + $remote = &$this->config->getRemote(); + $stable = ($this->config->get('preferred_state') == 'stable'); + $remoteInfo = $remote->call("package.listAll", true, $stable, false); + } + if (PEAR::isError($remoteInfo)) { + return $remoteInfo; + } + $cmd = &$this->factory("download"); + if (PEAR::isError($cmd)) { + return $cmd; + } + $this->ui->outputData('Using Preferred State of ' . + $this->config->get('preferred_state')); + $this->ui->outputData('Gathering release information, please wait...'); + /** + * Error handling not necessary, because already done by + * the download command + */ + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo)); + PEAR::staticPopErrorHandling(); + $this->config->set('default_channel', $savechannel); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage()); + } + return true; + } + + // }}} +} diff --git a/vas/rest/class/PEAR/Command/Mirror.xml b/vas/rest/class/PEAR/Command/Mirror.xml new file mode 100755 index 0000000000000000000000000000000000000000..fe8be9d03bf94a11aae5fb1fbbe338932bd2c9c8 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Mirror.xml @@ -0,0 +1,18 @@ +<commands version="1.0"> + <download-all> + <summary>Downloads each available package from the default channel</summary> + <function>doDownloadAll</function> + <shortcut>da</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>specify a channel other than the default channel</doc> + <arg>CHAN</arg> + </channel> + </options> + <doc> +Requests a list of available packages from the default channel ({config default_channel}) +and downloads them to current working directory. Note: only +packages within preferred_state ({config preferred_state}) will be downloaded</doc> + </download-all> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Package.php b/vas/rest/class/PEAR/Command/Package.php new file mode 100755 index 0000000000000000000000000000000000000000..8eb16df75f2e9df13471a24563f32016acffc8b0 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Package.php @@ -0,0 +1,843 @@ +<?php +/** + * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies, + * sign, makerpm, convert commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Package.php,v 1.128 2008/03/29 21:06:58 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ + +class PEAR_Command_Package extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'package' => array( + 'summary' => 'Build Package', + 'function' => 'doPackage', + 'shortcut' => 'p', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' + ), + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', + ), + ), + 'doc' => '[descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" +' + ), + 'package-validate' => array( + 'summary' => 'Validate Package Consistency', + 'function' => 'doPackageValidate', + 'shortcut' => 'pv', + 'options' => array(), + 'doc' => ' +', + ), + 'cvsdiff' => array( + 'summary' => 'Run a "cvs diff" for all files in a package', + 'function' => 'doCvsDiff', + 'shortcut' => 'cd', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'date' => array( + 'shortopt' => 'D', + 'doc' => 'Diff against revision of DATE', + 'arg' => 'DATE', + ), + 'release' => array( + 'shortopt' => 'R', + 'doc' => 'Diff against tag for package release REL', + 'arg' => 'REL', + ), + 'revision' => array( + 'shortopt' => 'r', + 'doc' => 'Diff against revision REV', + 'arg' => 'REV', + ), + 'context' => array( + 'shortopt' => 'c', + 'doc' => 'Generate context diff', + ), + 'unified' => array( + 'shortopt' => 'u', + 'doc' => 'Generate unified diff', + ), + 'ignore-case' => array( + 'shortopt' => 'i', + 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', + ), + 'ignore-whitespace' => array( + 'shortopt' => 'b', + 'doc' => 'Ignore changes in amount of white space', + ), + 'ignore-blank-lines' => array( + 'shortopt' => 'B', + 'doc' => 'Ignore changes that insert or delete blank lines', + ), + 'brief' => array( + 'doc' => 'Report only whether the files differ, no details', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => '<package.xml> +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. +', + ), + 'cvstag' => array( + 'summary' => 'Set CVS Release Tag', + 'function' => 'doCvsTag', + 'shortcut' => 'ct', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => '<package.xml> [files...] +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. + +to include files (such as a second package.xml, or tests not included in the +release), pass them as additional parameters. +', + ), + 'package-dependencies' => array( + 'summary' => 'Show package dependencies', + 'function' => 'doPackageDependencies', + 'shortcut' => 'pd', + 'options' => array(), + 'doc' => ' +List all dependencies the package has.' + ), + 'sign' => array( + 'summary' => 'Sign a package distribution file', + 'function' => 'doSign', + 'shortcut' => 'si', + 'options' => array( + 'verbose' => array( + 'shortopt' => 'v', + 'doc' => 'Display GnuPG output', + ), + ), + 'doc' => '<package-file> +Signs a package distribution (.tar or .tgz) file with GnuPG.', + ), + 'makerpm' => array( + 'summary' => 'Builds an RPM spec file from a PEAR package', + 'function' => 'doMakeRPM', + 'shortcut' => 'rpm', + 'options' => array( + 'spec-template' => array( + 'shortopt' => 't', + 'arg' => 'FILE', + 'doc' => 'Use FILE as RPM spec file template' + ), + 'rpm-pkgname' => array( + 'shortopt' => 'p', + 'arg' => 'FORMAT', + 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s".', + ), + ), + 'doc' => '<package-file> + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm +', + ), + 'convert' => array( + 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format', + 'function' => 'doConvert', + 'shortcut' => 'c2', + 'options' => array( + 'flat' => array( + 'shortopt' => 'f', + 'doc' => 'do not beautify the filelist.', + ), + ), + 'doc' => '[descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. +' + ), + ); + + var $output; + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Package constructor. + * + * @access public + */ + function PEAR_Command_Package(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ _displayValidationResults() + + function _displayValidationResults($err, $warn, $strict = false) + { + foreach ($err as $e) { + $this->output .= "Error: $e\n"; + } + foreach ($warn as $w) { + $this->output .= "Warning: $w\n"; + } + $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", + sizeof($err), sizeof($warn)); + if ($strict && sizeof($err) > 0) { + $this->output .= "Fix these errors and try again."; + return false; + } + return true; + } + + // }}} + function &getPackager() + { + if (!class_exists('PEAR_Packager')) { + require_once 'PEAR/Packager.php'; + } + $a = &new PEAR_Packager; + return $a; + } + + function &getPackageFile($config, $debug = false, $tmpdir = null) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $a = &new PEAR_PackageFile($config, $debug, $tmpdir); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); + return $a; + } + // {{{ doPackage() + + function doPackage($command, $options, $params) + { + $this->output = ''; + $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; + $pkg2 = isset($params[1]) ? $params[1] : null; + if (!$pkg2 && !isset($params[0])) { + if (file_exists('package2.xml')) { + $pkg2 = 'package2.xml'; + } + } + $packager = &$this->getPackager(); + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress, $pkg2); + if (PEAR::isError($result)) { + return $this->raiseError($result); + } + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->output = $result; + } + if ($this->output) { + $this->ui->outputData($this->output, $command); + } + return true; + } + + // }}} + // {{{ doPackageValidate() + + function doPackageValidate($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $params[0] = "package.xml"; + } + $obj = &$this->getPackageFile($this->config, $this->_debug); + $obj->rawReturn(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL); + } else { + $archive = $info->getArchiveFile(); + $tar = &new Archive_Tar($archive); + $tar->extract(dirname($info->getPackageFile())); + $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR . + $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR . + basename($info->getPackageFile())); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $valid = false; + if ($info->getPackagexmlVersion() == '2.0') { + if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) { + $info->flattenFileList(); + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); + } + } else { + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); + } + $err = $warn = array(); + if ($errors = $info->getValidationWarnings()) { + foreach ($errors as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + $this->_displayValidationResults($err, $warn); + $this->ui->outputData($this->output, $command); + return true; + } + + // }}} + // {{{ doCvsTag() + + function doCvsTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS tag failed'); + } + $version = $info->getVersion(); + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); + $cvstag = "RELEASE_$cvsversion"; + $files = array_keys($info->getFilelist()); + $command = "cvs"; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + if (isset($options['reallyquiet'])) { + $command .= ' -Q'; + } + $command .= ' tag'; + if (isset($options['slide'])) { + $command .= ' -F'; + } + if (isset($options['delete'])) { + $command .= ' -d'; + } + $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); + array_shift($params); + if (count($params)) { + // add in additional files to be tagged + $files = array_merge($files, $params); + } + foreach ($files as $file) { + $command .= ' ' . escapeshellarg($file); + } + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + $this->ui->outputData($this->output, $_cmd); + return true; + } + + // }}} + // {{{ doCvsDiff() + + function doCvsDiff($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS diff failed'); + } + $info1 = $info->getFilelist(); + $files = $info1; + $cmd = "cvs"; + if (isset($options['quiet'])) { + $cmd .= ' -q'; + unset($options['quiet']); + } + if (isset($options['reallyquiet'])) { + $cmd .= ' -Q'; + unset($options['reallyquiet']); + } + if (isset($options['release'])) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); + $cvstag = "RELEASE_$cvsversion"; + $options['revision'] = $cvstag; + unset($options['release']); + } + $execute = true; + if (isset($options['dry-run'])) { + $execute = false; + unset($options['dry-run']); + } + $cmd .= ' diff'; + // the rest of the options are passed right on to "cvs diff" + foreach ($options as $option => $optarg) { + $arg = $short = false; + if (isset($this->commands[$command]['options'][$option])) { + $arg = $this->commands[$command]['options'][$option]['arg']; + $short = $this->commands[$command]['options'][$option]['shortopt']; + } + $cmd .= $short ? " -$short" : " --$option"; + if ($arg && $optarg) { + $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); + } + } + foreach ($files as $file) { + $cmd .= ' ' . escapeshellarg($file['name']); + } + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $cmd\n"; + } + if ($execute) { + $fp = popen($cmd, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + $this->ui->outputData($this->output, $command); + return true; + } + + // }}} + // {{{ doPackageDependencies() + + function doPackageDependencies($command, $options, $params) + { + // $params[0] -> the PEAR package to list its information + if (sizeof($params) != 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $deps = $info->getDeps(); + if (is_array($deps)) { + if ($info->getPackagexmlVersion() == '1.0') { + $data = array( + 'caption' => 'Dependencies for pear/' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", "Relation", "Version"), + ); + + foreach ($deps as $d) { + if (isset($d['optional'])) { + if ($d['optional'] == 'yes') { + $req = 'No'; + } else { + $req = 'Yes'; + } + } else { + $req = 'Yes'; + } + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + + if (isset($d['name'])) { + $name = $d['name']; + } else { + $name = ''; + } + + if (isset($d['version'])) { + $version = $d['version']; + } else { + $version = ''; + } + + $data['data'][] = array($req, $type, $name, $rel, $version); + } + } else { // package.xml 2.0 dependencies display + require_once 'PEAR/Dependency2.php'; + $deps = $info->getDependencies(); + $reg = &$this->config->getRegistry(); + if (is_array($deps)) { + $d = new PEAR_Dependency2($this->config, array(), ''); + $data = array( + 'caption' => 'Dependencies for ' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'), + ); + foreach ($deps as $type => $subd) { + $req = ($type == 'required') ? 'Yes' : 'No'; + if ($type == 'group') { + $group = $subd['attribs']['name']; + } else { + $group = ''; + } + if (!isset($subd[0])) { + $subd = array($subd); + } + foreach ($subd as $groupa) { + foreach ($groupa as $deptype => $depinfo) { + if ($deptype == 'attribs') { + continue; + } + if ($deptype == 'pearinstaller') { + $deptype = 'pear Installer'; + } + if (!isset($depinfo[0])) { + $depinfo = array($depinfo); + } + foreach ($depinfo as $inf) { + $name = ''; + if (isset($inf['channel'])) { + $alias = $reg->channelAlias($inf['channel']); + if (!$alias) { + $alias = '(channel?) ' .$inf['channel']; + } + $name = $alias . '/'; + } + if (isset($inf['name'])) { + $name .= $inf['name']; + } elseif (isset($inf['pattern'])) { + $name .= $inf['pattern']; + } else { + $name .= ''; + } + if (isset($inf['uri'])) { + $name .= ' [' . $inf['uri'] . ']'; + } + if (isset($inf['conflicts'])) { + $ver = 'conflicts'; + } else { + $ver = $d->_getExtraString($inf); + } + $data['data'][] = array($req, ucfirst($deptype), $name, + $ver, $group); + } + } + } + } + } + } + + $this->ui->outputData($data, $command); + return true; + } + + // Fallback + $this->ui->outputData("This package does not have any dependencies.", $command); + } + + // }}} + // {{{ doSign() + + function doSign($command, $options, $params) + { + require_once 'System.php'; + require_once 'Archive/Tar.php'; + // should move most of this code into PEAR_Packager + // so it'll be easy to implement "pear package --sign" + if (sizeof($params) != 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + if (!file_exists($params[0])) { + return $this->raiseError("file does not exist: $params[0]"); + } + $obj = $this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + $tar = new Archive_Tar($params[0]); + $tmpdir = System::mktemp('-d pearsign'); + if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { + return $this->raiseError("failed to extract tar file"); + } + if (file_exists("$tmpdir/package.sig")) { + return $this->raiseError("package already signed"); + } + $packagexml = 'package.xml'; + if (file_exists("$tmpdir/package2.xml")) { + $packagexml = 'package2.xml'; + } + if (file_exists("$tmpdir/package.sig")) { + unlink("$tmpdir/package.sig"); + } + if (!file_exists("$tmpdir/$packagexml")) { + return $this->raiseError("Extracted file $tmpdir/$packagexml not found."); + } + $input = $this->ui->userDialog($command, + array('GnuPG Passphrase'), + array('password')); + if (!isset($input[0])) { + //use empty passphrase + $input[0] = ''; + } + + $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null'; + $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w"); + if (!$gpg) { + return $this->raiseError("gpg command failed"); + } + fwrite($gpg, "$input[0]\n"); + if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { + return $this->raiseError("gpg sign failed"); + } + if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) { + return $this->raiseError('failed adding signature to file'); + } + + $this->ui->outputData("Package signed.", $command); + return true; + } + + // }}} + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + /** + * For unit testing purposes + */ + function &getCommandPackaging(&$ui, &$config) + { + if (!class_exists('PEAR_Command_Packaging')) { + if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) { + fclose($fp); + include_once 'PEAR/Command/Packaging.php'; + } + } + + if (class_exists('PEAR_Command_Packaging')) { + $a = &new PEAR_Command_Packaging($ui, $config); + } else { + $a = null; + } + return $a; + } + + // {{{ doMakeRPM() + + function doMakeRPM($command, $options, $params) + { + + // Check to see if PEAR_Command_Packaging is installed, and + // transparently switch to use the "make-rpm-spec" command from it + // instead, if it does. Otherwise, continue to use the old version + // of "makerpm" supplied with this package (PEAR). + $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config); + if ($packaging_cmd !== null) { + $this->ui->outputData('PEAR_Command_Packaging is installed; using '. + 'newer "make-rpm-spec" command instead'); + return $packaging_cmd->run('make-rpm-spec', $options, $params); + } else { + $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '. + 'improved version is available via "pear make-rpm-spec", which '. + 'is available by installing PEAR_Command_Packaging'); + } + return true; + } + + function doConvert($command, $options, $params) + { + $packagexml = isset($params[0]) ? $params[0] : 'package.xml'; + $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) . + DIRECTORY_SEPARATOR . 'package2.xml'; + $pkg = &$this->getPackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (!PEAR::isError($pf)) { + if (is_a($pf, 'PEAR_PackageFile_v2')) { + $this->ui->outputData($packagexml . ' is already a package.xml version 2.0'); + return true; + } + $gen = &$pf->getDefaultGenerator(); + $newpf = &$gen->toV2(); + $newpf->setPackagefile($newpackagexml); + $gen = &$newpf->getDefaultGenerator(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL); + $saved = $gen->toPackageFile(dirname($newpackagexml), $state, + basename($newpackagexml)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($saved)) { + if (is_array($saved->getUserInfo())) { + foreach ($saved->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); + } + } + $this->ui->outputData($saved->getMessage()); + return true; + } + $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"'); + return true; + } else { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); + } + } + return $this->raiseError($pf); + } + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Command/Package.xml b/vas/rest/class/PEAR/Command/Package.xml new file mode 100755 index 0000000000000000000000000000000000000000..e3f6a553790535dacd463fd3942fb37c665da44a --- /dev/null +++ b/vas/rest/class/PEAR/Command/Package.xml @@ -0,0 +1,194 @@ +<commands version="1.0"> + <package> + <summary>Build Package</summary> + <function>doPackage</function> + <shortcut>p</shortcut> + <options> + <nocompress> + <shortopt>Z</shortopt> + <doc>Do not gzip the package file</doc> + </nocompress> + <showname> + <shortopt>n</shortopt> + <doc>Print the name of the packaged file.</doc> + </showname> + </options> + <doc>[descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" +</doc> + </package> + <package-validate> + <summary>Validate Package Consistency</summary> + <function>doPackageValidate</function> + <shortcut>pv</shortcut> + <options /> + <doc> +</doc> + </package-validate> + <cvsdiff> + <summary>Run a "cvs diff" for all files in a package</summary> + <function>doCvsDiff</function> + <shortcut>cd</shortcut> + <options> + <quiet> + <shortopt>q</shortopt> + <doc>Be quiet</doc> + </quiet> + <reallyquiet> + <shortopt>Q</shortopt> + <doc>Be really quiet</doc> + </reallyquiet> + <date> + <shortopt>D</shortopt> + <doc>Diff against revision of DATE</doc> + <arg>DATE</arg> + </date> + <release> + <shortopt>R</shortopt> + <doc>Diff against tag for package release REL</doc> + <arg>REL</arg> + </release> + <revision> + <shortopt>r</shortopt> + <doc>Diff against revision REV</doc> + <arg>REV</arg> + </revision> + <context> + <shortopt>c</shortopt> + <doc>Generate context diff</doc> + </context> + <unified> + <shortopt>u</shortopt> + <doc>Generate unified diff</doc> + </unified> + <ignore-case> + <shortopt>i</shortopt> + <doc>Ignore case, consider upper- and lower-case letters equivalent</doc> + </ignore-case> + <ignore-whitespace> + <shortopt>b</shortopt> + <doc>Ignore changes in amount of white space</doc> + </ignore-whitespace> + <ignore-blank-lines> + <shortopt>B</shortopt> + <doc>Ignore changes that insert or delete blank lines</doc> + </ignore-blank-lines> + <brief> + <doc>Report only whether the files differ, no details</doc> + </brief> + <dry-run> + <shortopt>n</shortopt> + <doc>Don't do anything, just pretend</doc> + </dry-run> + </options> + <doc><package.xml> +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. +</doc> + </cvsdiff> + <cvstag> + <summary>Set CVS Release Tag</summary> + <function>doCvsTag</function> + <shortcut>ct</shortcut> + <options> + <quiet> + <shortopt>q</shortopt> + <doc>Be quiet</doc> + </quiet> + <reallyquiet> + <shortopt>Q</shortopt> + <doc>Be really quiet</doc> + </reallyquiet> + <slide> + <shortopt>F</shortopt> + <doc>Move (slide) tag if it exists</doc> + </slide> + <delete> + <shortopt>d</shortopt> + <doc>Remove tag</doc> + </delete> + <dry-run> + <shortopt>n</shortopt> + <doc>Don't do anything, just pretend</doc> + </dry-run> + </options> + <doc><package.xml> +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. +</doc> + </cvstag> + <package-dependencies> + <summary>Show package dependencies</summary> + <function>doPackageDependencies</function> + <shortcut>pd</shortcut> + <options /> + <doc> +List all dependencies the package has.</doc> + </package-dependencies> + <sign> + <summary>Sign a package distribution file</summary> + <function>doSign</function> + <shortcut>si</shortcut> + <options /> + <doc><package-file> +Signs a package distribution (.tar or .tgz) file with GnuPG.</doc> + </sign> + <makerpm> + <summary>Builds an RPM spec file from a PEAR package</summary> + <function>doMakeRPM</function> + <shortcut>rpm</shortcut> + <options> + <spec-template> + <shortopt>t</shortopt> + <arg>FILE</arg> + <doc>Use FILE as RPM spec file template</doc> + </spec-template> + <rpm-pkgname> + <shortopt>p</shortopt> + <arg>FORMAT</arg> + <doc>Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s".</doc> + </rpm-pkgname> + </options> + <doc><package-file> + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm +</doc> + </makerpm> + <convert> + <summary>Convert a package.xml 1.0 to package.xml 2.0 format</summary> + <function>doConvert</function> + <shortcut>c2</shortcut> + <options> + <flat> + <shortopt>f</shortopt> + <doc>do not beautify the filelist.</doc> + </flat> + </options> + <doc>[descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. +</doc> + </convert> +</commands> diff --git a/vas/rest/class/PEAR/Command/Pickle.php b/vas/rest/class/PEAR/Command/Pickle.php new file mode 100755 index 0000000000000000000000000000000000000000..d59396aca507f5c64873f1fac21e83d4a3c9780c --- /dev/null +++ b/vas/rest/class/PEAR/Command/Pickle.php @@ -0,0 +1,376 @@ +<?php +/** + * PEAR_Command_Pickle (pickle command) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2005-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Pickle.php,v 1.8 2008/01/29 03:21:01 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2005-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.1 + */ + +class PEAR_Command_Pickle extends PEAR_Command_Common +{ + var $commands = array( + 'pickle' => array( + 'summary' => 'Build PECL Package', + 'function' => 'doPackage', + 'shortcut' => 'pi', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' + ), + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', + ), + ), + 'doc' => '[descfile] +Creates a PECL package from its package2.xml file. + +An automatic conversion will be made to a package.xml 1.0 and written out to +disk in the current directory as "package.xml". Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease or zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml. +' + ), + ); + + /** + * PEAR_Command_Package constructor. + * + * @access public + */ + function PEAR_Command_Pickle(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + + /** + * For unit-testing ease + * + * @return PEAR_Packager + */ + function &getPackager() + { + if (!class_exists('PEAR_Packager')) { + require_once 'PEAR/Packager.php'; + } + $a = &new PEAR_Packager; + return $a; + } + + /** + * For unit-testing ease + * + * @param PEAR_Config $config + * @param bool $debug + * @param string|null $tmpdir + * @return PEAR_PackageFile + */ + function &getPackageFile($config, $debug = false, $tmpdir = null) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $a = &new PEAR_PackageFile($config, $debug, $tmpdir); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); + return $a; + } + + function doPackage($command, $options, $params) + { + $this->output = ''; + $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml'; + $packager = &$this->getPackager(); + if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) { + return $err; + } + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress, 'package.xml'); + if (PEAR::isError($result)) { + return $this->raiseError($result); + } + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->ui->outputData($result, $command); + } + return true; + } + + function _convertPackage($packagexml) + { + $pkg = &$this->getPackageFile($this->config); + $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + if (!is_a($pf2, 'PEAR_PackageFile_v2')) { + return $this->raiseError('Cannot process "' . + $packagexml . '", is not a package.xml 2.0'); + } + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->config); + if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", is not an extension source package. Using a PEAR_PackageFileManager-based ' . + 'script is an option'); + } + if (is_array($pf2->getUsesRole())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + if (is_array($pf2->getUsesTask())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + $deps = $pf2->getDependencies(); + if (isset($deps['group'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + if (isset($deps['required']['subpackage']) || + isset($deps['optional']['subpackage'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + if (isset($deps['required']['os'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains os dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + if (isset($deps['required']['arch'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains arch dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + $pf->setPackage($pf2->getPackage()); + $pf->setSummary($pf2->getSummary()); + $pf->setDescription($pf2->getDescription()); + foreach ($pf2->getMaintainers() as $maintainer) { + $pf->addMaintainer($maintainer['role'], $maintainer['handle'], + $maintainer['name'], $maintainer['email']); + } + $pf->setVersion($pf2->getVersion()); + $pf->setDate($pf2->getDate()); + $pf->setLicense($pf2->getLicense()); + $pf->setState($pf2->getState()); + $pf->setNotes($pf2->getNotes()); + $pf->addPhpDep($deps['required']['php']['min'], 'ge'); + if (isset($deps['required']['php']['max'])) { + $pf->addPhpDep($deps['required']['php']['max'], 'le'); + } + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } + foreach ($deps['required']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge'); + } + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le'); + } + } + } + if (isset($deps['required']['extension'])) { + if (!isset($deps['required']['extension'][0])) { + $deps['required']['extension'] = array($deps['required']['extension']); + } + foreach ($deps['required']['extension'] as $dep) { + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge'); + } + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le'); + } + } + } + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + foreach ($deps['optional']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + if (isset($deps['optional']['extension'])) { + if (!isset($deps['optional']['extension'][0])) { + $deps['optional']['extension'] = array($deps['optional']['extension']); + } + foreach ($deps['optional']['extension'] as $dep) { + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + $contents = $pf2->getContents(); + $release = $pf2->getReleases(); + if (isset($releases[0])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + if ($configoptions = $pf2->getConfigureOptions()) { + foreach ($configoptions as $option) { + $pf->addConfigureOption($option['name'], $option['prompt'], + isset($option['default']) ? $option['default'] : false); + } + } + if (isset($release['filelist']['ignore'])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' . + ' command is an option'); + } + if (isset($release['filelist']['install']) && + !isset($release['filelist']['install'][0])) { + $release['filelist']['install'] = array($release['filelist']['install']); + } + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $baseinstalldir = $contents['dir']['attribs']['baseinstalldir']; + } else { + $baseinstalldir = false; + } + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + foreach ($contents['dir']['file'] as $file) { + if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) { + $file['attribs']['baseinstalldir'] = $baseinstalldir; + } + $processFile = $file; + unset($processFile['attribs']); + if (count($processFile)) { + foreach ($processFile as $name => $task) { + if ($name != $pf2->getTasksNs() . ':replace') { + return $this->raiseError('Cannot safely process "' . $packagexml . + '" contains tasks other than replace. Using a ' . + 'PEAR_PackageFileManager-based script is an option.'); + } + $file['attribs']['replace'][] = $task; + } + } + if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + if (isset($release['filelist']['install'])) { + foreach ($release['filelist']['install'] as $installas) { + if ($installas['attribs']['name'] == $file['attribs']['name']) { + $file['attribs']['install-as'] = $installas['attribs']['as']; + } + } + } + $pf->addFile('/', $file['attribs']['name'], $file['attribs']); + } + if ($pf2->getChangeLog()) { + $this->ui->outputData('WARNING: changelog is not translated to package.xml ' . + '1.0, use PEAR_PackageFileManager-based script if you need changelog-' . + 'translation for package.xml 1.0'); + } + $gen = &$pf->getDefaultGenerator(); + $gen->toPackageFile('.'); + } +} + +?> diff --git a/vas/rest/class/PEAR/Command/Pickle.xml b/vas/rest/class/PEAR/Command/Pickle.xml new file mode 100755 index 0000000000000000000000000000000000000000..04c85bc76d36cf391647f171c2dce636db986115 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Pickle.xml @@ -0,0 +1,40 @@ +<commands version="1.0"> + <pickle> + <summary>Build PECL Package</summary> + <function>doPackage</function> + <shortcut>pi</shortcut> + <options> + <nocompress> + <shortopt>Z</shortopt> + <doc>Do not gzip the package file</doc> + </nocompress> + <showname> + <shortopt>n</shortopt> + <doc>Print the name of the packaged file.</doc> + </showname> + </options> + <doc>[descfile] [descfile2] +Creates a PECL package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" + +If no second file is passed in, and [descfile] is a package.xml 2.0, +an automatic conversion will be made to a package.xml 1.0. Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease/zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml.</doc> + </pickle> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Registry.php b/vas/rest/class/PEAR/Command/Registry.php new file mode 100755 index 0000000000000000000000000000000000000000..d2f1dd1b7871883e94af38635ad56ec68a08c08e --- /dev/null +++ b/vas/rest/class/PEAR/Command/Registry.php @@ -0,0 +1,1070 @@ +<?php +/** + * PEAR_Command_Registry (list, list-files, shell-test, info commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Registry.php,v 1.81 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for registry manipulation + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Registry extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'list' => array( + 'summary' => 'List Installed Packages In The Default Channel', + 'function' => 'doList', + 'shortcut' => 'l', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'list installed packages from this channel', + 'arg' => 'CHAN', + ), + 'allchannels' => array( + 'shortopt' => 'a', + 'doc' => 'list installed packages from all channels', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => '<package> +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. +', + ), + 'list-files' => array( + 'summary' => 'List Files In Installed Package', + 'function' => 'doFileList', + 'shortcut' => 'fl', + 'options' => array(), + 'doc' => '<package> +List the files in an installed package. +' + ), + 'shell-test' => array( + 'summary' => 'Shell Script Test', + 'function' => 'doShellTest', + 'shortcut' => 'st', + 'options' => array(), + 'doc' => '<package> [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + <relation> The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + <version> The version to compare with +'), + 'info' => array( + 'summary' => 'Display information about a package', + 'function' => 'doInfo', + 'shortcut' => 'in', + 'options' => array(), + 'doc' => '<package> +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package.' + ) + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Registry(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + // {{{ doList() + + function _sortinfo($a, $b) + { + $apackage = isset($a['package']) ? $a['package'] : $a['name']; + $bpackage = isset($b['package']) ? $b['package'] : $b['name']; + return strcmp($apackage, $bpackage); + } + + function doList($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $channelinfo = isset($options['channelinfo']); + if (isset($options['allchannels']) && !$channelinfo) { + return $this->doListAll($command, array(), $params); + } + if (isset($options['allchannels']) && $channelinfo) { + // allchannels with $channelinfo + unset($options['allchannels']); + $channels = $reg->getChannels(); + $errors = array(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + foreach ($channels as $channel) { + $options['channel'] = $channel->getName(); + $ret = $this->doList($command, $options, $params); + + if (PEAR::isError($ret)) { + $errors[] = $ret; + } + } + PEAR::staticPopErrorHandling(); + if (count($errors)) { + // for now, only give first error + return PEAR::raiseError($errors[0]); + } + return true; + } + + if (count($params) == 1) { + return $this->doFileList($command, $options, $params); + } + if (isset($options['channel'])) { + if ($reg->channelExists($options['channel'])) { + $channel = $reg->channelName($options['channel']); + } else { + return $this->raiseError('Channel "' . $options['channel'] .'" does not exist'); + } + } else { + $channel = $this->config->get('default_channel'); + } + $installed = $reg->packageInfo(null, null, $channel); + usort($installed, array(&$this, '_sortinfo')); + + $data = array( + 'caption' => 'Installed packages, channel ' . + $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Version', 'State'), + 'channel' => $channel, + ); + if ($channelinfo) { + $data['headline'] = array('Channel', 'Package', 'Version', 'State'); + } + + if (count($installed) && !isset($data['data'])) { + $data['data'] = array(); + } + + foreach ($installed as $package) { + $pobj = $reg->getPackage(isset($package['package']) ? + $package['package'] : $package['name'], $channel); + if ($channelinfo) { + $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } else { + $packageinfo = array($pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } + $data['data'][] = $packageinfo; + } + if (count($installed) == 0) { + if (!$channelinfo) { + $data = '(no packages installed from channel ' . $channel . ')'; + } else { + $data = array( + 'caption' => 'Installed packages, channel ' . + $channel . ':', + 'border' => true, + 'channel' => $channel, + 'data' => '(no packages installed)', + ); + } + } + $this->ui->outputData($data, $command); + return true; + } + + function doListAll($command, $options, $params) + { + // This duplicate code is deprecated over + // list --channelinfo, which gives identical + // output for list and list --allchannels. + $reg = &$this->config->getRegistry(); + $installed = $reg->packageInfo(null, null, null); + foreach ($installed as $channel => $packages) { + usort($packages, array($this, '_sortinfo')); + $data = array( + 'caption' => 'Installed packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Version', 'State'), + 'channel' => $channel + ); + foreach ($packages as $package) { + $pobj = $reg->getPackage(isset($package['package']) ? + $package['package'] : $package['name'], $channel); + $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } + if (count($packages)==0) { + $data = array( + 'caption' => 'Installed packages, channel ' . $channel . ':', + 'border' => true, + 'data' => array(array('(no packages installed)')), + 'channel' => $channel + ); + } + $this->ui->outputData($data, $command); + } + return true; + } + + function doFileList($command, $options, $params) + { + if (count($params) != 1) { + return $this->raiseError('list-files expects 1 parameter'); + } + $reg = &$this->config->getRegistry(); + $fp = false; + if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], + 'r'))) { + if ($fp) { + fclose($fp); + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $pkg = &new PEAR_PackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + $headings = array('Package File', 'Install Path'); + $installed = false; + } else { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + $info = &$reg->getPackage($parsed['package'], $parsed['channel']); + $headings = array('Type', 'Install Path'); + $installed = true; + } + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + if ($info === null) { + return $this->raiseError("`$params[0]' not installed"); + } + $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ? + $info->getFilelist() : $info->getContents(); + if ($installed) { + $caption = 'Installed Files For ' . $params[0]; + } else { + $caption = 'Contents of ' . basename($params[0]); + } + $data = array( + 'caption' => $caption, + 'border' => true, + 'headline' => $headings); + if ($info->getPackagexmlVersion() == '1.0' || $installed) { + foreach ($list as $file => $att) { + if ($installed) { + if (empty($att['installed_as'])) { + continue; + } + $data['data'][] = array($att['role'], $att['installed_as']); + } else { + if (isset($att['baseinstalldir']) && !in_array($att['role'], + array('test', 'data', 'doc'))) { + $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . + $file; + } else { + $dest = $file; + } + switch ($att['role']) { + case 'test': + case 'data': + case 'doc': + $role = $att['role']; + if ($role == 'test') { + $role .= 's'; + } + $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR . + $info->getPackage() . DIRECTORY_SEPARATOR . $dest; + break; + case 'php': + default: + $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR . + $dest; + } + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + $dest); + $file = preg_replace('!/+!', '/', $file); + $data['data'][] = array($file, $dest); + } + } + } else { // package.xml 2.0, not installed + if (!isset($list['dir']['file'][0])) { + $list['dir']['file'] = array($list['dir']['file']); + } + foreach ($list['dir']['file'] as $att) { + $att = $att['attribs']; + $file = $att['name']; + $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config); + $role->setup($this, $info, $att, $file); + if (!$role->isInstallable()) { + $dest = '(not installable)'; + } else { + $dest = $role->processInstallation($info, $att, $file, ''); + if (PEAR::isError($dest)) { + $dest = '(Unknown role "' . $att['role'] . ')'; + } else { + list(,, $dest) = $dest; + } + } + $data['data'][] = array($file, $dest); + } + } + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doShellTest() + + function doShellTest($command, $options, $params) + { + if (count($params) < 1) { + return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]'); + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $reg = &$this->config->getRegistry(); + $info = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + if (PEAR::isError($info)) { + exit(1); // invalid package name + } + $package = $info['package']; + $channel = $info['channel']; + // "pear shell-test Foo" + if (!$reg->packageExists($package, $channel)) { + if ($channel == 'pecl.php.net') { + if ($reg->packageExists($package, 'pear.php.net')) { + $channel = 'pear.php.net'; // magically change channels for extensions + } + } + } + if (sizeof($params) == 1) { + if (!$reg->packageExists($package, $channel)) { + exit(1); + } + // "pear shell-test Foo 1.0" + } elseif (sizeof($params) == 2) { + $v = $reg->packageInfo($package, 'version', $channel); + if (!$v || !version_compare("$v", "{$params[1]}", "ge")) { + exit(1); + } + // "pear shell-test Foo ge 1.0" + } elseif (sizeof($params) == 3) { + $v = $reg->packageInfo($package, 'version', $channel); + if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) { + exit(1); + } + } else { + PEAR::staticPopErrorHandling(); + $this->raiseError("$command: expects 1 to 3 parameters"); + exit(1); + } + } + + // }}} + // {{{ doInfo + + function doInfo($command, $options, $params) + { + if (count($params) != 1) { + return $this->raiseError('pear info expects 1 parameter'); + } + $info = $fp = false; + $reg = &$this->config->getRegistry(); + if ((file_exists($params[0]) && is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) { + if ($fp) { + fclose($fp); + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $pkg = &new PEAR_PackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($obj)) { + $uinfo = $obj->getUserInfo(); + if (is_array($uinfo)) { + foreach ($uinfo as $message) { + if (is_array($message)) { + $message = $message['message']; + } + $this->ui->outputData($message); + } + } + return $this->raiseError($obj); + } + if ($obj->getPackagexmlVersion() == '1.0') { + $info = $obj->toArray(); + } else { + return $this->_doInfo2($command, $options, $params, $obj, false); + } + } else { + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + $package = $parsed['package']; + $channel = $parsed['channel']; + $info = $reg->packageInfo($package, null, $channel); + if (isset($info['old'])) { + $obj = $reg->getPackage($package, $channel); + return $this->_doInfo2($command, $options, $params, $obj, true); + } + } + if (PEAR::isError($info)) { + return $info; + } + if (empty($info)) { + $this->raiseError("No information found for `$params[0]'"); + return; + } + unset($info['filelist']); + unset($info['dirtree']); + unset($info['changelog']); + if (isset($info['xsdversion'])) { + $info['package.xml version'] = $info['xsdversion']; + unset($info['xsdversion']); + } + if (isset($info['packagerversion'])) { + $info['packaged with PEAR version'] = $info['packagerversion']; + unset($info['packagerversion']); + } + $keys = array_keys($info); + $longtext = array('description', 'summary'); + foreach ($keys as $key) { + if (is_array($info[$key])) { + switch ($key) { + case 'maintainers': { + $i = 0; + $mstr = ''; + foreach ($info[$key] as $m) { + if ($i++ > 0) { + $mstr .= "\n"; + } + $mstr .= $m['name'] . " <"; + if (isset($m['email'])) { + $mstr .= $m['email']; + } else { + $mstr .= $m['handle'] . '@php.net'; + } + $mstr .= "> ($m[role])"; + } + $info[$key] = $mstr; + break; + } + case 'release_deps': { + $i = 0; + $dstr = ''; + foreach ($info[$key] as $d) { + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + if (isset($d['name'])) { + $name = $d['name'] . ' '; + } else { + $name = ''; + } + if (isset($d['version'])) { + $version = $d['version'] . ' '; + } else { + $version = ''; + } + if (isset($d['optional']) && $d['optional'] == 'yes') { + $optional = ' (optional)'; + } else { + $optional = ''; + } + $dstr .= "$type $name$rel $version$optional\n"; + } + $info[$key] = $dstr; + break; + } + case 'provides' : { + $debug = $this->config->get('verbose'); + if ($debug < 2) { + $pstr = 'Classes: '; + } else { + $pstr = ''; + } + $i = 0; + foreach ($info[$key] as $p) { + if ($debug < 2 && $p['type'] != "class") { + continue; + } + // Only print classes when verbosity mode is < 2 + if ($debug < 2) { + if ($i++ > 0) { + $pstr .= ", "; + } + $pstr .= $p['name']; + } else { + if ($i++ > 0) { + $pstr .= "\n"; + } + $pstr .= ucfirst($p['type']) . " " . $p['name']; + if (isset($p['explicit']) && $p['explicit'] == 1) { + $pstr .= " (explicit)"; + } + } + } + $info[$key] = $pstr; + break; + } + case 'configure_options' : { + foreach ($info[$key] as $i => $p) { + $info[$key][$i] = array_map(null, array_keys($p), array_values($p)); + $info[$key][$i] = array_map(create_function('$a', + 'return join(" = ",$a);'), $info[$key][$i]); + $info[$key][$i] = implode(', ', $info[$key][$i]); + } + $info[$key] = implode("\n", $info[$key]); + break; + } + default: { + $info[$key] = implode(", ", $info[$key]); + break; + } + } + } + if ($key == '_lastmodified') { + $hdate = date('Y-m-d', $info[$key]); + unset($info[$key]); + $info['Last Modified'] = $hdate; + } elseif ($key == '_lastversion') { + $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -'; + unset($info[$key]); + } else { + $info[$key] = trim($info[$key]); + if (in_array($key, $longtext)) { + $info[$key] = preg_replace('/ +/', ' ', $info[$key]); + } + } + } + $caption = 'About ' . $info['package'] . '-' . $info['version']; + $data = array( + 'caption' => $caption, + 'border' => true); + foreach ($info as $key => $value) { + $key = ucwords(trim(str_replace('_', ' ', $key))); + $data['data'][] = array($key, $value); + } + $data['raw'] = $info; + + $this->ui->outputData($data, 'package-info'); + } + + // }}} + + /** + * @access private + */ + function _doInfo2($command, $options, $params, &$obj, $installed) + { + $reg = &$this->config->getRegistry(); + $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' . + $obj->getVersion(); + $data = array( + 'caption' => $caption, + 'border' => true); + switch ($obj->getPackageType()) { + case 'php' : + $release = 'PEAR-style PHP-based Package'; + break; + case 'extsrc' : + $release = 'PECL-style PHP extension (source code)'; + break; + case 'zendextsrc' : + $release = 'PECL-style Zend extension (source code)'; + break; + case 'extbin' : + $release = 'PECL-style PHP extension (binary)'; + break; + case 'zendextbin' : + $release = 'PECL-style Zend extension (binary)'; + break; + case 'bundle' : + $release = 'Package bundle (collection of packages)'; + break; + } + $extends = $obj->getExtends(); + $extends = $extends ? + $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage(); + if ($src = $obj->getSourcePackage()) { + $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')'; + } + $info = array( + 'Release Type' => $release, + 'Name' => $extends, + 'Channel' => $obj->getChannel(), + 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()), + 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()), + ); + $info['Maintainers'] = ''; + foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { + $leads = $obj->{"get{$role}s"}(); + if (!$leads) { + continue; + } + if (isset($leads['active'])) { + $leads = array($leads); + } + foreach ($leads as $lead) { + if (!empty($info['Maintainers'])) { + $info['Maintainers'] .= "\n"; + } + $info['Maintainers'] .= $lead['name'] . ' <'; + $info['Maintainers'] .= $lead['email'] . "> ($role)"; + } + } + $info['Release Date'] = $obj->getDate(); + if ($time = $obj->getTime()) { + $info['Release Date'] .= ' ' . $time; + } + $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')'; + $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')'; + $info['License'] = $obj->getLicense(); + $uri = $obj->getLicenseLocation(); + if ($uri) { + if (isset($uri['uri'])) { + $info['License'] .= ' (' . $uri['uri'] . ')'; + } else { + $extra = $obj->getInstalledLocation($info['filesource']); + if ($extra) { + $info['License'] .= ' (' . $uri['filesource'] . ')'; + } + } + } + $info['Release Notes'] = $obj->getNotes(); + if ($compat = $obj->getCompatible()) { + if (!isset($compat[0])) { + $compat = array($compat); + } + $info['Compatible with'] = ''; + foreach ($compat as $package) { + $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] . + "\nVersions >= " . $package['min'] . ', <= ' . $package['max']; + if (isset($package['exclude'])) { + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= $package['channel'] . '/' . + $package['name'] . "\nVersions " . $package['exclude']; + } + } + } + $usesrole = $obj->getUsesrole(); + if ($usesrole) { + if (!isset($usesrole[0])) { + $usesrole = array($usesrole); + } + foreach ($usesrole as $roledata) { + if (isset($info['Uses Custom Roles'])) { + $info['Uses Custom Roles'] .= "\n"; + } else { + $info['Uses Custom Roles'] = ''; + } + if (isset($roledata['package'])) { + $rolepackage = $reg->parsedPackageNameToString($roledata, true); + } else { + $rolepackage = $roledata['uri']; + } + $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')'; + } + } + $usestask = $obj->getUsestask(); + if ($usestask) { + if (!isset($usestask[0])) { + $usestask = array($usestask); + } + foreach ($usestask as $taskdata) { + if (isset($info['Uses Custom Tasks'])) { + $info['Uses Custom Tasks'] .= "\n"; + } else { + $info['Uses Custom Tasks'] = ''; + } + if (isset($taskdata['package'])) { + $taskpackage = $reg->parsedPackageNameToString($taskdata, true); + } else { + $taskpackage = $taskdata['uri']; + } + $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')'; + } + } + $deps = $obj->getDependencies(); + $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min']; + if (isset($deps['required']['php']['max'])) { + $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n"; + } else { + $info['Required Dependencies'] .= "\n"; + } + if (isset($deps['required']['php']['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + if (is_array($deps['required']['php']['exclude'])) { + $deps['required']['php']['exclude'] = + implode(', ', $deps['required']['php']['exclude']); + } + $info['Not Compatible with'] .= "PHP versions\n " . + $deps['required']['php']['exclude']; + } + $info['Required Dependencies'] .= 'PEAR installer version'; + if (isset($deps['required']['pearinstaller']['max'])) { + $info['Required Dependencies'] .= 's ' . + $deps['required']['pearinstaller']['min'] . '-' . + $deps['required']['pearinstaller']['max']; + } else { + $info['Required Dependencies'] .= ' ' . + $deps['required']['pearinstaller']['min'] . ' or newer'; + } + if (isset($deps['required']['pearinstaller']['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + if (is_array($deps['required']['pearinstaller']['exclude'])) { + $deps['required']['pearinstaller']['exclude'] = + implode(', ', $deps['required']['pearinstaller']['exclude']); + } + $info['Not Compatible with'] .= "PEAR installer\n Versions " . + $deps['required']['pearinstaller']['exclude']; + } + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($deps['required'][$index])) { + if (isset($deps['required'][$index]['name'])) { + $deps['required'][$index] = array($deps['required'][$index]); + } + foreach ($deps['required'][$index] as $package) { + if (isset($package['conflicts'])) { + $infoindex = 'Not Compatible with'; + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + } else { + $infoindex = 'Required Dependencies'; + $info[$infoindex] .= "\n"; + } + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + $info[$infoindex] .= "$type $name"; + if (isset($package['uri'])) { + $info[$infoindex] .= "\n Download URI: $package[uri]"; + continue; + } + if (isset($package['max']) && isset($package['min'])) { + $info[$infoindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$infoindex] .= " \n Version " . + $package['max'] . ' or older'; + } + if (isset($package['recommended'])) { + $info[$infoindex] .= "\n Recommended version: $package[recommended]"; + } + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + $package['package'] = $package['name']; // for parsedPackageNameToString + if (isset($package['conflicts'])) { + $info['Not Compatible with'] .= '=> except '; + } + $info['Not Compatible with'] .= 'Package ' . + $reg->parsedPackageNameToString($package, true); + $info['Not Compatible with'] .= "\n Versions " . $package['exclude']; + } + } + } + } + if (isset($deps['required']['os'])) { + if (isset($deps['required']['os']['name'])) { + $dep['required']['os']['name'] = array($dep['required']['os']['name']); + } + foreach ($dep['required']['os'] as $os) { + if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= "$os[name] Operating System"; + } else { + $info['Required Dependencies'] .= "\n"; + $info['Required Dependencies'] .= "$os[name] Operating System"; + } + } + } + if (isset($deps['required']['arch'])) { + if (isset($deps['required']['arch']['pattern'])) { + $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']); + } + foreach ($dep['required']['arch'] as $os) { + if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'"; + } else { + $info['Required Dependencies'] .= "\n"; + $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'"; + } + } + } + if (isset($deps['optional'])) { + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($deps['optional'][$index])) { + if (isset($deps['optional'][$index]['name'])) { + $deps['optional'][$index] = array($deps['optional'][$index]); + } + foreach ($deps['optional'][$index] as $package) { + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $infoindex = 'Not Compatible with'; + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + } else { + $infoindex = 'Optional Dependencies'; + if (!isset($info['Optional Dependencies'])) { + $info['Optional Dependencies'] = ''; + } else { + $info['Optional Dependencies'] .= "\n"; + } + } + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + $info[$infoindex] .= "$type $name"; + if (isset($package['uri'])) { + $info[$infoindex] .= "\n Download URI: $package[uri]"; + continue; + } + if ($infoindex == 'Not Compatible with') { + // conflicts is only used to say that all versions conflict + continue; + } + if (isset($package['max']) && isset($package['min'])) { + $info[$infoindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or older'; + } + if (isset($package['recommended'])) { + $info[$infoindex] .= "\n Recommended version: $package[recommended]"; + } + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + $info['Not Compatible with'] .= "Package $package\n Versions " . + $package['exclude']; + } + } + } + } + } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + foreach ($deps['group'] as $group) { + $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint']; + $groupindex = $group['attribs']['name'] . ' Contents'; + $info[$groupindex] = ''; + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($group[$index])) { + if (isset($group[$index]['name'])) { + $group[$index] = array($group[$index]); + } + foreach ($group[$index] as $package) { + if (!empty($info[$groupindex])) { + $info[$groupindex] .= "\n"; + } + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + if (isset($package['uri'])) { + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $info[$groupindex] .= "Not Compatible with $type $name"; + } else { + $info[$groupindex] .= "$type $name"; + } + $info[$groupindex] .= "\n Download URI: $package[uri]"; + continue; + } + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $info[$groupindex] .= "Not Compatible with $type $name"; + continue; + } + $info[$groupindex] .= "$type $name"; + if (isset($package['max']) && isset($package['min'])) { + $info[$groupindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$groupindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$groupindex] .= " \n Version " . + $package['min'] . ' or older'; + } + if (isset($package['recommended'])) { + $info[$groupindex] .= "\n Recommended version: $package[recommended]"; + } + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info[$groupindex] .= "Not Compatible with\n"; + } + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + $info[$groupindex] .= " Package $package\n Versions " . + $package['exclude']; + } + } + } + } + } + } + if ($obj->getPackageType() == 'bundle') { + $info['Bundled Packages'] = ''; + foreach ($obj->getBundledPackages() as $package) { + if (!empty($info['Bundled Packages'])) { + $info['Bundled Packages'] .= "\n"; + } + if (isset($package['uri'])) { + $info['Bundled Packages'] .= '__uri/' . $package['name']; + $info['Bundled Packages'] .= "\n (URI: $package[uri]"; + } else { + $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name']; + } + } + } + $info['package.xml version'] = '2.0'; + if ($installed) { + if ($obj->getLastModified()) { + $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified()); + } + $v = $obj->getLastInstalledVersion(); + $info['Previous Installed Version'] = $v ? $v : '- None -'; + } + foreach ($info as $key => $value) { + $data['data'][] = array($key, $value); + } + $data['raw'] = $obj->getArray(); // no validation needed + + $this->ui->outputData($data, 'package-info'); + } +} + +?> diff --git a/vas/rest/class/PEAR/Command/Registry.xml b/vas/rest/class/PEAR/Command/Registry.xml new file mode 100755 index 0000000000000000000000000000000000000000..9f4e2149672f9ed2b0b39947292108ac81444d1b --- /dev/null +++ b/vas/rest/class/PEAR/Command/Registry.xml @@ -0,0 +1,58 @@ +<commands version="1.0"> + <list> + <summary>List Installed Packages In The Default Channel</summary> + <function>doList</function> + <shortcut>l</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>list installed packages from this channel</doc> + <arg>CHAN</arg> + </channel> + <allchannels> + <shortopt>a</shortopt> + <doc>list installed packages from all channels</doc> + </allchannels> + <channelinfo> + <shortopt>i</shortopt> + <doc>output fully channel-aware data, even on failure</doc> + </channelinfo> + </options> + <doc><package> +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. +</doc> + </list> + <list-files> + <summary>List Files In Installed Package</summary> + <function>doFileList</function> + <shortcut>fl</shortcut> + <options /> + <doc><package> +List the files in an installed package. +</doc> + </list-files> + <shell-test> + <summary>Shell Script Test</summary> + <function>doShellTest</function> + <shortcut>st</shortcut> + <options /> + <doc><package> [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + <relation> The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + <version> The version to compare with +</doc> + </shell-test> + <info> + <summary>Display information about a package</summary> + <function>doInfo</function> + <shortcut>in</shortcut> + <options /> + <doc><package> +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package.</doc> + </info> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Remote.php b/vas/rest/class/PEAR/Command/Remote.php new file mode 100755 index 0000000000000000000000000000000000000000..c4fa9088c6f6ab32c737e6707fcf2895026d8123 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Remote.php @@ -0,0 +1,812 @@ +<?php +/** + * PEAR_Command_Remote (remote-info, list-upgrades, remote-list, search, list-all, download, + * clear-cache commands) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Remote.php,v 1.107 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; +require_once 'PEAR/REST.php'; + +/** + * PEAR commands for remote server querying + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Remote extends PEAR_Command_Common +{ + // {{{ command definitions + + var $commands = array( + 'remote-info' => array( + 'summary' => 'Information About Remote Packages', + 'function' => 'doRemoteInfo', + 'shortcut' => 'ri', + 'options' => array(), + 'doc' => '<package> +Get details on a package from the server.', + ), + 'list-upgrades' => array( + 'summary' => 'List Available Upgrades', + 'function' => 'doListUpgrades', + 'shortcut' => 'lu', + 'options' => array( + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => '[preferred_state] +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.) +or the state passed as the second parameter.' + ), + 'remote-list' => array( + 'summary' => 'List Remote Packages', + 'function' => 'doRemoteList', + 'shortcut' => 'rl', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ) + ), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'search' => array( + 'summary' => 'Search remote package database', + 'function' => 'doSearch', + 'shortcut' => 'sp', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + 'allchannels' => array( + 'shortopt' => 'a', + 'doc' => 'search packages from all known channels', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => '[packagename] [packageinfo] +Lists all packages which match the search parameters. The first +parameter is a fragment of a packagename. The default channel +will be used unless explicitly overridden. The second parameter +will be used to match any portion of the summary/description', + ), + 'list-all' => array( + 'summary' => 'List All Packages', + 'function' => 'doListAll', + 'shortcut' => 'la', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'download' => array( + 'summary' => 'Download Package', + 'function' => 'doDownload', + 'shortcut' => 'd', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'download an uncompressed (.tar) file', + ), + ), + 'doc' => '<package>... +Download package tarballs. The files will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.', + ), + 'clear-cache' => array( + 'summary' => 'Clear Web Services Cache', + 'function' => 'doClearCache', + 'shortcut' => 'cc', + 'options' => array(), + 'doc' => ' +Clear the XML-RPC/REST cache. See also the cache_ttl configuration +parameter. +', + ), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Remote constructor. + * + * @access public + */ + function PEAR_Command_Remote(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + function _checkChannelForStatus($channel, $chan) + { + if (PEAR::isError($chan)) { + $this->raiseError($chan); + } + if (!is_a($chan, 'PEAR_ChannelFile')) { + return $this->raiseError('Internal corruption error: invalid channel "' . + $channel . '"'); + } + $rest = new PEAR_REST($this->config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $mirror = $this->config->get('preferred_mirror', null, + $channel); + $a = $rest->downloadHttp('http://' . $channel . + '/channel.xml', $chan->lastModified()); + PEAR::staticPopErrorHandling(); + if (!PEAR::isError($a) && $a) { + $this->ui->outputData('WARNING: channel "' . $channel . '" has ' . + 'updated its protocols, use "channel-update ' . $channel . + '" to update'); + } + } + + // {{{ doRemoteInfo() + + function doRemoteInfo($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError("$command expects one param: the remote package name"); + } + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + $package = $params[0]; + $parsed = $reg->parsePackageName($package, $channel); + if (PEAR::isError($parsed)) { + return $this->raiseError('Invalid package name "' . $package . '"'); + } + + $channel = $parsed['channel']; + $this->config->set('default_channel', $channel); + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $info = $rest->packageInfo($base, $parsed['package'], $channel); + } else { + $r = &$this->config->getRemote(); + $info = $r->call('package.info', $parsed['package']); + } + if (PEAR::isError($info)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($info); + } + if (!isset($info['name'])) { + return $this->raiseError('No remote package "' . $package . '" was found'); + } + + $installed = $reg->packageInfo($info['name'], null, $channel); + $info['installed'] = $installed['version'] ? $installed['version'] : '- no -'; + if (is_array($info['installed'])) { + $info['installed'] = $info['installed']['release']; + } + + $this->ui->outputData($info, $command); + $this->config->set('default_channel', $savechannel); + + return true; + } + + // }}} + // {{{ doRemoteList() + + function doRemoteList($command, $options, $params) + { + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (isset($options['channel'])) { + $channel = $options['channel']; + if ($reg->channelExists($channel)) { + $this->config->set('default_channel', $channel); + } else { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + } + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') { + $list_options = true; + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) { + // use faster list-all if available + $rest = &$this->config->getREST('1.1', array()); + $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); + } else { + $r = &$this->config->getRemote(); + if ($channel == 'pear.php.net') { + // hack because of poor pearweb design + $available = $r->call('package.listAll', true, $list_options, false); + } else { + $available = $r->call('package.listAll', true, $list_options); + } + } + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($available); + } + $i = $j = 0; + $data = array( + 'caption' => 'Channel ' . $channel . ' Available packages:', + 'border' => true, + 'headline' => array('Package', 'Version'), + 'channel' => $channel + ); + if (count($available)==0) { + $data = '(no packages available yet)'; + } else { + foreach ($available as $name => $info) { + $data['data'][] = array($name, (isset($info['stable']) && $info['stable']) + ? $info['stable'] : '-n/a-'); + } + } + $this->ui->outputData($data, $command); + $this->config->set('default_channel', $savechannel); + return true; + } + + // }}} + // {{{ doListAll() + + function doListAll($command, $options, $params) + { + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (isset($options['channel'])) { + $channel = $options['channel']; + if ($reg->channelExists($channel)) { + $this->config->set('default_channel', $channel); + } else { + return $this->raiseError("Channel \"$channel\" does not exist"); + } + } + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') { + $list_options = true; + } + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) { + // use faster list-all if available + $rest = &$this->config->getREST('1.1', array()); + $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); + } else { + $r = &$this->config->getRemote(); + if ($channel == 'pear.php.net') { + // hack because of poor pearweb design + $available = $r->call('package.listAll', true, $list_options, false); + } else { + $available = $r->call('package.listAll', true, $list_options); + } + } + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")'); + } + $data = array( + 'caption' => 'All packages [Channel ' . $channel . ']:', + 'border' => true, + 'headline' => array('Package', 'Latest', 'Local'), + 'channel' => $channel, + ); + if (isset($options['channelinfo'])) { + // add full channelinfo + $data['caption'] = 'Channel ' . $channel . ' All packages:'; + $data['headline'] = array('Channel', 'Package', 'Latest', 'Local', + 'Description', 'Dependencies'); + } + $local_pkgs = $reg->listPackages($channel); + + foreach ($available as $name => $info) { + $installed = $reg->packageInfo($name, null, $channel); + if (is_array($installed['version'])) { + $installed['version'] = $installed['version']['release']; + } + $desc = $info['summary']; + if (isset($params[$name])) { + $desc .= "\n\n".$info['description']; + } + if (isset($options['mode'])) + { + if ($options['mode'] == 'installed' && !isset($installed['version'])) { + continue; + } + if ($options['mode'] == 'notinstalled' && isset($installed['version'])) { + continue; + } + if ($options['mode'] == 'upgrades' + && (!isset($installed['version']) || version_compare($installed['version'], + $info['stable'], '>='))) { + continue; + } + } + $pos = array_search(strtolower($name), $local_pkgs); + if ($pos !== false) { + unset($local_pkgs[$pos]); + } + + if (isset($info['stable']) && !$info['stable']) { + $info['stable'] = null; + } + + if (isset($options['channelinfo'])) { + // add full channelinfo + if ($info['stable'] === $info['unstable']) { + $state = $info['state']; + } else { + $state = 'stable'; + } + $latest = $info['stable'].' ('.$state.')'; + $local = ''; + if (isset($installed['version'])) { + $inst_state = $reg->packageInfo($name, 'release_state', $channel); + $local = $installed['version'].' ('.$inst_state.')'; + } + + $packageinfo = array( + $channel, + $name, + $latest, + $local, + isset($desc) ? $desc : null, + isset($info['deps']) ? $info['deps'] : null, + ); + } else { + $packageinfo = array( + $reg->channelAlias($channel) . '/' . $name, + isset($info['stable']) ? $info['stable'] : null, + isset($installed['version']) ? $installed['version'] : null, + isset($desc) ? $desc : null, + isset($info['deps']) ? $info['deps'] : null, + ); + } + $data['data'][$info['category']][] = $packageinfo; + } + + if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) { + $this->config->set('default_channel', $savechannel); + $this->ui->outputData($data, $command); + return true; + } + foreach ($local_pkgs as $name) { + $info = &$reg->getPackage($name, $channel); + $data['data']['Local'][] = array( + $reg->channelAlias($channel) . '/' . $info->getPackage(), + '', + $info->getVersion(), + $info->getSummary(), + $info->getDeps() + ); + } + + $this->config->set('default_channel', $savechannel); + $this->ui->outputData($data, $command); + return true; + } + + // }}} + // {{{ doSearch() + + function doSearch($command, $options, $params) + { + if ((!isset($params[0]) || empty($params[0])) + && (!isset($params[1]) || empty($params[1]))) + { + return $this->raiseError('no valid search string supplied'); + }; + + $channelinfo = isset($options['channelinfo']); + $reg = &$this->config->getRegistry(); + if (isset($options['allchannels'])) { + // search all channels + unset($options['allchannels']); + $channels = $reg->getChannels(); + $errors = array(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + foreach ($channels as $channel) { + if ($channel->getName() != '__uri') { + $options['channel'] = $channel->getName(); + $ret = $this->doSearch($command, $options, $params); + if (PEAR::isError($ret)) { + $errors[] = $ret; + } + } + } + PEAR::staticPopErrorHandling(); + if (count($errors) !== 0) { + // for now, only give first error + return PEAR::raiseError($errors[0]); + } + + return true; + } + + $savechannel = $channel = $this->config->get('default_channel'); + $package = $params[0]; + $summary = isset($params[1]) ? $params[1] : false; + if (isset($options['channel'])) { + $reg = &$this->config->getRegistry(); + $channel = $options['channel']; + if ($reg->channelExists($channel)) { + $this->config->set('default_channel', $channel); + } else { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + } + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName()); + } else { + $r = &$this->config->getRemote(); + $available = $r->call('package.search', $package, $summary, true, + $this->config->get('preferred_state') == 'stable', true); + } + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($available); + } + if (!$available && !$channelinfo) { + // clean exit when not found, no error ! + $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.'; + $this->ui->outputData($data); + $this->config->set('default_channel', $channel); + return true; + } + if ($channelinfo) { + $data = array( + 'caption' => 'Matched packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'), + 'channel' => $channel + ); + } else { + $data = array( + 'caption' => 'Matched packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Stable/(Latest)', 'Local'), + 'channel' => $channel + ); + } + + if (!$available && $channelinfo) { + unset($data['headline']); + $data['data'] = 'No packages found that match pattern "' . $package . '".'; + $available = array(); + } + foreach ($available as $name => $info) { + $installed = $reg->packageInfo($name, null, $channel); + $desc = $info['summary']; + if (isset($params[$name])) + $desc .= "\n\n".$info['description']; + + if (!isset($info['stable']) || !$info['stable']) { + $version_remote = 'none'; + } else { + if ($info['unstable']) { + $version_remote = $info['unstable']; + } else { + $version_remote = $info['stable']; + } + $version_remote .= ' ('.$info['state'].')'; + } + $version = is_array($installed['version']) ? $installed['version']['release'] : + $installed['version']; + if ($channelinfo) { + $packageinfo = array( + $channel, + $name, + $version_remote, + $version, + $desc, + ); + } else { + $packageinfo = array( + $name, + $version_remote, + $version, + $desc, + ); + } + $data['data'][$info['category']][] = $packageinfo; + } + $this->ui->outputData($data, $command); + $this->config->set('default_channel', $channel); + return true; + } + + // }}} + function &getDownloader($options) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = &new PEAR_Downloader($this->ui, $options, $this->config); + return $a; + } + // {{{ doDownload() + + function doDownload($command, $options, $params) + { + // make certain that dependencies are ignored + $options['downloadonly'] = 1; + + // eliminate error messages for preferred_state-related errors + /* TODO: Should be an option, but until now download does respect + prefered state */ + /* $options['ignorepreferred_state'] = 1; */ + // eliminate error messages for preferred_state-related errors + + $downloader = &$this->getDownloader($options); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $e = $downloader->setDownloadDir(getcwd()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + return $this->raiseError('Current directory is not writeable, cannot download'); + } + $errors = array(); + $downloaded = array(); + $err = $downloader->download($params); + if (PEAR::isError($err)) { + return $err; + } + $errors = $downloader->getErrorMsgs(); + if (count($errors)) { + foreach ($errors as $error) { + $this->ui->outputData($error); + } + return $this->raiseError("$command failed"); + } + $downloaded = $downloader->getDownloadedPackages(); + foreach ($downloaded as $pkg) { + $this->ui->outputData("File $pkg[file] downloaded", $command); + } + return true; + } + + function downloadCallback($msg, $params = null) + { + if ($msg == 'done') { + $this->bytes_downloaded = $params; + } + } + + // }}} + // {{{ doListUpgrades() + + function doListUpgrades($command, $options, $params) + { + require_once 'PEAR/Common.php'; + if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) { + return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"'); + } + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + foreach ($reg->listChannels() as $channel) { + $inst = array_flip($reg->listPackages($channel)); + if (!count($inst)) { + continue; + } + if ($channel == '__uri') { + continue; + } + $this->config->set('default_channel', $channel); + if (empty($params[0])) { + $state = $this->config->get('preferred_state'); + } else { + $state = $params[0]; + } + $caption = $channel . ' Available Upgrades'; + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + if (empty($state) || $state == 'any') { + $state = false; + } else { + $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')'; + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg); + PEAR::staticPopErrorHandling(); + } else { + $remote = &$this->config->getRemote(); + $remote->pushErrorHandling(PEAR_ERROR_RETURN); + if (empty($state) || $state == 'any') { + $latest = $remote->call("package.listLatestReleases"); + } else { + $latest = $remote->call("package.listLatestReleases", $state); + $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')'; + } + $remote->popErrorHandling(); + } + if (PEAR::isError($latest)) { + $this->ui->outputData($latest->getMessage()); + continue; + } + $caption .= ':'; + if (PEAR::isError($latest)) { + $this->config->set('default_channel', $savechannel); + return $latest; + } + $data = array( + 'caption' => $caption, + 'border' => 1, + 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'), + 'channel' => $channel + ); + foreach ((array)$latest as $pkg => $info) { + $package = strtolower($pkg); + if (!isset($inst[$package])) { + // skip packages we don't have installed + continue; + } + extract($info); + $inst_version = $reg->packageInfo($package, 'version', $channel); + $inst_state = $reg->packageInfo($package, 'release_state', $channel); + if (version_compare("$version", "$inst_version", "le")) { + // installed version is up-to-date + continue; + } + if ($filesize >= 20480) { + $filesize += 1024 - ($filesize % 1024); + $fs = sprintf("%dkB", $filesize / 1024); + } elseif ($filesize > 0) { + $filesize += 103 - ($filesize % 103); + $fs = sprintf("%.1fkB", $filesize / 1024.0); + } else { + $fs = " -"; // XXX center instead + } + $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs); + } + if (isset($options['channelinfo'])) { + if (empty($data['data'])) { + unset($data['headline']); + if (count($inst) == 0) { + $data['data'] = '(no packages installed)'; + } else { + $data['data'] = '(no upgrades available)'; + } + } + $this->ui->outputData($data, $command); + } else { + if (empty($data['data'])) { + $this->ui->outputData('Channel ' . $channel . ': No upgrades available'); + } else { + $this->ui->outputData($data, $command); + } + } + } + $this->config->set('default_channel', $savechannel); + return true; + } + + // }}} + // {{{ doClearCache() + + function doClearCache($command, $options, $params) + { + $cache_dir = $this->config->get('cache_dir'); + $verbose = $this->config->get('verbose'); + $output = ''; + if (!file_exists($cache_dir) || !is_dir($cache_dir)) { + return $this->raiseError("$cache_dir does not exist or is not a directory"); + } + if (!($dp = @opendir($cache_dir))) { + return $this->raiseError("opendir($cache_dir) failed: $php_errormsg"); + } + if ($verbose >= 1) { + $output .= "reading directory $cache_dir\n"; + } + $num = 0; + while ($ent = readdir($dp)) { + if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}\\z/', $ent) || + preg_match('/rest.cache(file|id)\\z/', $ent)) { + $path = $cache_dir . DIRECTORY_SEPARATOR . $ent; + if (file_exists($path)) { + $ok = @unlink($path); + } else { + $ok = false; + $php_errormsg = ''; + } + if ($ok) { + if ($verbose >= 2) { + $output .= "deleted $path\n"; + } + $num++; + } elseif ($verbose >= 1) { + $output .= "failed to delete $path $php_errormsg\n"; + } + } + } + closedir($dp); + if ($verbose >= 1) { + $output .= "$num cache entries cleared\n"; + } + $this->ui->outputData(rtrim($output), $command); + return $num; + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Command/Remote.xml b/vas/rest/class/PEAR/Command/Remote.xml new file mode 100755 index 0000000000000000000000000000000000000000..d06f2227b2e48f01680baf945a860bcbd5b446de --- /dev/null +++ b/vas/rest/class/PEAR/Command/Remote.xml @@ -0,0 +1,108 @@ +<commands version="1.0"> + <remote-info> + <summary>Information About Remote Packages</summary> + <function>doRemoteInfo</function> + <shortcut>ri</shortcut> + <options /> + <doc><package> +Get details on a package from the server.</doc> + </remote-info> + <list-upgrades> + <summary>List Available Upgrades</summary> + <function>doListUpgrades</function> + <shortcut>lu</shortcut> + <options /> + <doc>[preferred_state] +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.) +or the state passed as the second parameter.</doc> + </list-upgrades> + <remote-list> + <summary>List Remote Packages</summary> + <function>doRemoteList</function> + <shortcut>rl</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>specify a channel other than the default channel</doc> + <arg>CHAN</arg> + </channel> + <channelinfo> + <shortopt>i</shortopt> + <doc>output fully channel-aware data, even on failure</doc> + </channelinfo> + </options> + <doc> +Lists the packages available on the configured server along with the +latest stable release of each package.</doc> + </remote-list> + <search> + <summary>Search remote package database</summary> + <function>doSearch</function> + <shortcut>sp</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>specify a channel other than the default channel</doc> + <arg>CHAN</arg> + </channel> + <allchannels> + <shortopt>a</shortopt> + <doc>search packages from all known channels</doc> + </allchannels> + <channelinfo> + <shortopt>i</shortopt> + <doc>output fully channel-aware data, even on failure</doc> + </channelinfo> + </options> + <doc>[packagename] [packageinfo] +Lists all packages which match the search parameters. The first +parameter is a fragment of a packagename. The default channel +will be used unless explicitly overridden. The second parameter +will be used to match any portion of the summary/description</doc> + </search> + <list-all> + <summary>List All Packages</summary> + <function>doListAll</function> + <shortcut>la</shortcut> + <options> + <channel> + <shortopt>c</shortopt> + <doc>specify a channel other than the default channel</doc> + <arg>CHAN</arg> + </channel> + <channelinfo> + <shortopt>i</shortopt> + <doc>output fully channel-aware data, even on failure</doc> + </channelinfo> + </options> + <doc> +Lists the packages available on the configured server along with the +latest stable release of each package.</doc> + </list-all> + <download> + <summary>Download Package</summary> + <function>doDownload</function> + <shortcut>d</shortcut> + <options> + <nocompress> + <shortopt>Z</shortopt> + <doc>download an uncompressed (.tar) file</doc> + </nocompress> + </options> + <doc><package>... +Download package tarballs. The files will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.</doc> + </download> + <clear-cache> + <summary>Clear Web Services Cache</summary> + <function>doClearCache</function> + <shortcut>cc</shortcut> + <options /> + <doc> +Clear the XML-RPC/REST cache. See also the cache_ttl configuration +parameter. +</doc> + </clear-cache> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Test.php b/vas/rest/class/PEAR/Command/Test.php new file mode 100755 index 0000000000000000000000000000000000000000..4cf40f61c2cc30cb4e98dfcab64e917d053f4861 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Test.php @@ -0,0 +1,345 @@ +<?php +/** + * PEAR_Command_Test (run-tests) + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Test.php,v 1.27 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ + +class PEAR_Command_Test extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'run-tests' => array( + 'summary' => 'Run Regression Tests', + 'function' => 'doRunTests', + 'shortcut' => 'rt', + 'options' => array( + 'recur' => array( + 'shortopt' => 'r', + 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', + ), + 'ini' => array( + 'shortopt' => 'i', + 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', + 'arg' => 'SETTINGS' + ), + 'realtimelog' => array( + 'shortopt' => 'l', + 'doc' => 'Log test runs/results as they are run', + ), + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Only display detail for failed tests', + ), + 'simple' => array( + 'shortopt' => 's', + 'doc' => 'Display simple output for all tests', + ), + 'package' => array( + 'shortopt' => 'p', + 'doc' => 'Treat parameters as installed packages from which to run tests', + ), + 'phpunit' => array( + 'shortopt' => 'u', + 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests +If none is found, all .phpt tests will be tried instead.', + ), + 'tapoutput' => array( + 'shortopt' => 't', + 'doc' => 'Output run-tests.log in TAP-compliant format', + ), + 'cgi' => array( + 'shortopt' => 'c', + 'doc' => 'CGI php executable (needed for tests with POST/GET section)', + 'arg' => 'PHPCGI', + ), + 'coverage' => array( + 'shortopt' => 'x', + 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)', + ), + ), + 'doc' => '[testfile|dir ...] +Run regression tests with PHP\'s regression testing script (run-tests.php).', + ), + ); + + var $output; + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Test constructor. + * + * @access public + */ + function PEAR_Command_Test(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + // {{{ doRunTests() + + function doRunTests($command, $options, $params) + { + if (isset($options['phpunit']) && isset($options['tapoutput'])) { + return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time'); + } + require_once 'PEAR/Common.php'; + require_once 'System.php'; + $log = new PEAR_Common; + $log->ui = &$this->ui; // slightly hacky, but it will work + $tests = array(); + $depth = isset($options['recur']) ? 4 : 1; + + if (!count($params)) { + $params[] = '.'; + } + if (isset($options['package'])) { + $oldparams = $params; + $params = array(); + $reg = &$this->config->getRegistry(); + foreach ($oldparams as $param) { + $pname = $reg->parsePackageName($param, $this->config->get('default_channel')); + if (PEAR::isError($pname)) { + return $this->raiseError($pname); + } + + $package = &$reg->getPackage($pname['package'], $pname['channel']); + if (!$package) { + return PEAR::raiseError('Unknown package "' . + $reg->parsedPackageNameToString($pname) . '"'); + } + + $filelist = $package->getFilelist(); + foreach ($filelist as $name => $atts) { + if (isset($atts['role']) && $atts['role'] != 'test') { + continue; + } + + if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) { + $params[] = $atts['installed_as']; + continue; + } elseif (!preg_match('/\.phpt\\z/', $name)) { + continue; + } + $params[] = $atts['installed_as']; + } + } + } + + foreach ($params as $p) { + if (is_dir($p)) { + if (isset($options['phpunit'])) { + $dir = System::find(array($p, '-type', 'f', + '-maxdepth', $depth, + '-name', 'AllTests.php')); + if (count($dir)) { + foreach ($dir as $p) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + } + continue; + } + $dir = System::find(array($p, '-type', 'f', + '-maxdepth', $depth, + '-name', '*.phpt')); + $tests = array_merge($tests, $dir); + } else { + if (isset($options['phpunit'])) { + if (preg_match('/AllTests\.php\\z/i', $p)) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + continue; + } + + if (file_exists($p) && preg_match('/\.phpt$/', $p)) { + $tests[] = $p; + continue; + } + + if (!preg_match('/\.phpt\\z/', $p)) { + $p .= '.phpt'; + } + $dir = System::find(array(dirname($p), '-type', 'f', + '-maxdepth', $depth, + '-name', $p)); + $tests = array_merge($tests, $dir); + } + } + + $ini_settings = ''; + if (isset($options['ini'])) { + $ini_settings .= $options['ini']; + } + + if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { + $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; + } + + if ($ini_settings) { + $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); + } + $skipped = $passed = $failed = array(); + $tests_count = count($tests); + $this->ui->outputData('Running ' . $tests_count . ' tests', $command); + $start = time(); + if (isset($options['realtimelog']) && file_exists('run-tests.log')) { + unlink('run-tests.log'); + } + + if (isset($options['tapoutput'])) { + $tap = '1..' . $tests_count . "\n"; + } + + require_once 'PEAR/RunTest.php'; + $run = new PEAR_RunTest($log, $options); + $run->tests_count = $tests_count; + + if (isset($options['coverage']) && extension_loaded('xdebug')){ + $run->xdebug_loaded = true; + } else { + $run->xdebug_loaded = false; + } + + $j = $i = 1; + foreach ($tests as $t) { + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "Running test [$i / $tests_count] $t..."); + fclose($fp); + } + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (isset($options['phpunit'])) { + $result = $run->runPHPUnit($t, $ini_settings); + } else { + $result = $run->run($t, $ini_settings, $j); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($result)) { + $this->ui->log($result->getMessage()); + continue; + } + + if (isset($options['tapoutput'])) { + $tap .= $result[0] . ' ' . $i . $result[1] . "\n"; + continue; + } + + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "$result\n"); + fclose($fp); + } + } + + if ($result == 'FAILED') { + $failed[] = $t; + } + if ($result == 'PASSED') { + $passed[] = $t; + } + if ($result == 'SKIPPED') { + $skipped[] = $t; + } + + $j++; + } + + $total = date('i:s', time() - $start); + if (isset($options['tapoutput'])) { + $fp = @fopen('run-tests.log', 'w'); + if ($fp) { + fwrite($fp, $tap, strlen($tap)); + fclose($fp); + $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') . + '"', $command); + } + } else { + if (count($failed)) { + $output = "TOTAL TIME: $total\n"; + $output .= count($passed) . " PASSED TESTS\n"; + $output .= count($skipped) . " SKIPPED TESTS\n"; + $output .= count($failed) . " FAILED TESTS:\n"; + foreach ($failed as $failure) { + $output .= $failure . "\n"; + } + + $mode = isset($options['realtimelog']) ? 'a' : 'w'; + $fp = @fopen('run-tests.log', $mode); + + if ($fp) { + fwrite($fp, $output, strlen($output)); + fclose($fp); + $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); + } + } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) { + @unlink('run-tests.log'); + } + } + $this->ui->outputData('TOTAL TIME: ' . $total); + $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); + $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); + if (count($failed)) { + $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); + foreach ($failed as $failure) { + $this->ui->outputData($failure, $command); + } + } + + return true; + } + // }}} +} \ No newline at end of file diff --git a/vas/rest/class/PEAR/Command/Test.xml b/vas/rest/class/PEAR/Command/Test.xml new file mode 100755 index 0000000000000000000000000000000000000000..68e8f5381381b817806e5227d763e8e48eedfa63 --- /dev/null +++ b/vas/rest/class/PEAR/Command/Test.xml @@ -0,0 +1,54 @@ +<commands version="1.0"> + <run-tests> + <summary>Run Regression Tests</summary> + <function>doRunTests</function> + <shortcut>rt</shortcut> + <options> + <recur> + <shortopt>r</shortopt> + <doc>Run tests in child directories, recursively. 4 dirs deep maximum</doc> + </recur> + <ini> + <shortopt>i</shortopt> + <doc>actual string of settings to pass to php in format " -d setting=blah"</doc> + <arg>SETTINGS</arg> + </ini> + <realtimelog> + <shortopt>l</shortopt> + <doc>Log test runs/results as they are run</doc> + </realtimelog> + <quiet> + <shortopt>q</shortopt> + <doc>Only display detail for failed tests</doc> + </quiet> + <simple> + <shortopt>s</shortopt> + <doc>Display simple output for all tests</doc> + </simple> + <package> + <shortopt>p</shortopt> + <doc>Treat parameters as installed packages from which to run tests</doc> + </package> + <phpunit> + <shortopt>u</shortopt> + <doc>Search parameters for AllTests.php, and use that to run phpunit-based tests. +If none is found, all .phpt tests will be tried instead.</doc> + </phpunit> + <tapoutput> + <shortopt>t</shortopt> + <doc>Output run-tests.log in TAP-compliant format</doc> + </tapoutput> + <cgi> + <shortopt>c</shortopt> + <doc>CGI php executable (needed for tests with POST/GET section)</doc> + <arg>PHPCGI</arg> + </cgi> + <coverage> + <shortopt>x</shortopt> + <doc>Generate a code coverage report (requires Xdebug 2.0.0+)</doc> + </coverage> + </options> + <doc>[testfile|dir ...] +Run regression tests with PHP's regression testing script (run-tests.php).</doc> + </run-tests> +</commands> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Common.php b/vas/rest/class/PEAR/Common.php new file mode 100755 index 0000000000000000000000000000000000000000..73ec384f365d8e3b9cbcc62490190df423821e55 --- /dev/null +++ b/vas/rest/class/PEAR/Common.php @@ -0,0 +1,1126 @@ +<?php +/** + * PEAR_Common, the base class for the PEAR Installer + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Common.php,v 1.160 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1.0 + * @deprecated File deprecated since Release 1.4.0a1 + */ + +/** + * Include error handling + */ +require_once 'PEAR.php'; + +// {{{ constants and globals + +/** + * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + */ +define('PEAR_COMMON_ERROR_INVALIDPHP', 1); +define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); +define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); + +// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 +define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); +define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); + +// XXX far from perfect :-) +define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . + ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . + '\\z/'); + +define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); +define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); + +// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED +define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); +define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); + +define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); +define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); + +define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); + +/** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); + +/** + * Valid maintainer roles + * @var array + */ +$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); + +/** + * Valid release states + * @var array + */ +$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); + +/** + * Valid dependency types + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); + +/** + * Valid dependency relations + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); + +/** + * Valid file roles + * @var array + */ +$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); + +/** + * Valid replacement types + * @var array + */ +$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); + +// }}} + +/** + * Class providing common functionality for PEAR administration classes. + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + * @deprecated This class will disappear, and its components will be spread + * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 + */ +class PEAR_Common extends PEAR +{ + // {{{ properties + + /** stack of elements, gives some sort of XML context */ + var $element_stack = array(); + + /** name of currently parsed XML element */ + var $current_element; + + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); + + /** assoc with information about a package */ + var $pkginfo = array(); + + /** + * User Interface object (PEAR_Frontend_* class). If null, + * the log() method uses print. + * @var object + */ + var $ui = null; + + /** + * Configuration object (PEAR_Config). + * @var PEAR_Config + */ + var $config = null; + + var $current_path = null; + + /** + * PEAR_SourceAnalyzer instance + * @var object + */ + var $source_analyzer = null; + /** + * Flag variable used to mark a valid package file + * @var boolean + * @access private + */ + var $_validPackageFile; + + // }}} + + // {{{ constructor + + /** + * PEAR_Common constructor + * + * @access public + */ + function PEAR_Common() + { + parent::PEAR(); + $this->config = &PEAR_Config::singleton(); + $this->debug = $this->config->get('verbose'); + } + + // }}} + // {{{ destructor + + /** + * PEAR_Common destructor + * + * @access private + */ + function _PEAR_Common() + { + // doesn't work due to bug #14744 + //$tempfiles = $this->_tempfiles; + $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; + while ($file = array_shift($tempfiles)) { + if (@is_dir($file)) { + if (!class_exists('System')) { + require_once 'System.php'; + } + System::rm(array('-rf', $file)); + } elseif (file_exists($file)) { + unlink($file); + } + } + } + + // }}} + // {{{ addTempFile() + + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * + * @return void + * + * @access public + */ + function addTempFile($file) + { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; + } + PEAR_Frontend::addTempFile($file); + } + + // }}} + // {{{ mkDirHier() + + /** + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string $dir directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ + function mkDirHier($dir) + { + $this->log(2, "+ create dir $dir"); + if (!class_exists('System')) { + require_once 'System.php'; + } + return System::mkDir(array('-p', $dir)); + } + + // }}} + // {{{ log() + + /** + * Logging method. + * + * @param int $level log level (0 is quiet, higher is noisier) + * @param string $msg message to write to the log + * + * @return void + * + * @access public + * @static + */ + function log($level, $msg, $append_crlf = true) + { + if ($this->debug >= $level) { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; + } + $ui = &PEAR_Frontend::singleton(); + if (is_a($ui, 'PEAR_Frontend')) { + $ui->log($msg, $append_crlf); + } else { + print "$msg\n"; + } + } + } + + // }}} + // {{{ mkTempDir() + + /** + * Create and register a temporary directory. + * + * @param string $tmpdir (optional) Directory to use as tmpdir. + * Will use system defaults (for example + * /tmp or c:\windows\temp) if not specified + * + * @return string name of created directory + * + * @access public + */ + function mkTempDir($tmpdir = '') + { + if ($tmpdir) { + $topt = array('-t', $tmpdir); + } else { + $topt = array(); + } + $topt = array_merge($topt, array('-d', 'pear')); + if (!class_exists('System')) { + require_once 'System.php'; + } + if (!$tmpdir = System::mktemp($topt)) { + return false; + } + $this->addTempFile($tmpdir); + return $tmpdir; + } + + // }}} + // {{{ setFrontendObject() + + /** + * Set object that represents the frontend to be used. + * + * @param object Reference of the frontend object + * @return void + * @access public + */ + function setFrontendObject(&$ui) + { + $this->ui = &$ui; + } + + // }}} + + // {{{ infoFromTgzFile() + + /** + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string $file name of .tgz file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromTgzFile() instead + * + */ + function infoFromTgzFile($file) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + return $pf; + } + return $this->_postProcessValidPackagexml($pf); + } + + // }}} + // {{{ infoFromDescriptionFile() + + /** + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string $descfile name of package xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromPackageFile() instead + * + */ + function infoFromDescriptionFile($descfile) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + return $pf; + } + return $this->_postProcessValidPackagexml($pf); + } + + // }}} + // {{{ infoFromString() + + /** + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string $data contents of package.xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromXmlstring() instead + * + */ + function infoFromString($data) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + return $pf; + } + return $this->_postProcessValidPackagexml($pf); + } + // }}} + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return array + */ + function _postProcessValidPackagexml(&$pf) + { + if (is_a($pf, 'PEAR_PackageFile_v2')) { + // sort of make this into a package.xml 1.0-style array + // changelog is not converted to old format. + $arr = $pf->toArray(true); + $arr = array_merge($arr, $arr['old']); + unset($arr['old']); + unset($arr['xsdversion']); + unset($arr['contents']); + unset($arr['compatible']); + unset($arr['channel']); + unset($arr['uri']); + unset($arr['dependencies']); + unset($arr['phprelease']); + unset($arr['extsrcrelease']); + unset($arr['zendextsrcrelease']); + unset($arr['extbinrelease']); + unset($arr['zendextbinrelease']); + unset($arr['bundle']); + unset($arr['lead']); + unset($arr['developer']); + unset($arr['helper']); + unset($arr['contributor']); + $arr['filelist'] = $pf->getFilelist(); + $this->pkginfo = $arr; + return $arr; + } else { + $this->pkginfo = $pf->toArray(); + return $this->pkginfo; + } + } + // {{{ infoFromAny() + + /** + * Returns package information from different sources + * + * This method is able to extract information about a package + * from a .tgz archive or from a XML package definition file. + * + * @access public + * @param string Filename of the source ('package.xml', '<package>.tgz') + * @return string + * @deprecated use PEAR_PackageFile->fromAnyFile() instead + */ + function infoFromAny($info) + { + if (is_string($info) && file_exists($info)) { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + return $pf; + } + return $this->_postProcessValidPackagexml($pf); + } + return $info; + } + + // }}} + // {{{ xmlFromInfo() + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array $pkginfo package info + * + * @return string XML data + * + * @access public + * @deprecated use a PEAR_PackageFile_v* object's generator instead + */ + function xmlFromInfo($pkginfo) + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + $pf = &$packagefile->fromArray($pkginfo); + $gen = &$pf->getDefaultGenerator(); + return $gen->toXml(PEAR_VALIDATE_PACKAGING); + } + + // }}} + // {{{ validatePackageInfo() + + /** + * Validate XML package definition file. + * + * @param string $info Filename of the package archive or of the + * package definition file + * @param array $errors Array that will contain the errors + * @param array $warnings Array that will contain the warnings + * @param string $dir_prefix (optional) directory where source files + * may be found, or empty if they are not available + * @access public + * @return boolean + * @deprecated use the validation of PEAR_PackageFile objects + */ + function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (strpos($info, '<?xml') !== false) { + $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); + } else { + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + if ($error['level'] == 'error') { + $errors[] = $error['message']; + } else { + $warnings[] = $error['message']; + } + } + } + return false; + } + return true; + } + + // }}} + // {{{ buildProvidesArray() + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access public + * + */ + function buildProvidesArray($srcinfo) + { + $file = basename($srcinfo['source_file']); + $pn = ''; + if (isset($this->_packageName)) { + $pn = $this->_packageName; + } + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->pkginfo['provides'][$key])) { + continue; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->pkginfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->pkginfo['provides'][$key])) { + continue; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { + continue; + } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + // }}} + // {{{ analyzeSourceCode() + + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access public + */ + 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 != '"') { + continue; + } else { + $inquote = false; + continue; + } + } + switch ($token) { + case T_WHITESPACE: + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + $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)) { + PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", + PEAR_COMMON_ERROR_INVALIDPHP); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + PEAR::raiseError('Error: PHP5 token encountered in ' . $file . + 'packaging should be done in PHP 5'); + return false; + } + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + $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)) { + 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, + ); + } + + // }}} + // {{{ betterStates() + + /** + * 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); + } + + // }}} + // {{{ detectDependencies() + + function detectDependencies($any, $status_callback = null) + { + if (!function_exists("token_get_all")) { + return false; + } + if (PEAR::isError($info = $this->infoFromAny($any))) { + return $this->raiseError($info); + } + if (!is_array($info)) { + return false; + } + $deps = array(); + $used_c = $decl_c = $decl_f = $decl_m = array(); + foreach ($info['filelist'] as $file => $fa) { + $tmp = $this->analyzeSourceCode($file); + $used_c = @array_merge($used_c, $tmp['used_classes']); + $decl_c = @array_merge($decl_c, $tmp['declared_classes']); + $decl_f = @array_merge($decl_f, $tmp['declared_functions']); + $decl_m = @array_merge($decl_m, $tmp['declared_methods']); + $inheri = @array_merge($inheri, $tmp['inheritance']); + } + $used_c = array_unique($used_c); + $decl_c = array_unique($decl_c); + $undecl_c = array_diff($used_c, $decl_c); + return array('used_classes' => $used_c, + 'declared_classes' => $decl_c, + 'declared_methods' => $decl_m, + 'declared_functions' => $decl_f, + 'undeclared_classes' => $undecl_c, + 'inheritance' => $inheri, + ); + } + + // }}} + // {{{ getUserRoles() + + /** + * Get the valid roles for a PEAR package maintainer + * + * @return array + * @static + */ + function getUserRoles() + { + return $GLOBALS['_PEAR_Common_maintainer_roles']; + } + + // }}} + // {{{ getReleaseStates() + + /** + * Get the valid package release states of packages + * + * @return array + * @static + */ + function getReleaseStates() + { + return $GLOBALS['_PEAR_Common_release_states']; + } + + // }}} + // {{{ getDependencyTypes() + + /** + * Get the implemented dependency types (php, ext, pkg etc.) + * + * @return array + * @static + */ + function getDependencyTypes() + { + return $GLOBALS['_PEAR_Common_dependency_types']; + } + + // }}} + // {{{ getDependencyRelations() + + /** + * Get the implemented dependency relations (has, lt, ge etc.) + * + * @return array + * @static + */ + function getDependencyRelations() + { + return $GLOBALS['_PEAR_Common_dependency_relations']; + } + + // }}} + // {{{ getFileRoles() + + /** + * Get the implemented file roles + * + * @return array + * @static + */ + function getFileRoles() + { + return $GLOBALS['_PEAR_Common_file_roles']; + } + + // }}} + // {{{ getReplacementTypes() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getReplacementTypes() + { + return $GLOBALS['_PEAR_Common_replacement_types']; + } + + // }}} + // {{{ getProvideTypes() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getProvideTypes() + { + return $GLOBALS['_PEAR_Common_provide_types']; + } + + // }}} + // {{{ getScriptPhases() + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getScriptPhases() + { + return $GLOBALS['_PEAR_Common_script_phases']; + } + + // }}} + // {{{ validPackageName() + + /** + * Test whether a string contains a valid package name. + * + * @param string $name the package name to test + * + * @return bool + * + * @access public + */ + function validPackageName($name) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); + } + + + // }}} + // {{{ validPackageVersion() + + /** + * Test whether a string contains a valid package version. + * + * @param string $ver the package version to test + * + * @return bool + * + * @access public + */ + function validPackageVersion($ver) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + + // }}} + + // {{{ downloadHttp() + + /** + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir (optional) directory to save file in + * @param mixed $callback (optional) function/method to call for status + * updates + * + * @return string Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). + * + * @access public + * @deprecated in favor of PEAR_Downloader::downloadHttp() + */ + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); + } + + // }}} + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($ipath as $include) { + $test = realpath($include . DIRECTORY_SEPARATOR . $path); + if (file_exists($test) && is_readable($test)) { + return true; + } + } + return false; + } +} +require_once 'PEAR/Config.php'; +require_once 'PEAR/PackageFile.php'; +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Config.php b/vas/rest/class/PEAR/Config.php new file mode 100755 index 0000000000000000000000000000000000000000..fe37037eca1cd6ca5b46cfdafa71a219fc025ef5 --- /dev/null +++ b/vas/rest/class/PEAR/Config.php @@ -0,0 +1,2163 @@ +<?php +/** + * PEAR_Config, customized configuration handling for the PEAR Installer + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Config.php,v 1.146 2008/05/14 04:16:08 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Required for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Registry.php'; +require_once 'PEAR/Installer/Role.php'; +require_once 'System.php'; +require_once 'PEAR/Remote.php'; + +/** + * Last created PEAR_Config instance. + * @var object + */ +$GLOBALS['_PEAR_Config_instance'] = null; +if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { + $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; +} else { + $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; +} + +// Below we define constants with default values for all configuration +// parameters except username/password. All of them can have their +// defaults set through environment variables. The reason we use the +// PHP_ prefix is for some security, PHP protects environment +// variables starting with PHP_*. + +// default channel and preferred mirror is based on whether we are invoked through +// the "pear" or the "pecl" command + +if (!defined('PEAR_RUNTYPE') || PEAR_RUNTYPE == 'pear') { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); +} else { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); +} + +if (getenv('PHP_PEAR_SYSCONF_DIR')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); +} elseif (getenv('SystemRoot')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); +} else { + define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); +} + +// Default for master_server +if (getenv('PHP_PEAR_MASTER_SERVER')) { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); +} else { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); +} + +// Default for http_proxy +if (getenv('PHP_PEAR_HTTP_PROXY')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); +} elseif (getenv('http_proxy')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); +} else { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); +} + +// Default for php_dir +if (getenv('PHP_PEAR_INSTALL_DIR')) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); +} else { + if (file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', + $PEAR_INSTALL_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } +} + +// Default for ext_dir +if (getenv('PHP_PEAR_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); +} else { + if (ini_get('extension_dir')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); + } elseif (defined('PEAR_EXTENSION_DIR') && + file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); + } elseif (defined('PHP_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); + } +} + +// Default for doc_dir +if (getenv('PHP_PEAR_DOC_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); +} + +// Default for bin_dir +if (getenv('PHP_PEAR_BIN_DIR')) { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); +} + +// Default for data_dir +if (getenv('PHP_PEAR_DATA_DIR')) { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); +} + +// Default for cfg_dir +if (getenv('PHP_PEAR_CFG_DIR')) { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); +} + +// Default for www_dir +if (getenv('PHP_PEAR_WWW_DIR')) { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); +} + +// Default for test_dir +if (getenv('PHP_PEAR_TEST_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); +} + +// Default for temp_dir +if (getenv('PHP_PEAR_TEMP_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'temp'); +} + +// Default for cache_dir +if (getenv('PHP_PEAR_CACHE_DIR')) { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'cache'); +} + +// Default for download_dir +if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'download'); +} + +// Default for php_bin +if (getenv('PHP_PEAR_PHP_BIN')) { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. + DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); +} + +// Default for verbose +if (getenv('PHP_PEAR_VERBOSE')) { + define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); +} else { + define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); +} + +// Default for preferred_state +if (getenv('PHP_PEAR_PREFERRED_STATE')) { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); +} else { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); +} + +// Default for umask +if (getenv('PHP_PEAR_UMASK')) { + define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); +} else { + define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); +} + +// Default for cache_ttl +if (getenv('PHP_PEAR_CACHE_TTL')) { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); +} + +// Default for sig_type +if (getenv('PHP_PEAR_SIG_TYPE')) { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); +} + +// Default for sig_bin +if (getenv('PHP_PEAR_SIG_BIN')) { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', + System::which( + 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); +} + +// Default for sig_keydir +if (getenv('PHP_PEAR_SIG_KEYDIR')) { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', + PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); +} + +/** + * This is a class for storing configuration data, keeping track of + * which are system-defined, user-defined or defaulted. + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Config extends PEAR +{ + // {{{ properties + + /** + * Array of config files used. + * + * @var array layer => config file + */ + var $files = array( + 'system' => '', + 'user' => '', + ); + + var $layers = array(); + + /** + * Configuration data, two-dimensional array where the first + * dimension is the config layer ('user', 'system' and 'default'), + * and the second dimension is keyname => value. + * + * The order in the first dimension is important! Earlier + * layers will shadow later ones when a config value is + * requested (if a 'user' value exists, it will be returned first, + * then 'system' and finally 'default'). + * + * @var array layer => array(keyname => value, ...) + */ + var $configuration = array( + 'user' => array(), + 'system' => array(), + 'default' => array(), + ); + + /** + * Configuration values that can be set for a channel + * + * All other configuration values can only have a global value + * @var array + * @access private + */ + var $_channelConfigInfo = array( + 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', + 'test_dir', 'www_dir', 'php_bin', 'username', 'password', 'verbose', + 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' + ); + + /** + * Channels that can be accessed + * @see setChannels() + * @var array + * @access private + */ + var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); + + /** + * This variable is used to control the directory values returned + * @see setInstallRoot(); + * @var string|false + * @access private + */ + var $_installRoot = false; + + /** + * If requested, this will always refer to the registry + * contained in php_dir + * @var PEAR_Registry + */ + var $_registry = array(); + + /** + * @var array + * @access private + */ + var $_regInitialized = array(); + + /** + * @var bool + * @access private + */ + var $_noRegistry = false; + + /** + * amount of errors found while parsing config + * @var integer + * @access private + */ + var $_errorsFound = 0; + var $_lastError = null; + + /** + * Information about the configuration data. Stores the type, + * default value and a documentation string for each configuration + * value. + * + * @var array layer => array(infotype => value, ...) + */ + var $configuration_info = array( + // Channels/Internet Access + 'default_channel' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default channel to use for all non explicit commands', + 'prompt' => 'Default Channel', + 'group' => 'Internet Access', + ), + 'preferred_mirror' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default server or mirror to use for channel actions', + 'prompt' => 'Default Channel Mirror', + 'group' => 'Internet Access', + ), + 'remote_config' => array( + 'type' => 'password', + 'default' => '', + 'doc' => 'ftp url of remote configuration file to use for synchronized install', + 'prompt' => 'Remote Configuration File', + 'group' => 'Internet Access', + ), + 'auto_discover' => array( + 'type' => 'integer', + 'default' => 0, + 'doc' => 'whether to automatically discover new channels', + 'prompt' => 'Auto-discover new Channels', + 'group' => 'Internet Access', + ), + // Internet Access + 'master_server' => array( + 'type' => 'string', + 'default' => 'pear.php.net', + 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', + 'prompt' => 'PEAR server [DEPRECATED]', + 'group' => 'Internet Access', + ), + 'http_proxy' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, + 'doc' => 'HTTP proxy (host:port) to use when downloading packages', + 'prompt' => 'HTTP Proxy Server Address', + 'group' => 'Internet Access', + ), + // File Locations + 'php_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, + 'doc' => 'directory where .php files are installed', + 'prompt' => 'PEAR directory', + 'group' => 'File Locations', + ), + 'ext_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, + 'doc' => 'directory where loadable extensions are installed', + 'prompt' => 'PHP extension directory', + 'group' => 'File Locations', + ), + 'doc_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, + 'doc' => 'directory where documentation is installed', + 'prompt' => 'PEAR documentation directory', + 'group' => 'File Locations', + ), + 'bin_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, + 'doc' => 'directory where executables are installed', + 'prompt' => 'PEAR executables directory', + 'group' => 'File Locations', + ), + 'data_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, + 'doc' => 'directory where data files are installed', + 'prompt' => 'PEAR data directory', + 'group' => 'File Locations (Advanced)', + ), + 'cfg_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, + 'doc' => 'directory where modifiable configuration files are installed', + 'prompt' => 'PEAR configuration file directory', + 'group' => 'File Locations (Advanced)', + ), + 'www_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, + 'doc' => 'directory where www frontend files (html/js) are installed', + 'prompt' => 'PEAR www files directory', + 'group' => 'File Locations (Advanced)', + ), + 'test_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, + 'doc' => 'directory where regression tests are installed', + 'prompt' => 'PEAR test directory', + 'group' => 'File Locations (Advanced)', + ), + 'cache_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, + 'doc' => 'directory which is used for XMLRPC cache', + 'prompt' => 'PEAR Installer cache directory', + 'group' => 'File Locations (Advanced)', + ), + 'temp_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, + 'doc' => 'directory which is used for all temp files', + 'prompt' => 'PEAR Installer temp directory', + 'group' => 'File Locations (Advanced)', + ), + 'download_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, + 'doc' => 'directory which is used for all downloaded files', + 'prompt' => 'PEAR Installer download directory', + 'group' => 'File Locations (Advanced)', + ), + 'php_bin' => array( + 'type' => 'file', + 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, + 'doc' => 'PHP CLI/CGI binary for executing scripts', + 'prompt' => 'PHP CLI/CGI binary', + 'group' => 'File Locations (Advanced)', + ), + 'php_ini' => array( + 'type' => 'file', + 'default' => '', + 'doc' => 'location of php.ini in which to enable PECL extensions on install', + 'prompt' => 'php.ini location', + 'group' => 'File Locations (Advanced)', + ), + // Maintainers + 'username' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '(maintainers) your PEAR account name', + 'prompt' => 'PEAR username (for maintainers)', + 'group' => 'Maintainers', + ), + 'password' => array( + 'type' => 'password', + 'default' => '', + 'doc' => '(maintainers) your PEAR account password', + 'prompt' => 'PEAR password (for maintainers)', + 'group' => 'Maintainers', + ), + // Advanced + 'verbose' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, + 'doc' => 'verbosity level +0: really quiet +1: somewhat quiet +2: verbose +3: debug', + 'prompt' => 'Debug Log Level', + 'group' => 'Advanced', + ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, + 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot'), + 'prompt' => 'Preferred Package State', + 'group' => 'Advanced', + ), + 'umask' => array( + 'type' => 'mask', + 'default' => PEAR_CONFIG_DEFAULT_UMASK, + 'doc' => 'umask used when creating files (Unix-like systems only)', + 'prompt' => 'Unix file mask', + 'group' => 'Advanced', + ), + 'cache_ttl' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, + 'doc' => 'amount of secs where the local cache is used and not updated', + 'prompt' => 'Cache TimeToLive', + 'group' => 'Advanced', + ), + 'sig_type' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, + 'doc' => 'which package signature mechanism to use', + 'valid_set' => array('gpg'), + 'prompt' => 'Package Signature Type', + 'group' => 'Maintainers', + ), + 'sig_bin' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Handling Program', + 'group' => 'Maintainers', + ), + 'sig_keyid' => array( + 'type' => 'string', + 'default' => '', + 'doc' => 'which key to use for signing with', + 'prompt' => 'Signature Key Id', + 'group' => 'Maintainers', + ), + 'sig_keydir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, + 'doc' => 'directory where signature keys are located', + 'prompt' => 'Signature Key Directory', + 'group' => 'Maintainers', + ), + // __channels is reserved - used for channel-specific configuration + ); + + // }}} + + // {{{ PEAR_Config([file], [defaults_file]) + + /** + * Constructor. + * + * @param string file to read user-defined options from + * @param string file to read system-wide defaults from + * @param bool determines whether a registry object "follows" + * the value of php_dir (is automatically created + * and moved when php_dir is changed) + * @param bool if true, fails if configuration files cannot be loaded + * + * @access public + * + * @see PEAR_Config::singleton + */ + function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, + $strict = true) + { + $this->PEAR(); + PEAR_Installer_Role::initializeConfig($this); + $sl = DIRECTORY_SEPARATOR; + if (empty($user_file)) { + if (OS_WINDOWS) { + $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; + } else { + $user_file = getenv('HOME') . $sl . '.pearrc'; + } + } + if (empty($system_file)) { + if (OS_WINDOWS) { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'; + } else { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'; + } + } + + $this->layers = array_keys($this->configuration); + $this->files['user'] = $user_file; + $this->files['system'] = $system_file; + if ($user_file && file_exists($user_file)) { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $this->readConfigFile($user_file, 'user', $strict); + $this->popErrorHandling(); + if ($this->_errorsFound > 0) { + return; + } + } + + if ($system_file && file_exists($system_file)) { + $this->mergeConfigFile($system_file, false, 'system', $strict); + if ($this->_errorsFound > 0) { + return; + } + + } + + if (!$ftp_file) { + $ftp_file = $this->get('remote_config'); + } + + if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { + $this->readFTPConfigFile($ftp_file); + } + + foreach ($this->configuration_info as $key => $info) { + $this->configuration['default'][$key] = $info['default']; + } + + $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); + $this->_registry['default']->setConfig($this, false); + $this->_regInitialized['default'] = false; + //$GLOBALS['_PEAR_Config_instance'] = &$this; + } + + // }}} + /** + * Return the default locations of user and system configuration files + * @static + */ + function getDefaultConfigFiles() + { + $sl = DIRECTORY_SEPARATOR; + if (OS_WINDOWS) { + return array( + 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' + ); + } else { + return array( + 'user' => getenv('HOME') . $sl . '.pearrc', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' + ); + } + } + // {{{ singleton([file], [defaults_file]) + + /** + * Static singleton method. If you want to keep only one instance + * of this class in use, this method will give you a reference to + * the last created PEAR_Config object if one exists, or create a + * new object. + * + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from + * + * @return object an existing or new PEAR_Config instance + * + * @access public + * + * @see PEAR_Config::PEAR_Config + */ + function &singleton($user_file = '', $system_file = '', $strict = true) + { + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; + } + + $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); + if ($t_conf->_errorsFound > 0) { + return $t_conf->lastError; + } + + $GLOBALS['_PEAR_Config_instance'] = &$t_conf; + return $GLOBALS['_PEAR_Config_instance']; + } + + // }}} + // {{{ validConfiguration() + + /** + * Determine whether any configuration files have been detected, and whether a + * registry object can be retrieved from this configuration. + * @return bool + * @since PEAR 1.4.0a1 + */ + function validConfiguration() + { + if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { + return true; + } + return false; + } + + // }}} + // {{{ readConfigFile([file], [layer]) + + /** + * Reads configuration data from a file. All existing values in + * the config layer are discarded and replaced with data from the + * file. + * @param string file to read from, if NULL or not specified, the + * last-used file for the same layer (second param) is used + * @param string config layer to insert data into ('user' or 'system') + * @return bool TRUE on success or a PEAR error on failure + */ + function readConfigFile($file = null, $layer = 'user', $strict = true) + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } + + if ($file === null) { + $file = $this->files[$layer]; + } + + $data = $this->_readConfigDataFrom($file); + + if (PEAR::isError($data)) { + if ($strict) { + $this->_errorsFound++; + $this->lastError = $data; + + return $data; + } else { + return true; + } + } else { + $this->files[$layer] = $file; + } + + $this->_decodeInput($data); + $this->configuration[$layer] = $data; + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + } + return true; + } + + // }}} + + /** + * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini + * @return true|PEAR_Error + */ + function readFTPConfigFile($path) + { + do { // poor man's try + if (!class_exists('PEAR_FTP')) { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { + require_once 'PEAR/FTP.php'; + } + } + if (class_exists('PEAR_FTP')) { + $this->_ftp = &new PEAR_FTP; + $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); + $e = $this->_ftp->init($path); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } + $tmp = System::mktemp('-d'); + PEAR_Common::addTempFile($tmp); + $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . + 'pear.ini', false, FTP_BINARY); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } + PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); + $this->_ftp->disconnect(); + $this->_ftp->popErrorHandling(); + $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; + $e = $this->readConfigFile(null, 'ftp'); + if (PEAR::isError($e)) { + return $e; + } + $fail = array(); + foreach ($this->configuration_info as $key => $val) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + // any directory configs must be set for this to work + if (!isset($this->configuration['ftp'][$key])) { + $fail[] = $key; + } + } + } + if (count($fail)) { + $fail = '"' . implode('", "', $fail) . '"'; + unset($this->files['ftp']); + unset($this->configuration['ftp']); + return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . + 'directory configuration variables. These variables were not set: ' . + $fail); + } else { + return true; + } + } else { + return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); + } + } while (false); // poor man's catch + unset($this->files['ftp']); + return PEAR::raiseError('no remote host specified'); + } + + // {{{ _setupChannels() + + /** + * Reads the existing configurations and creates the _channels array from it + */ + function _setupChannels() + { + $set = array_flip(array_values($this->_channels)); + foreach ($this->configuration as $layer => $data) { + $i = 1000; + if (isset($data['__channels']) && is_array($data['__channels'])) { + foreach ($data['__channels'] as $channel => $info) { + $set[$channel] = $i++; + } + } + } + $this->_channels = array_values(array_flip($set)); + $this->setChannels($this->_channels); + } + + // }}} + // {{{ deleteChannel(channel) + + function deleteChannel($channel) + { + foreach ($this->configuration as $layer => $data) { + if (isset($data['__channels'])) { + if (isset($data['__channels'][strtolower($channel)])) { + unset($this->configuration[$layer]['__channels'][strtolower($channel)]); + } + } + } + $this->_channels = array_flip($this->_channels); + unset($this->_channels[strtolower($channel)]); + $this->_channels = array_flip($this->_channels); + } + + // }}} + // {{{ mergeConfigFile(file, [override], [layer]) + + /** + * Merges data into a config layer from a file. Does the same + * thing as readConfigFile, except it does not replace all + * existing values in the config layer. + * @param string file to read from + * @param bool whether to overwrite existing data (default TRUE) + * @param string config layer to insert data into ('user' or 'system') + * @param string if true, errors are returned if file opening fails + * @return bool TRUE on success or a PEAR error on failure + */ + function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } + if ($file === null) { + $file = $this->files[$layer]; + } + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if ($strict) { + $this->_errorsFound++; + $this->lastError = $data; + + return $data; + } else { + return true; + } + } + $this->_decodeInput($data); + if ($override) { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); + } else { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); + } + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + } + return true; + } + + // }}} + // {{{ arrayMergeRecursive($arr2, $arr1) + /** + * @param array + * @param array + * @return array + * @static + */ + function arrayMergeRecursive($arr2, $arr1) + { + $ret = array(); + foreach ($arr2 as $key => $data) { + if (!isset($arr1[$key])) { + $ret[$key] = $data; + unset($arr1[$key]); + continue; + } + if (is_array($data)) { + if (!is_array($arr1[$key])) { + $ret[$key] = $arr1[$key]; + unset($arr1[$key]); + continue; + } + $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); + unset($arr1[$key]); + } + } + return array_merge($ret, $arr1); + } + + // }}} + // {{{ writeConfigFile([file], [layer]) + + /** + * Writes data into a config layer from a file. + * + * @param string|null file to read from, or null for default + * @param string config layer to insert data into ('user' or + * 'system') + * @param string|null data to write to config file or null for internal data [DEPRECATED] + * @return bool TRUE on success or a PEAR error on failure + */ + function writeConfigFile($file = null, $layer = 'user', $data = null) + { + $this->_lazyChannelSetup($layer); + if ($layer == 'both' || $layer == 'all') { + foreach ($this->files as $type => $file) { + $err = $this->writeConfigFile($file, $type, $data); + if (PEAR::isError($err)) { + return $err; + } + } + return true; + } + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + if ($file === null) { + $file = $this->files[$layer]; + } + $data = ($data === null) ? $this->configuration[$layer] : $data; + $this->_encodeOutput($data); + $opt = array('-p', dirname($file)); + if (!@System::mkDir($opt)) { + return $this->raiseError("could not create directory: " . dirname($file)); + } + if (file_exists($file) && is_file($file) && !is_writeable($file)) { + return $this->raiseError("no write access to $file!"); + } + $fp = @fopen($file, "w"); + if (!$fp) { + return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); + } + $contents = "#PEAR_Config 0.9\n" . serialize($data); + if (!@fwrite($fp, $contents)) { + return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + } + return true; + } + + // }}} + // {{{ _readConfigDataFrom(file) + + /** + * Reads configuration data from a file and returns the parsed data + * in an array. + * + * @param string file to read from + * + * @return array configuration data or a PEAR error on failure + * + * @access private + */ + function _readConfigDataFrom($file) + { + $fp = false; + if (file_exists($file)) { + $fp = @fopen($file, "r"); + } + if (!$fp) { + return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); + } + $size = filesize($file); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fclose($fp); + $contents = file_get_contents($file); + if (empty($contents)) { + return $this->raiseError('Configuration file "' . $file . '" is empty'); + } + + set_magic_quotes_runtime($rt); + + $version = false; + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { + $version = $matches[1]; + $contents = substr($contents, strlen($matches[0])); + } else { + // Museum config file + if (substr($contents,0,2) == 'a:') { + $version = '0.1'; + } + } + if ($version && version_compare("$version", '1', '<')) { + + // no '@', it is possible that unserialize + // raises a notice but it seems to block IO to + // STDOUT if a '@' is used and a notice is raise + $data = unserialize($contents); + + if (!is_array($data) && !$data) { + if ($contents == serialize(false)) { + $data = array(); + } else { + $err = $this->raiseError("PEAR_Config: bad data in $file"); + return $err; + } + } + if (!is_array($data)) { + if (strlen(trim($contents)) > 0) { + $error = "PEAR_Config: bad data in $file"; + $err = $this->raiseError($error); + return $err; + } else { + $data = array(); + } + } + // add parsing of newer formats here... + } else { + $err = $this->raiseError("$file: unknown version `$version'"); + return $err; + } + return $data; + } + + // }}} + // {{{ getConfFile(layer) + /** + * Gets the file used for storing the config for a layer + * + * @param string $layer 'user' or 'system' + */ + + function getConfFile($layer) + { + return $this->files[$layer]; + } + + // }}} + + /** + * @param string Configuration class name, used for detecting duplicate calls + * @param array information on a role as parsed from its xml file + * @return true|PEAR_Error + * @access private + */ + function _addConfigVars($class, $vars) + { + static $called = array(); + if (isset($called[$class])) { + return; + } + $called[$class] = 1; + if (count($vars) > 3) { + return $this->raiseError('Roles can only define 3 new config variables or less'); + } + foreach ($vars as $name => $var) { + if (!is_array($var)) { + return $this->raiseError('Configuration information must be an array'); + } + if (!isset($var['type'])) { + return $this->raiseError('Configuration information must contain a type'); + } else { + if (!in_array($var['type'], + array('string', 'mask', 'password', 'directory', 'file', 'set'))) { + return $this->raiseError( + 'Configuration type must be one of directory, file, string, ' . + 'mask, set, or password'); + } + } + if (!isset($var['default'])) { + return $this->raiseError( + 'Configuration information must contain a default value ("default" index)'); + } else { + if (is_array($var['default'])) { + $real_default = ''; + foreach ($var['default'] as $config_var => $val) { + if (strpos($config_var, 'text') === 0) { + $real_default .= $val; + } elseif (strpos($config_var, 'constant') === 0) { + if (defined($val)) { + $real_default .= constant($val); + } else { + return $this->raiseError( + 'Unknown constant "' . $val . '" requested in ' . + 'default value for configuration variable "' . + $name . '"'); + } + } elseif (isset($this->configuration_info[$config_var])) { + $real_default .= + $this->configuration_info[$config_var]['default']; + } else { + return $this->raiseError( + 'Unknown request for "' . $config_var . '" value in ' . + 'default value for configuration variable "' . + $name . '"'); + } + } + $var['default'] = $real_default; + } + if ($var['type'] == 'integer') { + $var['default'] = (integer) $var['default']; + } + } + if (!isset($var['doc'])) { + return $this->raiseError( + 'Configuration information must contain a summary ("doc" index)'); + } + if (!isset($var['prompt'])) { + return $this->raiseError( + 'Configuration information must contain a simple prompt ("prompt" index)'); + } + if (!isset($var['group'])) { + return $this->raiseError( + 'Configuration information must contain a simple group ("group" index)'); + } + if (isset($this->configuration_info[$name])) { + return $this->raiseError('Configuration variable "' . $name . + '" already exists'); + } + $this->configuration_info[$name] = $var; + // fix bug #7351: setting custom config variable in a channel fails + $this->_channelConfigInfo[] = $name; + } + return true; + } + + // {{{ _encodeOutput(&data) + + /** + * Encodes/scrambles configuration data before writing to files. + * Currently, 'password' values will be base64-encoded as to avoid + * that people spot cleartext passwords by accident. + * + * @param array (reference) array to encode values in + * + * @return bool TRUE on success + * + * @access private + */ + function _encodeOutput(&$data) + { + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_encodeOutput($data['__channels'][$channel]); + } + } + if (!isset($this->configuration_info[$key])) { + continue; + } + $type = $this->configuration_info[$key]['type']; + switch ($type) { + // we base64-encode passwords so they are at least + // not shown in plain by accident + case 'password': { + $data[$key] = base64_encode($data[$key]); + break; + } + case 'mask': { + $data[$key] = octdec($data[$key]); + break; + } + } + } + return true; + } + + // }}} + // {{{ _decodeInput(&data) + + /** + * Decodes/unscrambles configuration data after reading from files. + * + * @param array (reference) array to encode values in + * + * @return bool TRUE on success + * + * @access private + * + * @see PEAR_Config::_encodeOutput + */ + function _decodeInput(&$data) + { + if (!is_array($data)) { + return true; + } + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_decodeInput($data['__channels'][$channel]); + } + } + if (!isset($this->configuration_info[$key])) { + continue; + } + $type = $this->configuration_info[$key]['type']; + switch ($type) { + case 'password': { + $data[$key] = base64_decode($data[$key]); + break; + } + case 'mask': { + $data[$key] = decoct($data[$key]); + break; + } + } + } + return true; + } + + // }}} + // {{{ getDefaultChannel([layer]) + /** + * Retrieve the default channel. + * + * On startup, channels are not initialized, so if the default channel is not + * pear.php.net, then initialize the config. + * @param string registry layer + * @return string|false + */ + function getDefaultChannel($layer = null) + { + $ret = false; + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + break; + } + } + } elseif (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + } + if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { + $ret = 'pecl.php.net'; + } + if ($ret) { + if ($ret != 'pear.php.net') { + $this->_lazyChannelSetup(); + } + return $ret; + } + return PEAR_CONFIG_DEFAULT_CHANNEL; + } + + // {{{ get(key, [layer]) + /** + * Returns a configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * + * @return mixed the config value, or NULL if not found + * + * @access public + */ + function get($key, $layer = null, $channel = false) + { + if (!isset($this->configuration_info[$key])) { + return null; + } + if ($key == '__channels') { + return null; + } + if ($key == 'default_channel') { + return $this->getDefaultChannel($layer); + } + if (!$channel) { + $channel = $this->getDefaultChannel(); + } elseif ($channel != 'pear.php.net') { + $this->_lazyChannelSetup(); + } + $channel = strtolower($channel); + + $test = (in_array($key, $this->_channelConfigInfo)) ? + $this->_getChannelValue($key, $layer, $channel) : + null; + if ($test !== null) { + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + return $test; + } + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } + } + return $test; + } + } + } elseif (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } + } + return $test; + } + return null; + } + + // }}} + // {{{ _getChannelValue(key, value, [layer]) + /** + * Returns a channel-specific configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * + * @return mixed the config value, or NULL if not found + * + * @access private + */ + function _getChannelValue($key, $layer, $channel) + { + if ($key == '__channels' || $channel == 'pear.php.net') { + return null; + } + $ret = null; + if ($layer === null) { + foreach ($this->layers as $ilayer) { + if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; + break; + } + } + } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$layer]['__channels'][$channel][$key]; + } + if ($key == 'preferred_mirror') { + if ($ret !== null) { + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + if (!$chan->getMirror($ret) && $chan->getName() != $ret) { + return $channel; // mirror does not exist + } + } + return $ret; + } + if ($channel != $this->getDefaultChannel($layer)) { + return $channel; // we must use the channel name as the preferred mirror + // if the user has not chosen an alternate + } else { + return $this->getDefaultChannel($layer); + } + } + return $ret; + } + + + // }}} + // {{{ set(key, value, [layer]) + + /** + * Set a config value in a specific layer (defaults to 'user'). + * Enforces the types defined in the configuration_info array. An + * integer config variable will be cast to int, and a set config + * variable will be validated against its legal values. + * + * @param string config key + * @param string config value + * @param string (optional) config layer + * @param string channel to set this value for, or null for global value + * @return bool TRUE on success, FALSE on failure + */ + function set($key, $value, $layer = 'user', $channel = false) + { + if ($key == '__channels') { + return false; + } + if (!isset($this->configuration[$layer])) { + return false; + } + if ($key == 'default_channel') { + // can only set this value globally + $channel = 'pear.php.net'; + if ($value != 'pear.php.net') { + $this->_lazyChannelSetup($layer); + } + } + if ($key == 'preferred_mirror') { + if ($channel == '__uri') { + return false; // can't set the __uri pseudo-channel's mirror + } + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); + if (PEAR::isError($chan)) { + return false; + } + if (!$chan->getMirror($value) && $chan->getName() != $value) { + return false; // mirror does not exist + } + } + } + if (!isset($this->configuration_info[$key])) { + return false; + } + extract($this->configuration_info[$key]); + switch ($type) { + case 'integer': + $value = (int)$value; + break; + case 'set': { + // If a valid_set is specified, require the value to + // be in the set. If there is no valid_set, accept + // any value. + if ($valid_set) { + reset($valid_set); + if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || + (key($valid_set) !== 0 && empty($valid_set[$value]))) + { + return false; + } + } + break; + } + } + if (!$channel) { + $channel = $this->get('default_channel', null, 'pear.php.net'); + } + if (!in_array($channel, $this->_channels)) { + $this->_lazyChannelSetup($layer); + $reg = &$this->getRegistry($layer); + if ($reg) { + $channel = $reg->channelName($channel); + } + if (!in_array($channel, $this->_channels)) { + return false; + } + } + if ($channel != 'pear.php.net') { + if (in_array($key, $this->_channelConfigInfo)) { + $this->configuration[$layer]['__channels'][$channel][$key] = $value; + return true; + } else { + return false; + } + } else { + if ($key == 'default_channel') { + if (!isset($reg)) { + $reg = &$this->getRegistry($layer); + if (!$reg) { + $reg = &$this->getRegistry(); + } + } + if ($reg) { + $value = $reg->channelName($value); + } + if (!$value) { + return false; + } + } + } + $this->configuration[$layer][$key] = $value; + if ($key == 'php_dir' && !$this->_noRegistry) { + if (!isset($this->_registry[$layer]) || + $value != $this->_registry[$layer]->install_dir) { + $this->_registry[$layer] = &new PEAR_Registry($value); + $this->_regInitialized[$layer] = false; + $this->_registry[$layer]->setConfig($this, false); + } + } + return true; + } + + // }}} + function _lazyChannelSetup($uselayer = false) + { + if ($this->_noRegistry) { + return; + } + $merge = false; + foreach ($this->_registry as $layer => $p) { + if ($uselayer && $uselayer != $layer) { + continue; + } + if (!$this->_regInitialized[$layer]) { + if ($layer == 'default' && isset($this->_registry['user']) || + isset($this->_registry['system'])) { + // only use the default registry if there are no alternatives + continue; + } + if (!is_object($this->_registry[$layer])) { + if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + return; + } + } + $this->setChannels($this->_registry[$layer]->listChannels(), $merge); + $this->_regInitialized[$layer] = true; + $merge = true; + } + } + } + // {{{ setChannels() + + /** + * Set the list of channels. + * + * This should be set via a call to {@link PEAR_Registry::listChannels()} + * @param array + * @param bool + * @return bool success of operation + */ + function setChannels($channels, $merge = false) + { + if (!is_array($channels)) { + return false; + } + if ($merge) { + $this->_channels = array_merge($this->_channels, $channels); + } else { + $this->_channels = $channels; + } + foreach ($channels as $channel) { + $channel = strtolower($channel); + if ($channel == 'pear.php.net') { + continue; + } + foreach ($this->layers as $layer) { + if (!isset($this->configuration[$layer]['__channels'])) { + $this->configuration[$layer]['__channels'] = array(); + } + if (!isset($this->configuration[$layer]['__channels'][$channel]) + || !is_array($this->configuration[$layer]['__channels'][$channel])) { + $this->configuration[$layer]['__channels'][$channel] = array(); + } + } + } + return true; + } + + // }}} + // {{{ getType(key) + + /** + * Get the type of a config value. + * + * @param string config key + * + * @return string type, one of "string", "integer", "file", + * "directory", "set" or "password". + * + * @access public + * + */ + function getType($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['type']; + } + return false; + } + + // }}} + // {{{ getDocs(key) + + /** + * Get the documentation for a config value. + * + * @param string config key + * + * @return string documentation string + * + * @access public + * + */ + function getDocs($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['doc']; + } + return false; + } + // }}} + // {{{ getPrompt(key) + + /** + * Get the short documentation for a config value. + * + * @param string config key + * + * @return string short documentation string + * + * @access public + * + */ + function getPrompt($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['prompt']; + } + return false; + } + // }}} + // {{{ getGroup(key) + + /** + * Get the parameter group for a config key. + * + * @param string config key + * + * @return string parameter group + * + * @access public + * + */ + function getGroup($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['group']; + } + return false; + } + + // }}} + // {{{ getGroups() + + /** + * Get the list of parameter groups. + * + * @return array list of parameter groups + * + * @access public + * + */ + function getGroups() + { + $tmp = array(); + foreach ($this->configuration_info as $key => $info) { + $tmp[$info['group']] = 1; + } + return array_keys($tmp); + } + + // }}} + // {{{ getGroupKeys() + + /** + * Get the list of the parameters in a group. + * + * @param string $group parameter group + * + * @return array list of parameters in $group + * + * @access public + * + */ + function getGroupKeys($group) + { + $keys = array(); + foreach ($this->configuration_info as $key => $info) { + if ($info['group'] == $group) { + $keys[] = $key; + } + } + return $keys; + } + + // }}} + // {{{ getSetValues(key) + + /** + * Get the list of allowed set values for a config value. Returns + * NULL for config values that are not sets. + * + * @param string config key + * + * @return array enumerated array of set values, or NULL if the + * config key is unknown or not a set + * + * @access public + * + */ + function getSetValues($key) + { + if (isset($this->configuration_info[$key]) && + isset($this->configuration_info[$key]['type']) && + $this->configuration_info[$key]['type'] == 'set') + { + $valid_set = $this->configuration_info[$key]['valid_set']; + reset($valid_set); + if (key($valid_set) === 0) { + return $valid_set; + } + return array_keys($valid_set); + } + return null; + } + + // }}} + // {{{ getKeys() + + /** + * Get all the current config keys. + * + * @return array simple array of config keys + * + * @access public + */ + function getKeys() + { + $keys = array(); + foreach ($this->layers as $layer) { + $test = $this->configuration[$layer]; + if (isset($test['__channels'])) { + foreach ($test['__channels'] as $channel => $configs) { + $keys = array_merge($keys, $configs); + } + } + unset($test['__channels']); + $keys = array_merge($keys, $test); + } + return array_keys($keys); + } + + // }}} + // {{{ remove(key, [layer]) + + /** + * Remove the a config key from a specific config layer. + * + * @param string config key + * + * @param string (optional) config layer + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function remove($key, $layer = 'user') + { + $channel = $this->getDefaultChannel(); + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + unset($this->configuration[$layer]['__channels'][$channel][$key]); + return true; + } + } + if (isset($this->configuration[$layer][$key])) { + unset($this->configuration[$layer][$key]); + return true; + } + return false; + } + + // }}} + // {{{ removeLayer(layer) + + /** + * Temporarily remove an entire config layer. USE WITH CARE! + * + * @param string config key + * + * @param string (optional) config layer + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function removeLayer($layer) + { + if (isset($this->configuration[$layer])) { + $this->configuration[$layer] = array(); + return true; + } + return false; + } + + // }}} + // {{{ store([layer]) + + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user', $data = null) + { + return $this->writeConfigFile(null, $layer, $data); + } + + // }}} + // {{{ toDefault(key) + + /** + * Unset the user-defined value of a config key, reverting the + * value to the system-defined one. + * + * @param string config key + * + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function toDefault($key) + { + trigger_error("PEAR_Config::toDefault() deprecated, use PEAR_Config::remove() instead", E_USER_NOTICE); + return $this->remove($key, 'user'); + } + + // }}} + // {{{ definedBy(key) + + /** + * Tells what config layer that gets to define a key. + * + * @param string config key + * @param boolean return the defining channel + * + * @return string|array the config layer, or an empty string if not found. + * + * if $returnchannel, the return is an array array('layer' => layername, + * 'channel' => channelname), or an empty string if not found + * + * @access public + */ + function definedBy($key, $returnchannel = false) + { + foreach ($this->layers as $layer) { + $channel = $this->getDefaultChannel(); + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => $channel); + } + return $layer; + } + } + if (isset($this->configuration[$layer][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => 'pear.php.net'); + } + return $layer; + } + } + return ''; + } + + // }}} + // {{{ isDefaulted(key) + + /** + * Tells whether a config value has a system-defined value. + * + * @param string config key + * + * @return bool + * + * @access public + * + * @deprecated + */ + function isDefaulted($key) + { + trigger_error("PEAR_Config::isDefaulted() deprecated, use PEAR_Config::definedBy() instead", E_USER_NOTICE); + return $this->definedBy($key) == 'system'; + } + + // }}} + // {{{ isDefined(key) + + /** + * Tells whether a given key exists as a config value. + * + * @param string config key + * + * @return bool whether <config key> exists in this object + * + * @access public + */ + function isDefined($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return true; + } + } + return false; + } + + // }}} + // {{{ isDefinedLayer(key) + + /** + * Tells whether a given config layer exists. + * + * @param string config layer + * + * @return bool whether <config layer> exists in this object + * + * @access public + */ + function isDefinedLayer($layer) + { + return isset($this->configuration[$layer]); + } + + // }}} + // {{{ getLayers() + + /** + * Returns the layers defined (except the 'default' one) + * + * @return array of the defined layers + */ + function getLayers() + { + $cf = $this->configuration; + unset($cf['default']); + return array_keys($cf); + } + + // }}} + // {{{ apiVersion() + function apiVersion() + { + return '1.1'; + } + // }}} + + /** + * @return PEAR_Registry + */ + function &getRegistry($use = null) + { + if ($use === null) { + $layer = 'user'; + } else { + $layer = $use; + } + if (isset($this->_registry[$layer])) { + return $this->_registry[$layer]; + } elseif ($use === null && isset($this->_registry['system'])) { + return $this->_registry['system']; + } elseif ($use === null && isset($this->_registry['default'])) { + return $this->_registry['default']; + } elseif ($use) { + $a = false; + return $a; + } else { + // only go here if null was passed in + echo "CRITICAL ERROR: Registry could not be initialized from any value"; + exit(1); + } + } + /** + * This is to allow customization like the use of installroot + * @param PEAR_Registry + * @return bool + */ + function setRegistry(&$reg, $layer = 'user') + { + if ($this->_noRegistry) { + return false; + } + if (!in_array($layer, array('user', 'system'))) { + return false; + } + $this->_registry[$layer] = &$reg; + if (is_object($reg)) { + $this->_registry[$layer]->setConfig($this, false); + } + return true; + } + + function noRegistry() + { + $this->_noRegistry = true; + } + + /** + * @return PEAR_Remote + */ + function &getRemote() + { + $remote = &new PEAR_Remote($this); + return $remote; + } + + /** + * @return PEAR_REST + */ + function &getREST($version, $options = array()) + { + $version = str_replace('.', '', $version); + if (!class_exists($class = 'PEAR_REST_' . $version)) { + require_once 'PEAR/REST/' . $version . '.php'; + } + $remote = &new $class($this, $options); + return $remote; + } + + /** + * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a + * remote configuration file has been specified + * @return PEAR_FTP|false + */ + function &getFTP() + { + if (isset($this->_ftp)) { + return $this->_ftp; + } else { + $a = false; + return $a; + } + } + + // {{{ _prependPath($path, $prepend) + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; + } + } + return $path; + } + // }}} + + /** + * @param string|false installation directory to prepend to all _dir variables, or false to + * disable + */ + function setInstallRoot($root) + { + if (substr($root, -1) == DIRECTORY_SEPARATOR) { + $root = substr($root, 0, -1); + } + $old = $this->_installRoot; + $this->_installRoot = $root; + if (($old != $root) && !$this->_noRegistry) { + foreach (array_keys($this->_registry) as $layer) { + if ($layer == 'ftp' || !isset($this->_registry[$layer])) { + continue; + } + $this->_registry[$layer] = + &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } + } + } +} + +?> diff --git a/vas/rest/class/PEAR/Dependency.php b/vas/rest/class/PEAR/Dependency.php new file mode 100755 index 0000000000000000000000000000000000000000..0265f6f75aeb22525238faf147a1dc67e532f532 --- /dev/null +++ b/vas/rest/class/PEAR/Dependency.php @@ -0,0 +1,498 @@ +<?php +/** + * PEAR_Dependency + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * THIS FILE IS DEPRECATED IN FAVOR OF DEPENDENCY2.PHP, AND IS NOT USED IN THE INSTALLER + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Dependency.php,v 1.43 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +require_once "PEAR.php"; +require_once "OS/Guess.php"; + +define('PEAR_DEPENDENCY_MISSING', -1); +define('PEAR_DEPENDENCY_CONFLICT', -2); +define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3); +define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4); +define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5); +define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6); +define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL', -7); +define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL', -8); +define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL', -9); + +/** + * Dependency check for PEAR packages + * + * The class is based on the dependency RFC that can be found at + * http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1 + * + * @author Tomas V.V.Vox <cox@idecnet.com> + * @author Stig Bakken <ssb@php.net> + */ +class PEAR_Dependency +{ + // {{{ constructor + /** + * Constructor + * + * @access public + * @param object Registry object + * @return void + */ + function PEAR_Dependency(&$registry) + { + $this->registry = &$registry; + } + + // }}} + // {{{ callCheckMethod() + + /** + * This method maps the XML dependency definition to the + * corresponding one from PEAR_Dependency + * + * <pre> + * $opts => Array + * ( + * [type] => pkg + * [rel] => ge + * [version] => 3.4 + * [name] => HTML_Common + * [optional] => false + * ) + * </pre> + * + * @param string Error message + * @param array Options + * @return boolean + */ + function callCheckMethod(&$errmsg, $opts) + { + $rel = isset($opts['rel']) ? $opts['rel'] : 'has'; + $req = isset($opts['version']) ? $opts['version'] : null; + $name = isset($opts['name']) ? $opts['name'] : null; + $channel = isset($opts['channel']) ? $opts['channel'] : 'pear.php.net'; + $opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ? + $opts['optional'] : null; + $errmsg = ''; + switch ($opts['type']) { + case 'pkg': + return $this->checkPackage($errmsg, $name, $req, $rel, $opt, $channel); + break; + case 'ext': + return $this->checkExtension($errmsg, $name, $req, $rel, $opt); + break; + case 'php': + return $this->checkPHP($errmsg, $req, $rel); + break; + case 'prog': + return $this->checkProgram($errmsg, $name); + break; + case 'os': + return $this->checkOS($errmsg, $name); + break; + case 'sapi': + return $this->checkSAPI($errmsg, $name); + break; + case 'zend': + return $this->checkZend($errmsg, $name); + break; + default: + return "'{$opts['type']}' dependency type not supported"; + } + } + + // }}} + // {{{ checkPackage() + + /** + * Package dependencies check method + * + * @param string $errmsg Empty string, it will be populated with an error message, if any + * @param string $name Name of the package to test + * @param string $req The package version required + * @param string $relation How to compare versions with each other + * @param bool $opt Whether the relationship is optional + * @param string $channel Channel name + * + * @return mixed bool false if no error or the error string + */ + function checkPackage(&$errmsg, $name, $req = null, $relation = 'has', + $opt = false, $channel = 'pear.php.net') + { + if (is_string($req) && substr($req, 0, 2) == 'v.') { + $req = substr($req, 2); + } + switch ($relation) { + case 'has': + if (!$this->registry->packageExists($name, $channel)) { + if ($opt) { + $errmsg = "package `$channel/$name' is recommended to utilize some features."; + return PEAR_DEPENDENCY_MISSING_OPTIONAL; + } + $errmsg = "requires package `$channel/$name'"; + return PEAR_DEPENDENCY_MISSING; + } + return false; + case 'not': + if ($this->registry->packageExists($name, $channel)) { + $errmsg = "conflicts with package `$channel/$name'"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + case 'lt': + case 'le': + case 'eq': + case 'ne': + case 'ge': + case 'gt': + $version = $this->registry->packageInfo($name, 'version', $channel); + if (!$this->registry->packageExists($name, $channel) + || !version_compare("$version", "$req", $relation)) + { + $code = $this->codeFromRelation($relation, $version, $req, $opt); + if ($opt) { + $errmsg = "package `$channel/$name' version " . $this->signOperator($relation) . + " $req is recommended to utilize some features."; + if ($version) { + $errmsg .= " Installed version is $version"; + } + return $code; + } + $errmsg = "requires package `$channel/$name' " . + $this->signOperator($relation) . " $req"; + return $code; + } + return false; + } + $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$channel/$name)"; + return PEAR_DEPENDENCY_BAD_DEPENDENCY; + } + + // }}} + // {{{ checkPackageUninstall() + + /** + * Check package dependencies on uninstall + * + * @param string $error The resultant error string + * @param string $warning The resultant warning string + * @param string $name Name of the package to test + * @param string $channel Channel name of the package + * + * @return bool true if there were errors + */ + function checkPackageUninstall(&$error, &$warning, $package, $channel = 'pear.php.net') + { + $channel = strtolower($channel); + $error = null; + $channels = $this->registry->listAllPackages(); + foreach ($channels as $channelname => $packages) { + foreach ($packages as $pkg) { + if ($pkg == $package && $channel == $channelname) { + continue; + } + $deps = $this->registry->packageInfo($pkg, 'release_deps', $channel); + if (empty($deps)) { + continue; + } + foreach ($deps as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : 'pear.php.net'; + if ($dep['type'] == 'pkg' && (strcasecmp($dep['name'], $package) == 0) && + ($depchannel == $channel)) { + if ($dep['rel'] == 'ne') { + continue; + } + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $warning .= "\nWarning: Package '$depchannel/$pkg' optionally depends on '$channel:/package'"; + } else { + $error .= "Package '$depchannel/$pkg' depends on '$channel/$package'\n"; + } + } + } + } + } + return ($error) ? true : false; + } + + // }}} + // {{{ checkExtension() + + /** + * Extension dependencies check method + * + * @param string $name Name of the extension to test + * @param string $req_ext_ver Required extension version to compare with + * @param string $relation How to compare versions with eachother + * @param bool $opt Whether the relationship is optional + * + * @return mixed bool false if no error or the error string + */ + function checkExtension(&$errmsg, $name, $req = null, $relation = 'has', + $opt = false) + { + if ($relation == 'not') { + if (extension_loaded($name)) { + $errmsg = "conflicts with PHP extension '$name'"; + return PEAR_DEPENDENCY_CONFLICT; + } else { + return false; + } + } + + if (!extension_loaded($name)) { + if ($relation == 'ne') { + return false; + } + if ($opt) { + $errmsg = "'$name' PHP extension is recommended to utilize some features"; + return PEAR_DEPENDENCY_MISSING_OPTIONAL; + } + $errmsg = "'$name' PHP extension is not installed"; + return PEAR_DEPENDENCY_MISSING; + } + if ($relation == 'has') { + return false; + } + $code = false; + if (is_string($req) && substr($req, 0, 2) == 'v.') { + $req = substr($req, 2); + } + $ext_ver = phpversion($name); + $operator = $relation; + // Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90) + if (!version_compare("$ext_ver", "$req", $operator)) { + $errmsg = "'$name' PHP extension version " . + $this->signOperator($operator) . " $req is required"; + $code = $this->codeFromRelation($relation, $ext_ver, $req, $opt); + if ($opt) { + $errmsg = "'$name' PHP extension version " . $this->signOperator($operator) . + " $req is recommended to utilize some features"; + return $code; + } + } + return $code; + } + + // }}} + // {{{ checkOS() + + /** + * Operating system dependencies check method + * + * @param string $os Name of the operating system + * + * @return mixed bool false if no error or the error string + */ + function checkOS(&$errmsg, $os) + { + // XXX Fixme: Implement a more flexible way, like + // comma separated values or something similar to PEAR_OS + static $myos; + if (empty($myos)) { + $myos = new OS_Guess(); + } + // only 'has' relation is currently supported + if ($myos->matchSignature($os)) { + return false; + } + $errmsg = "'$os' operating system not supported"; + return PEAR_DEPENDENCY_CONFLICT; + } + + // }}} + // {{{ checkPHP() + + /** + * PHP version check method + * + * @param string $req which version to compare + * @param string $relation how to compare the version + * + * @return mixed bool false if no error or the error string + */ + function checkPHP(&$errmsg, $req, $relation = 'ge') + { + // this would be a bit stupid, but oh well :) + if ($relation == 'has') { + return false; + } + if ($relation == 'not') { + $errmsg = "Invalid dependency - 'not' is allowed when specifying PHP, you must run PHP in PHP"; + return PEAR_DEPENDENCY_BAD_DEPENDENCY; + } + if (substr($req, 0, 2) == 'v.') { + $req = substr($req,2, strlen($req) - 2); + } + $php_ver = phpversion(); + $operator = $relation; + if (!version_compare("$php_ver", "$req", $operator)) { + $errmsg = "PHP version " . $this->signOperator($operator) . + " $req is required"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + } + + // }}} + // {{{ checkProgram() + + /** + * External program check method. Looks for executable files in + * directories listed in the PATH environment variable. + * + * @param string $program which program to look for + * + * @return mixed bool false if no error or the error string + */ + function checkProgram(&$errmsg, $program) + { + // XXX FIXME honor safe mode + $exe_suffix = OS_WINDOWS ? '.exe' : ''; + $path_elements = explode(PATH_SEPARATOR, getenv('PATH')); + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix; + if (file_exists($file) && is_executable($file)) { + return false; + } + } + $errmsg = "'$program' program is not present in the PATH"; + return PEAR_DEPENDENCY_MISSING; + } + + // }}} + // {{{ checkSAPI() + + /** + * SAPI backend check method. Version comparison is not yet + * available here. + * + * @param string $name name of SAPI backend + * @param string $req which version to compare + * @param string $relation how to compare versions (currently + * hardcoded to 'has') + * @return mixed bool false if no error or the error string + */ + function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has') + { + // XXX Fixme: There is no way to know if the user has or + // not other SAPI backends installed than the installer one + + $sapi_backend = php_sapi_name(); + // Version comparisons not supported, sapi backends don't have + // version information yet. + if ($sapi_backend == $name) { + return false; + } + $errmsg = "'$sapi_backend' SAPI backend not supported"; + return PEAR_DEPENDENCY_CONFLICT; + } + + // }}} + // {{{ checkZend() + + /** + * Zend version check method + * + * @param string $req which version to compare + * @param string $relation how to compare the version + * + * @return mixed bool false if no error or the error string + */ + function checkZend(&$errmsg, $req, $relation = 'ge') + { + if (substr($req, 0, 2) == 'v.') { + $req = substr($req,2, strlen($req) - 2); + } + $zend_ver = zend_version(); + $operator = substr($relation,0,2); + if (!version_compare("$zend_ver", "$req", $operator)) { + $errmsg = "Zend version " . $this->signOperator($operator) . + " $req is required"; + return PEAR_DEPENDENCY_CONFLICT; + } + return false; + } + + // }}} + // {{{ signOperator() + + /** + * Converts text comparing operators to them sign equivalents + * + * Example: 'ge' to '>=' + * + * @access public + * @param string Operator + * @return string Sign equivalent + */ + function signOperator($operator) + { + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; + } + } + + // }}} + // {{{ codeFromRelation() + + /** + * Convert relation into corresponding code + * + * @access public + * @param string Relation + * @param string Version + * @param string Requirement + * @param bool Optional dependency indicator + * @return integer + */ + function codeFromRelation($relation, $version, $req, $opt = false) + { + $code = PEAR_DEPENDENCY_BAD_DEPENDENCY; + switch ($relation) { + case 'gt': case 'ge': case 'eq': + // upgrade + $have_major = preg_replace('/\D.*/', '', $version); + $need_major = preg_replace('/\D.*/', '', $req); + if ($need_major > $have_major) { + $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL : + PEAR_DEPENDENCY_UPGRADE_MAJOR; + } else { + $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL : + PEAR_DEPENDENCY_UPGRADE_MINOR; + } + break; + case 'lt': case 'le': case 'ne': + $code = $opt ? PEAR_DEPENDENCY_CONFLICT_OPTIONAL : + PEAR_DEPENDENCY_CONFLICT; + break; + } + return $code; + } + + // }}} +} +?> diff --git a/vas/rest/class/PEAR/Dependency2.php b/vas/rest/class/PEAR/Dependency2.php new file mode 100755 index 0000000000000000000000000000000000000000..802e9bfa20787e6a8f49ef4c9bc805aeba7b980c --- /dev/null +++ b/vas/rest/class/PEAR/Dependency2.php @@ -0,0 +1,1299 @@ +<?php +/** + * PEAR_Dependency2, advanced dependency validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Dependency2.php,v 1.56 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Required for the PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; + +/** + * Dependency check for PEAR packages + * + * This class handles both version 1.0 and 2.0 dependencies + * WARNING: *any* changes to this class must be duplicated in the + * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, + * or unit tests will not actually validate the changes + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Dependency2 +{ + /** + * One of the PEAR_VALIDATE_* states + * @see PEAR_VALIDATE_NORMAL + * @var integer + */ + var $_state; + /** + * Command-line options to install/upgrade/uninstall commands + * @param array + */ + var $_options; + /** + * @var OS_Guess + */ + var $_os; + /** + * @var PEAR_Registry + */ + var $_registry; + /** + * @var PEAR_Config + */ + var $_config; + /** + * @var PEAR_DependencyDB + */ + var $_dependencydb; + /** + * Output of PEAR_Registry::parsedPackageName() + * @var array + */ + var $_currentPackage; + /** + * @param PEAR_Config + * @param array installation options + * @param array format of PEAR_Registry::parsedPackageName() + * @param int installation state (one of PEAR_VALIDATE_*) + */ + function PEAR_Dependency2(&$config, $installoptions, $package, + $state = PEAR_VALIDATE_INSTALLING) + { + $this->_config = &$config; + if (!class_exists('PEAR_DependencyDB')) { + require_once 'PEAR/DependencyDB.php'; + } + if (isset($installoptions['packagingroot'])) { + // make sure depdb is in the right location + $config->setInstallRoot($installoptions['packagingroot']); + } + $this->_registry = &$config->getRegistry(); + $this->_dependencydb = &PEAR_DependencyDB::singleton($config); + if (isset($installoptions['packagingroot'])) { + $config->setInstallRoot(false); + } + $this->_options = $installoptions; + $this->_state = $state; + if (!class_exists('OS_Guess')) { + require_once 'OS/Guess.php'; + } + $this->_os = new OS_Guess; + $this->_currentPackage = $package; + } + + function _getExtraString($dep) + { + $extra = ' ('; + if (isset($dep['uri'])) { + return ''; + } + if (isset($dep['recommended'])) { + $extra .= 'recommended version ' . $dep['recommended']; + } else { + if (isset($dep['min'])) { + $extra .= 'version >= ' . $dep['min']; + } + if (isset($dep['max'])) { + if ($extra != ' (') { + $extra .= ', '; + } + $extra .= 'version <= ' . $dep['max']; + } + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + if ($extra != ' (') { + $extra .= ', '; + } + $extra .= 'excluded versions: '; + foreach ($dep['exclude'] as $i => $exclude) { + if ($i) { + $extra .= ', '; + } + $extra .= $exclude; + } + } + } + $extra .= ')'; + if ($extra == ' ()') { + $extra = ''; + } + return $extra; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getPHP_OS() + { + return PHP_OS; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getsysname() + { + return $this->_os->getSysname(); + } + + /** + * Specify a dependency on an OS. Use arch for detailed os/processor information + * + * There are two generic OS dependencies that will be the most common, unix and windows. + * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix + */ + function validateOsDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + if (isset($dep['conflicts'])) { + $not = true; + } else { + $not = false; + } + if ($dep['name'] == '*') { + return true; + } + switch (strtolower($dep['name'])) { + case 'windows' : + if ($not) { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on Windows"); + } else { + return $this->warning("warning: Cannot install %s on Windows"); + } + } + } else { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on Windows"); + } else { + return $this->warning("warning: Can only install %s on Windows"); + } + } + } + break; + case 'unix' : + $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); + if ($not) { + if (in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on any Unix system"); + } else { + return $this->warning( + "warning: Cannot install %s on any Unix system"); + } + } + } else { + if (!in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on a Unix system"); + } else { + return $this->warning( + "warning: Can only install %s on a Unix system"); + } + } + } + break; + default : + if ($not) { + if (strtolower($dep['name']) == strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . $dep['name'] . + ' operating system'); + } else { + return $this->warning('warning: Cannot install %s on ' . + $dep['name'] . ' operating system'); + } + } + } else { + if (strtolower($dep['name']) != strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } else { + return $this->warning('warning: Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } + } + } + } + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function matchSignature($pattern) + { + return $this->_os->matchSignature($pattern); + } + + /** + * Specify a complex dependency on an OS/processor/kernel version, + * Use OS for simple operating system dependency. + * + * This is the only dependency that accepts an eregable pattern. The pattern + * will be matched against the php_uname() output parsed by OS_Guess + */ + function validateArchDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING) { + return true; + } + if (isset($dep['conflicts'])) { + $not = true; + } else { + $not = false; + } + if (!$this->matchSignature($dep['pattern'])) { + if (!$not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, does not ' . + 'match "' . $dep['pattern'] . '"'); + } else { + return $this->warning('warning: %s Architecture dependency failed, does ' . + 'not match "' . $dep['pattern'] . '"'); + } + } + return true; + } else { + if ($not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, required "' . + $dep['pattern'] . '"'); + } else { + return $this->warning('warning: %s Architecture dependency failed, ' . + 'required "' . $dep['pattern'] . '"'); + } + } + return true; + } + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function extension_loaded($name) + { + return extension_loaded($name); + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function phpversion($name = null) + { + if ($name !== null) { + return phpversion($name); + } else { + return phpversion(); + } + } + + function validateExtensionDependency($dep, $required = true) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + $loaded = $this->extension_loaded($dep['name']); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude'])) { + if ($loaded) { + if (isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } else { + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } + } + return true; + } else { + if (isset($dep['conflicts'])) { + return true; + } + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . + $dep['name'] . '"' . $extra); + } else { + return $this->warning('warning: %s requires PHP extension "' . + $dep['name'] . '"' . $extra); + } + } else { + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } + } + } + if (!$loaded) { + if (isset($dep['conflicts'])) { + return true; + } + if (!$required) { + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } else { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } + } + $version = (string) $this->phpversion($dep['name']); + if (empty($version)) { + $version = '0'; + } + $fail = false; + if (isset($dep['min'])) { + if (!version_compare($version, $dep['min'], '>=')) { + $fail = true; + } + } + if (isset($dep['max'])) { + if (!version_compare($version, $dep['max'], '<=')) { + $fail = true; + } + } + if ($fail && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } else { + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } else { + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + } + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (isset($dep['conflicts'])) { + continue; + } + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } else { + return $this->warning('warning: %s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } else { + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + } + } + } + if (isset($dep['recommended'])) { + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } else { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . + ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'] . + '", but may be compatible, use --force to install'); + } else { + return $this->warning('warning: %s dependency: PHP extension ' . + $dep['name'] . ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'].'"'); + } + } + } + return true; + } + + function validatePhpDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + $version = $this->phpversion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + if (isset($dep['min'])) { + if (!version_compare($version, $dep['min'], '>=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } else { + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } + } + } + if (isset($dep['max'])) { + if (!version_compare($version, $dep['max'], '<=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } else { + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } + } + } + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP version ' . + $exclude); + } else { + return $this->warning( + 'warning: %s is not compatible with PHP version ' . + $exclude); + } + } + } + } + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getPEARVersion() + { + return '1.7.2'; + } + + function validatePearinstallerDependency($dep) + { + $pearversion = $this->getPEARVersion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + if (version_compare($pearversion, $dep['min'], '<')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } else { + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + } + if (isset($dep['max'])) { + if (version_compare($pearversion, $dep['max'], '>')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } else { + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + } + } + if (isset($dep['exclude'])) { + if (!isset($dep['exclude'][0])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (version_compare($exclude, $pearversion, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PEAR Installer ' . + 'version ' . $exclude); + } else { + return $this->warning('warning: %s is not compatible with PEAR ' . + 'Installer version ' . $exclude); + } + } + } + } + return true; + } + + function validateSubpackageDependency($dep, $required, $params) + { + return $this->validatePackageDependency($dep, $required, $params); + } + + /** + * @param array dependency information (2.0 format) + * @param boolean whether this is a required dependency + * @param array a list of downloaded packages to be installed, if any + * @param boolean if true, then deps on pear.php.net that fail will also check + * against pecl.php.net packages to accomodate extensions that have + * moved to pecl.php.net from pear.php.net + */ + function validatePackageDependency($dep, $required, $params, $depv1 = false) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + if (isset($dep['providesextension'])) { + if ($this->extension_loaded($dep['providesextension'])) { + $save = $dep; + $subdep = $dep; + $subdep['name'] = $subdep['providesextension']; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->validateExtensionDependency($subdep, $required); + PEAR::popErrorHandling(); + if (!PEAR::isError($ret)) { + return true; + } + } + } + if ($this->_state == PEAR_VALIDATE_INSTALLING) { + return $this->_validatePackageInstall($dep, $required, $depv1); + } + if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { + return $this->_validatePackageDownload($dep, $required, $params, $depv1); + } + } + + function _validatePackageDownload($dep, $required, $params, $depv1 = false) + { + $dep['package'] = $dep['name']; + if (isset($dep['uri'])) { + $dep['channel'] = '__uri'; + } + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $found = false; + foreach ($params as $param) { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => $dep['channel']))) { + $found = true; + break; + } + if ($depv1 && $dep['channel'] == 'pear.php.net') { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => 'pecl.php.net'))) { + $found = true; + break; + } + } + } + if (!$found && isset($dep['providesextension'])) { + foreach ($params as $param) { + if ($param->isExtension($dep['providesextension'])) { + $found = true; + break; + } + } + } + if ($found) { + $version = $param->getVersion(); + $installed = false; + $downloaded = true; + } else { + if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + $dep['channel']); + } else { + if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], + 'pear.php.net')) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + 'pear.php.net'); + } else { + $version = 'not installed or downloaded'; + $installed = false; + $downloaded = false; + } + } + } + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude'])) { + if ($installed || $downloaded) { + $installed = $installed ? 'installed' : 'downloaded'; + if (isset($dep['conflicts'])) { + if ($version) { + $rest = ", $installed version is " . $version; + } else { + $rest = ''; + } + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . + $extra . $rest); + } else { + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . $rest); + } + } + return true; + } else { + if (isset($dep['conflicts'])) { + return true; + } + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra); + } else { + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra); + } + } else { + return $this->warning('%s can optionally use package "' . $depname . '"' . + $extra); + } + } + } + if (!$installed && !$downloaded) { + if (isset($dep['conflicts'])) { + return true; + } + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra); + } else { + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra); + } + } else { + return $this->warning('%s can optionally use package "' . $depname . '"' . + $extra); + } + } + $fail = false; + if (isset($dep['min'])) { + if (version_compare($version, $dep['min'], '<')) { + $fail = true; + } + } + if (isset($dep['max'])) { + if (version_compare($version, $dep['max'], '>')) { + $fail = true; + } + } + if ($fail && !isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + $dep['package'] = $dep['name']; + $dep = $this->_registry->parsedPackageNameToString($dep, true); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } else { + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && + isset($dep['conflicts']) && !isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . + ", $installed version is " . $version); + } else { + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } + if (isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } else { + return $this->warning('warning: %s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } else { + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } + } + } + if (isset($dep['recommended'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } else { + if (!$found && $installed) { + $param = $this->_registry->getPackage($dep['name'], $dep['channel']); + } + if ($param) { + $found = false; + foreach ($params as $parent) { + if ($parent->isEqual($this->_currentPackage)) { + $found = true; + break; + } + } + if ($found) { + if ($param->isCompatible($parent)) { + return true; + } + } else { // this is for validPackage() calls + $parent = $this->_registry->getPackage($this->_currentPackage['package'], + $this->_currentPackage['channel']); + if ($parent !== null) { + if ($param->isCompatible($parent)) { + return true; + } + } + } + } + if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && + !isset($this->_options['loose'])) { + return $this->raiseError('%s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended'] . + ', but may be compatible, use --force to install'); + } else { + return $this->warning('warning: %s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended']); + } + } + } + return true; + } + + function _validatePackageInstall($dep, $required, $depv1 = false) + { + return $this->_validatePackageDownload($dep, $required, array(), $depv1); + } + + /** + * Verify that uninstalling packages passed in to command line is OK. + * + * @param PEAR_Installer $dl + * @return PEAR_Error|true + */ + function validatePackageUninstall(&$dl) + { + if (PEAR::isError($this->_dependencydb)) { + return $this->_dependencydb; + } + $params = array(); + // construct an array of "downloaded" packages to fool the package dependency checker + // into using these to validate uninstalls of circular dependencies + $downloaded = &$dl->getUninstallPackages(); + foreach ($downloaded as $i => $pf) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $dp = &new PEAR_Downloader_Package($dl); + $dp->setPackageFile($downloaded[$i]); + $params[$i] = &$dp; + } + // check cache + $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . + strtolower($this->_currentPackage['package']); + if (isset($dl->___uninstall_package_cache)) { + $badpackages = $dl->___uninstall_package_cache; + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } else { + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } + } + return true; + } + // first, list the immediate parents of each package to be uninstalled + $perpackagelist = array(); + $allparents = array(); + foreach ($params as $i => $param) { + $a = array('channel' => strtolower($param->getChannel()), + 'package' => strtolower($param->getPackage())); + $deps = $this->_dependencydb->getDependentPackages($a); + if ($deps) { + foreach ($deps as $d) { + $pardeps = $this->_dependencydb->getDependencies($d); + foreach ($pardeps as $dep) { + if (strtolower($dep['dep']['channel']) == $a['channel'] && + strtolower($dep['dep']['name']) == $a['package']) { + if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { + $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); + } + $perpackagelist[$a['channel'] . '/' . $a['package']][] + = array($d['channel'] . '/' . $d['package'], $dep); + if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { + $allparents[$d['channel'] . '/' . $d['package']] = array(); + } + if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { + $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); + } + $allparents[$d['channel'] . '/' . $d['package']] + [$a['channel'] . '/' . $a['package']][] + = array($d, $dep); + } + } + } + } + } + // next, remove any packages from the parents list that are not installed + $remove = array(); + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { + continue; + } + $remove[$parent] = true; + } + } + // next remove any packages from the parents list that are not passed in for + // uninstallation + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + foreach ($params as $param) { + if (strtolower($param->getChannel()) == $d[0][0]['channel'] && + strtolower($param->getPackage()) == $d[0][0]['package']) { + // found it + continue 3; + } + } + $remove[$parent] = true; + } + } + // remove all packages whose dependencies fail + // save which ones failed for error reporting + $badchildren = array(); + do { + $fail = false; + foreach ($remove as $package => $unused) { + if (!isset($allparents[$package])) { + continue; + } + foreach ($allparents[$package] as $kid => $d1) { + foreach ($d1 as $depinfo) { + if ($depinfo[1]['type'] != 'optional') { + if (isset($badchildren[$kid])) { + continue; + } + $badchildren[$kid] = true; + $remove[$kid] = true; + $fail = true; + continue 2; + } + } + } + if ($fail) { + // start over, we removed some children + continue 2; + } + } + } while ($fail); + // next, construct the list of packages that can't be uninstalled + $badpackages = array(); + $save = $this->_currentPackage; + foreach ($perpackagelist as $package => $packagedeps) { + foreach ($packagedeps as $parent) { + if (!isset($remove[$parent[0]])) { + continue; + } + $packagename = $this->_registry->parsePackageName($parent[0]); + $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); + $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); + $packagename['package'] = $pa->getPackage(); + $this->_currentPackage = $packagename; + // parent is not present in uninstall list, make sure we can actually + // uninstall it (parent dep is optional) + $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); + $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); + $parentname['package'] = $pa->getPackage(); + $parent[1]['dep']['package'] = $parentname['package']; + $parent[1]['dep']['channel'] = $parentname['channel']; + if ($parent[1]['type'] == 'optional') { + $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); + if ($test !== true) { + $badpackages[$package]['warnings'][] = $test; + } + } else { + $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); + if ($test !== true) { + $badpackages[$package]['errors'][] = $test; + } + } + } + } + $this->_currentPackage = $save; + $dl->___uninstall_package_cache = $badpackages; + if (isset($badpackages[$memyselfandI])) { + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } else { + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } + } + } + return true; + } + + function _validatePackageUninstall($dep, $required, $dl) + { + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $version = $this->_registry->packageinfo($dep['package'], 'version', + $dep['channel']); + if (!$version) { + return true; + } + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + if (isset($dep['conflicts'])) { + return true; // uninstall OK - these packages conflict (probably installed with --force) + } + if (!isset($dep['min']) && !isset($dep['max'])) { + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('"' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } else { + return $this->warning('warning: "' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } + } else { + return $this->warning('"' . $depname . '" can be optionally used by ' . + 'installed package %s' . $extra); + } + } + $fail = false; + if (isset($dep['min'])) { + if (version_compare($version, $dep['min'], '>=')) { + $fail = true; + } + } + if (isset($dep['max'])) { + if (version_compare($version, $dep['max'], '<=')) { + $fail = true; + } + } + // we re-use this variable, preserve the original value + $saverequired = $required; + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError($depname . $extra . ' is required by installed package' . + ' "%s"'); + } else { + return $this->raiseError('warning: ' . $depname . $extra . + ' is required by installed package "%s"'); + } + } else { + return $this->warning($depname . $extra . ' can be optionally used by installed package' . + ' "%s"'); + } + return true; + } + + /** + * validate a downloaded package against installed packages + * + * As of PEAR 1.4.3, this will only validate + * + * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * $pkg package identifier (either + * array('package' => blah, 'channel' => blah) or an array with + * index 'info' referencing an object) + * @param PEAR_Downloader $dl + * @param array $params full list of packages to install + * @return true|PEAR_Error + */ + function validatePackage($pkg, &$dl, $params = array()) + { + if (is_array($pkg) && isset($pkg['info'])) { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); + } else { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); + } + $fail = false; + if ($deps) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $dp = &new PEAR_Downloader_Package($dl); + if (is_object($pkg)) { + $dp->setPackageFile($pkg); + } else { + $dp->setDownloadURL($pkg); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($deps as $channel => $info) { + foreach ($info as $package => $ds) { + foreach ($params as $packd) { + if (strtolower($packd->getPackage()) == strtolower($package) && + $packd->getChannel() == $channel) { + $dl->log(3, 'skipping installed package check of "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $channel, 'package' => $package), + true) . + '", version "' . $packd->getVersion() . '" will be ' . + 'downloaded and installed'); + continue 2; // jump to next package + } + } + foreach ($ds as $d) { + $checker = &new PEAR_Dependency2($this->_config, $this->_options, + array('channel' => $channel, 'package' => $package), $this->_state); + $dep = $d['dep']; + $required = $d['type'] == 'required'; + $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); + if (is_array($ret)) { + $dl->log(0, $ret[0]); + } elseif (PEAR::isError($ret)) { + $dl->log(0, $ret->getMessage()); + $fail = true; + } + } + } + } + PEAR::popErrorHandling(); + } + if ($fail) { + return $this->raiseError( + '%s cannot be installed, conflicts with installed packages'); + } + return true; + } + + /** + * validate a package.xml 1.0 dependency + */ + function validateDependency1($dep, $params = array()) + { + if (!isset($dep['optional'])) { + $dep['optional'] = 'no'; + } + list($newdep, $type) = $this->normalizeDep($dep); + if (!$newdep) { + return $this->raiseError("Invalid Dependency"); + } + if (method_exists($this, "validate{$type}Dependency")) { + return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', + $params, true); + } + } + + /** + * Convert a 1.0 dep into a 2.0 dep + */ + function normalizeDep($dep) + { + $types = array( + 'pkg' => 'Package', + 'ext' => 'Extension', + 'os' => 'Os', + 'php' => 'Php' + ); + if (isset($types[$dep['type']])) { + $type = $types[$dep['type']]; + } else { + return array(false, false); + } + $newdep = array(); + switch ($type) { + case 'Package' : + $newdep['channel'] = 'pear.php.net'; + case 'Extension' : + case 'Os' : + $newdep['name'] = $dep['name']; + break; + } + $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); + switch ($dep['rel']) { + case 'has' : + return array($newdep, $type); + break; + case 'not' : + $newdep['conflicts'] = true; + break; + case '>=' : + case '>' : + $newdep['min'] = $dep['version']; + if ($dep['rel'] == '>') { + $newdep['exclude'] = $dep['version']; + } + break; + case '<=' : + case '<' : + $newdep['max'] = $dep['version']; + if ($dep['rel'] == '<') { + $newdep['exclude'] = $dep['version']; + } + break; + case 'ne' : + case '!=' : + $newdep['min'] = '0'; + $newdep['max'] = '100000'; + $newdep['exclude'] = $dep['version']; + break; + case '==' : + $newdep['min'] = $dep['version']; + $newdep['max'] = $dep['version']; + break; + } + if ($type == 'Php') { + if (!isset($newdep['min'])) { + $newdep['min'] = '4.2.0'; + } + if (!isset($newdep['max'])) { + $newdep['max'] = '6.0.0'; + } + } + return array($newdep, $type); + } + + /** + * Converts text comparing operators to them sign equivalents + * + * Example: 'ge' to '>=' + * + * @access public + * @param string Operator + * @return string Sign equivalent + */ + function signOperator($operator) + { + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; + } + } + + function raiseError($msg) + { + if (isset($this->_options['ignore-errors'])) { + return $this->warning($msg); + } + return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } + + function warning($msg) + { + return array(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/DependencyDB.php b/vas/rest/class/PEAR/DependencyDB.php new file mode 100755 index 0000000000000000000000000000000000000000..f79ae81e31311cc3b59af0b668b8bc1b6621c130 --- /dev/null +++ b/vas/rest/class/PEAR/DependencyDB.php @@ -0,0 +1,713 @@ +<?php +/** + * PEAR_DependencyDB, advanced installed packages dependency database + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: DependencyDB.php,v 1.37 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); +/** + * Track dependency relationships between installed packages + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Tomas V.V.Cox <cox@idec.net.com> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_DependencyDB +{ + // {{{ properties + + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Config + * @access private + */ + var $_config; + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Registry + * @access private + */ + var $_registry; + /** + * Filename of the dependency DB (usually .depdb) + * @var string + * @access private + */ + var $_depdb = false; + /** + * File name of the lockfile (usually .depdblock) + * @var string + * @access private + */ + var $_lockfile = false; + /** + * Open file resource for locking the lockfile + * @var resource|false + * @access private + */ + var $_lockFp = false; + /** + * API version of this class, used to validate a file on-disk + * @var string + * @access private + */ + var $_version = '1.0'; + /** + * Cached dependency database file + * @var array|null + * @access private + */ + var $_cache; + + // }}} + // {{{ & singleton() + + /** + * Get a raw dependency database. Calls setConfig() and assertDepsDB() + * @param PEAR_Config + * @param string|false full path to the dependency database, or false to use default + * @return PEAR_DependencyDB|PEAR_Error + * @static + */ + function &singleton(&$config, $depdb = false) + { + if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] + [$config->get('php_dir', null, 'pear.php.net')])) { + $a = new PEAR_DependencyDB; + $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] + [$config->get('php_dir', null, 'pear.php.net')] = &$a; + $a->setConfig($config, $depdb); + if (PEAR::isError($e = $a->assertDepsDB())) { + return $e; + } + } + return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] + [$config->get('php_dir', null, 'pear.php.net')]; + } + + /** + * Set up the registry/location of dependency DB + * @param PEAR_Config|false + * @param string|false full path to the dependency database, or false to use default + */ + function setConfig(&$config, $depdb = false) + { + if (!$config) { + $this->_config = &PEAR_Config::singleton(); + } else { + $this->_config = &$config; + } + $this->_registry = &$this->_config->getRegistry(); + if (!$depdb) { + $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'; + } else { + $this->_depdb = $depdb; + } + $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; + } + // }}} + + function hasWriteAccess() + { + if (!file_exists($this->_depdb)) { + $dir = $this->_depdb; + while ($dir && $dir != '.') { + $dir = dirname($dir); // cd .. + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } else { + return false; + } + } + } + return false; + } + return is_writeable($this->_depdb); + } + + // {{{ assertDepsDB() + + /** + * Create the dependency database, if it doesn't exist. Error if the database is + * newer than the code reading it. + * @return void|PEAR_Error + */ + function assertDepsDB() + { + if (!is_file($this->_depdb)) { + $this->rebuildDB(); + } else { + $depdb = $this->_getDepDB(); + // Datatype format has been changed, rebuild the Deps DB + if ($depdb['_version'] < $this->_version) { + $this->rebuildDB(); + } + if ($depdb['_version']{0} > $this->_version{0}) { + return PEAR::raiseError('Dependency database is version ' . + $depdb['_version'] . ', and we are version ' . + $this->_version . ', cannot continue'); + } + } + } + + /** + * Get a list of installed packages that depend on this package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependentPackages(&$pkg) + { + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + if (isset($data['packages'][$channel][$package])) { + return $data['packages'][$channel][$package]; + } + return false; + } + + /** + * Get a list of the actual dependencies of installed packages that depend on + * a package. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependentPackageDependencies(&$pkg) + { + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + $depend = $this->getDependentPackages($pkg); + if (!$depend) { + return false; + } + $dependencies = array(); + foreach ($depend as $info) { + $temp = $this->getDependencies($info); + foreach ($temp as $dep) { + if (strtolower($dep['dep']['channel']) == strtolower($channel) && + strtolower($dep['dep']['name']) == strtolower($package)) { + if (!isset($dependencies[$info['channel']])) { + $dependencies[$info['channel']] = array(); + } + if (!isset($dependencies[$info['channel']][$info['package']])) { + $dependencies[$info['channel']][$info['package']] = array(); + } + $dependencies[$info['channel']][$info['package']][] = $dep; + } + } + } + return $dependencies; + } + + /** + * Get a list of dependencies of this installed package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependencies(&$pkg) + { + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + $data = $this->_getDepDB(); + if (isset($data['dependencies'][$channel][$package])) { + return $data['dependencies'][$channel][$package]; + } + return false; + } + + /** + * Determine whether $parent depends on $child, near or deep + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function dependsOn($parent, $child) + { + $c = array(); + $this->_getDepDB(); + return $this->_dependsOn($parent, $child, $c); + } + + function _dependsOn($parent, $child, &$checked) + { + if (is_object($parent)) { + $channel = strtolower($parent->getChannel()); + $package = strtolower($parent->getPackage()); + } else { + $channel = strtolower($parent['channel']); + $package = strtolower($parent['package']); + } + if (is_object($child)) { + $depchannel = strtolower($child->getChannel()); + $deppackage = strtolower($child->getPackage()); + } else { + $depchannel = strtolower($child['channel']); + $deppackage = strtolower($child['package']); + } + if (isset($checked[$channel][$package][$depchannel][$deppackage])) { + return false; // avoid endless recursion + } + $checked[$channel][$package][$depchannel][$deppackage] = true; + if (!isset($this->_cache['dependencies'][$channel][$package])) { + return false; + } + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if (is_object($child)) { + if ($info['dep']['uri'] == $child->getURI()) { + return true; + } + } elseif (isset($child['uri'])) { + if ($info['dep']['uri'] == $child['uri']) { + return true; + } + } + return false; + } + if (strtolower($info['dep']['channel']) == strtolower($depchannel) && + strtolower($info['dep']['name']) == strtolower($deppackage)) { + return true; + } + } + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if ($this->_dependsOn(array( + 'uri' => $info['dep']['uri'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } else { + if ($this->_dependsOn(array( + 'channel' => $info['dep']['channel'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } + } + return false; + } + + /** + * Register dependencies of a package that is being installed or upgraded + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function installPackage(&$package) + { + $data = $this->_getDepDB(); + unset($this->_cache); + $this->_setPackageDeps($data, $package); + $this->_writeDepDB($data); + } + + /** + * Remove dependencies of a package that is being uninstalled, or upgraded. + * + * Upgraded packages first uninstall, then install + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have + * indices 'channel' and 'package' + */ + function uninstallPackage(&$pkg) + { + $data = $this->_getDepDB(); + unset($this->_cache); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + if (!isset($data['dependencies'][$channel][$package])) { + return true; + } + foreach ($data['dependencies'][$channel][$package] as $dep) { + $found = false; + if (isset($dep['dep']['uri'])) { + $depchannel = '__uri'; + } else { + $depchannel = strtolower($dep['dep']['channel']); + } + if (isset($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) { + foreach ($data['packages'][$depchannel][strtolower($dep['dep']['name'])] as + $i => $info) { + if ($info['channel'] == $channel && + $info['package'] == $package) { + $found = true; + break; + } + } + } + if ($found) { + unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])][$i]); + if (!count($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) { + unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])]); + if (!count($data['packages'][$depchannel])) { + unset($data['packages'][$depchannel]); + } + } else { + $data['packages'][$depchannel][strtolower($dep['dep']['name'])] = + array_values( + $data['packages'][$depchannel][strtolower($dep['dep']['name'])]); + } + } + } + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } + if (!count($data['dependencies'])) { + unset($data['dependencies']); + } + if (!count($data['packages'])) { + unset($data['packages']); + } + $this->_writeDepDB($data); + } + + /** + * Rebuild the dependency DB by reading registry entries. + * @return true|PEAR_Error + */ + function rebuildDB() + { + $depdb = array('_version' => $this->_version); + if (!$this->hasWriteAccess()) { + // allow startup for read-only with older Registry + return $depdb; + } + $packages = $this->_registry->listAllPackages(); + if (PEAR::isError($packages)) { + return $packages; + } + foreach ($packages as $channel => $ps) { + foreach ($ps as $package) { + $package = $this->_registry->getPackage($package, $channel); + if (PEAR::isError($package)) { + return $package; + } + $this->_setPackageDeps($depdb, $package); + } + } + $error = $this->_writeDepDB($depdb); + if (PEAR::isError($error)) { + return $error; + } + $this->_cache = $depdb; + return true; + } + + /** + * Register usage of the dependency DB to prevent race conditions + * @param int one of the LOCK_* constants + * @return true|PEAR_Error + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (!eregi('Windows 9', php_uname())) { + if ($mode != LOCK_UN && is_resource($this->_lockFp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH) { + if (!file_exists($this->_lockfile)) { + touch($this->_lockfile); + } elseif (!is_file($this->_lockfile)) { + return PEAR::raiseError('could not create Dependency lock file, ' . + 'it exists and is not a regular file'); + } + $open_mode = 'r'; + } + + if (!is_resource($this->_lockFp)) { + $this->_lockFp = @fopen($this->_lockfile, $open_mode); + } + if (!is_resource($this->_lockFp)) { + return PEAR::raiseError("could not create Dependency lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + if (!(int)flock($this->_lockFp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); + } + } + return true; + } + + /** + * Release usage of dependency DB + * @return true|PEAR_Error + * @access private + */ + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->_lockFp)) { + fclose($this->_lockFp); + } + $this->_lockFp = null; + return $ret; + } + + /** + * Load the dependency database from disk, or return the cache + * @return array|PEAR_Error + */ + function _getDepDB() + { + if (!$this->hasWriteAccess()) { + return array('_version' => $this->_version); + } + if (isset($this->_cache)) { + return $this->_cache; + } + if (!$fp = fopen($this->_depdb, 'r')) { + $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); + return $err; + } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + fclose($fp); + $data = unserialize(file_get_contents($this->_depdb)); + set_magic_quotes_runtime($rt); + $this->_cache = $data; + return $data; + } + + /** + * Write out the dependency database to disk + * @param array the database + * @return true|PEAR_Error + * @access private + */ + function _writeDepDB(&$deps) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + if (!$fp = fopen($this->_depdb, 'wb')) { + $this->_unlock(); + return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); + } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fwrite($fp, serialize($deps)); + set_magic_quotes_runtime($rt); + fclose($fp); + $this->_unlock(); + $this->_cache = $deps; + return true; + } + + /** + * Register all dependencies from a package in the dependencies database, in essence + * "installing" the package's dependency information + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @access private + */ + function _setPackageDeps(&$data, &$pkg) + { + $pkg->setConfig($this->_config); + if ($pkg->getPackagexmlVersion() == '1.0') { + $gen = &$pkg->getDefaultGenerator(); + $deps = $gen->dependenciesToV2(); + } else { + $deps = $pkg->getDeps(true); + } + if (!$deps) { + return; + } + if (!is_array($data)) { + $data = array(); + } + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } + if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) { + $data['dependencies'][strtolower($pkg->getChannel())] = array(); + } + $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())] + = array(); + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } + foreach ($deps['required']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + foreach ($deps['optional']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } + if (isset($deps['required']['subpackage'])) { + if (!isset($deps['required']['subpackage'][0])) { + $deps['required']['subpackage'] = array($deps['required']['subpackage']); + } + foreach ($deps['required']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } + if (isset($deps['optional']['subpackage'])) { + if (!isset($deps['optional']['subpackage'][0])) { + $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); + } + foreach ($deps['optional']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + foreach ($deps['group'] as $group) { + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } + foreach ($group['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } + foreach ($group['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } + } + } + if ($data['dependencies'][strtolower($pkg->getChannel())] + [strtolower($pkg->getPackage())] == array()) { + unset($data['dependencies'][strtolower($pkg->getChannel())] + [strtolower($pkg->getPackage())]); + if (!count($data['dependencies'][strtolower($pkg->getChannel())])) { + unset($data['dependencies'][strtolower($pkg->getChannel())]); + } + } + } + + /** + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array the specific dependency + * @param required|optional whether this is a required or an optional dep + * @param string|false dependency group this dependency is from, or false for ordinary dep + */ + function _registerDep(&$data, &$pkg, $dep, $type, $group = false) + { + $info = array( + 'dep' => $dep, + 'type' => $type, + 'group' => $group); + + if (isset($dep['channel'])) { + $depchannel = $dep['channel']; + } else { + $depchannel = '__uri'; + } + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } + if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) { + $data['dependencies'][strtolower($pkg->getChannel())] = array(); + } + if (!isset($data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())])) { + $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())] = array(); + } + $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())][] + = $info; + if (isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) { + $found = false; + foreach ($data['packages'][strtolower($depchannel)][strtolower($dep['name'])] + as $i => $p) { + if ($p['channel'] == strtolower($pkg->getChannel()) && + $p['package'] == strtolower($pkg->getPackage())) { + $found = true; + break; + } + } + if (!$found) { + $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][] + = array('channel' => strtolower($pkg->getChannel()), + 'package' => strtolower($pkg->getPackage())); + } + } else { + if (!isset($data['packages'])) { + $data['packages'] = array(); + } + if (!isset($data['packages'][strtolower($depchannel)])) { + $data['packages'][strtolower($depchannel)] = array(); + } + if (!isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) { + $data['packages'][strtolower($depchannel)][strtolower($dep['name'])] = array(); + } + $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][] + = array('channel' => strtolower($pkg->getChannel()), + 'package' => strtolower($pkg->getPackage())); + } + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Downloader.php b/vas/rest/class/PEAR/Downloader.php new file mode 100755 index 0000000000000000000000000000000000000000..c70a07b19fa0881b0c18a54cef101c8c5809fbfb --- /dev/null +++ b/vas/rest/class/PEAR/Downloader.php @@ -0,0 +1,1752 @@ +<?php +/** + * PEAR_Downloader, the PEAR Installer's download utility class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Martin Jansen <mj@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Downloader.php,v 1.138 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.0 + */ + +/** + * Needed for constants, extending + */ +require_once 'PEAR/Common.php'; + +define('PEAR_INSTALLER_OK', 1); +define('PEAR_INSTALLER_FAILED', 0); +define('PEAR_INSTALLER_SKIPPED', -1); +define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + +/** + * Administration class used to download anything from the internet (PEAR Packages, + * static URLs, xml files) + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Martin Jansen <mj@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.0 + */ +class PEAR_Downloader extends PEAR_Common +{ + /** + * @var PEAR_Registry + * @access private + */ + var $_registry; + + /** + * @var PEAR_Remote + * @access private + */ + var $_remote; + + /** + * Preferred Installation State (snapshot, devel, alpha, beta, stable) + * @var string|null + * @access private + */ + var $_preferredState; + + /** + * Options from command-line passed to Install. + * + * Recognized options:<br /> + * - onlyreqdeps : install all required dependencies as well + * - alldeps : install all dependencies, including optional + * - installroot : base relative path to install files in + * - force : force a download even if warnings would prevent it + * - nocompress : download uncompressed tarballs + * @see PEAR_Command_Install + * @access private + * @var array + */ + var $_options; + + /** + * Downloaded Packages after a call to download(). + * + * Format of each entry: + * + * <code> + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * </code> + * @access private + * @var array + */ + var $_downloadedPackages = array(); + + /** + * Packages slated for download. + * + * This is used to prevent downloading a package more than once should it be a dependency + * for two packages to be installed. + * Format of each entry: + * + * <pre> + * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml, + * ); + * </pre> + * @access private + * @var array + */ + var $_toDownload = array(); + + /** + * Array of every package installed, with names lower-cased. + * + * Format: + * <code> + * array('package1' => 0, 'package2' => 1, ); + * </code> + * @var array + */ + var $_installed = array(); + + /** + * @var array + * @access private + */ + var $_errorStack = array(); + + /** + * @var boolean + * @access private + */ + var $_internalDownload = false; + + /** + * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} + * @var array + * @access private + */ + var $_packageSortTree; + + /** + * Temporary directory, or configuration value where downloads will occur + * @var string + */ + var $_downloadDir; + // {{{ PEAR_Downloader() + + /** + * @param PEAR_Frontend_* + * @param array + * @param PEAR_Config + */ + function PEAR_Downloader(&$ui, $options, &$config) + { + parent::PEAR_Common(); + $this->_options = $options; + $this->config = &$config; + $this->_preferredState = $this->config->get('preferred_state'); + $this->ui = &$ui; + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + + if (isset($this->_options['installroot'])) { + $this->config->setInstallRoot($this->_options['installroot']); + } + $this->_registry = &$config->getRegistry(); + $this->_remote = &$config->getRemote(); + + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $this->_installed = $this->_registry->listAllPackages(); + foreach ($this->_installed as $key => $unused) { + if (!count($unused)) { + continue; + } + $strtolower = create_function('$a','return strtolower($a);'); + array_walk($this->_installed[$key], $strtolower); + } + } + } + + /** + * Attempt to discover a channel's remote capabilities from + * its server name + * @param string + * @return boolean + */ + function discover($channel) + { + $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $callback = $this->ui ? array(&$this, '_downloadCallback') : null; + if (!class_exists('System')) { + require_once 'System.php'; + } + $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, + System::mktemp(array('-d')), $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + return false; + } + list($a, $lastmodified) = $a; + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $b = new PEAR_ChannelFile; + if ($b->fromXmlFile($a)) { + unlink($a); + if ($this->config->get('auto_discover')) { + $this->_registry->addChannel($b, $lastmodified); + $alias = $b->getName(); + if ($b->getName() == $this->_registry->channelName($b->getAlias())) { + $alias = $b->getAlias(); + } + $this->log(1, 'Auto-discovered channel "' . $channel . + '", alias "' . $alias . '", adding to registry'); + } + return true; + } + unlink($a); + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Downloader + * @return PEAR_Downloader_Package + */ + function &newDownloaderPackage(&$t) + { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $a = &new PEAR_Downloader_Package($t); + return $a; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param array + * @param array + * @param int + */ + function &getDependency2Object(&$c, $i, $p, $s) + { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $z = &new PEAR_Dependency2($c, $i, $p, $s); + return $z; + } + + function &download($params) + { + if (!count($params)) { + $a = array(); + return $a; + } + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + if (!isset($this->_remote)) { + $this->_remote = &$this->config->getRemote(); + } + $channelschecked = array(); + // convert all parameters into PEAR_Downloader_Package objects + foreach ($params as $i => $param) { + $params[$i] = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $params[$i]->initialize($param); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + continue; + } + if (PEAR::isError($err)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $err->getMessage()); + } + $params[$i] = false; + if (is_object($param)) { + $param = $param->getChannel() . '/' . $param->getPackage(); + } + $this->pushError('Package "' . $param . '" is not valid', + PEAR_INSTALLER_SKIPPED); + } else { + do { + if ($params[$i] && $params[$i]->getType() == 'local') { + // bug #7090 + // skip channel.xml check for local packages + break; + } + if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && + !isset($this->_options['offline'])) { + $channelschecked[$params[$i]->getChannel()] = true; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('System')) { + require_once 'System.php'; + } + $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); + if (PEAR::isError($curchannel)) { + PEAR::staticPopErrorHandling(); + return $this->raiseError($curchannel); + } + if (PEAR::isError($dir = $this->getDownloadDir())) { + PEAR::staticPopErrorHandling(); + break; + } + $mirror = $this->config->get('preferred_mirror', null, + $params[$i]->getChannel()); + $a = $this->downloadHttp('http://' . $mirror . + '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + break; + } + $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . + 'updated its protocols, use "channel-update ' . $params[$i]->getChannel() . + '" to update'); + } + } while (false); + if ($params[$i] && !isset($this->_options['downloadonly'])) { + if (isset($this->_options['packagingroot'])) { + $checkdir = $this->_prependPath( + $this->config->get('php_dir', null, $params[$i]->getChannel()), + $this->_options['packagingroot']); + } else { + $checkdir = $this->config->get('php_dir', + null, $params[$i]->getChannel()); + } + while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { + $checkdir = dirname($checkdir); + } + if ($checkdir == '.') { + $checkdir = '/'; + } + if (!is_writeable($checkdir)) { + return PEAR::raiseError('Cannot install, php_dir for channel "' . + $params[$i]->getChannel() . '" is not writeable by the current user'); + } + } + } + } + unset($channelschecked); + PEAR_Downloader_Package::removeDuplicates($params); + if (!count($params)) { + $a = array(); + return $a; + } + if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { + $reverify = true; + while ($reverify) { + $reverify = false; + foreach ($params as $i => $param) { + //PHP Bug 40768 / PEAR Bug #10944 + //Nested foreaches fail in PHP 5.2.1 + key($params); + $ret = $params[$i]->detectDependencies($params); + if (PEAR::isError($ret)) { + $reverify = true; + $params[$i] = false; + PEAR_Downloader_Package::removeDuplicates($params); + if (!isset($this->_options['soft'])) { + $this->log(0, $ret->getMessage()); + } + continue 2; + } + } + } + } + if (isset($this->_options['offline'])) { + $this->log(3, 'Skipping dependency download check, --offline specified'); + } + if (!count($params)) { + $a = array(); + return $a; + } + while (PEAR_Downloader_Package::mergeDependencies($params)); + PEAR_Downloader_Package::removeDuplicates($params, true); + $errorparams = array(); + if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { + if (count($errorparams)) { + foreach ($errorparams as $param) { + $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); + $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); + } + $a = array(); + return $a; + } + } + PEAR_Downloader_Package::removeInstalled($params); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($params); + PEAR::popErrorHandling(); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + $ret = array(); + $newparams = array(); + if (isset($this->_options['pretend'])) { + return $params; + } + $somefailed = false; + foreach ($params as $i => $package) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$params[$i]->download(); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (!isset($this->_options['soft'])) { + $this->log(1, $pf->getMessage()); + $this->log(0, 'Error: cannot download "' . + $this->_registry->parsedPackageNameToString($package->getParsedPackage(), + true) . + '"'); + } + $somefailed = true; + continue; + } + $newparams[] = &$params[$i]; + $ret[] = array('file' => $pf->getArchiveFile(), + 'info' => &$pf, + 'pkg' => $pf->getPackage()); + } + if ($somefailed) { + // remove params that did not download successfully + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($newparams, true); + PEAR::popErrorHandling(); + if (!count($newparams)) { + $this->pushError('Download failed', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + } + $this->_downloadedPackages = $ret; + return $newparams; + } + + /** + * @param array all packages to be installed + */ + function analyzeDependencies(&$params, $force = false) + { + $hasfailed = $failed = false; + if (isset($this->_options['downloadonly'])) { + return; + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $redo = true; + $reset = false; + while ($redo) { + $redo = false; + foreach ($params as $i => $param) { + $deps = $param->getDeps(); + if (!$deps) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + if ($param->getType() == 'xmlrpc') { + $send = $param->getDownloadURL(); + } else { + $send = $param->getPackageFile(); + } + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + continue; + } + if (!$reset && $param->alreadyValidated() && !$force) { + continue; + } + if (count($deps)) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + if ($param->getType() == 'xmlrpc') { + $send = $param->getDownloadURL(); + } else { + $send = $param->getPackageFile(); + } + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + $failed = false; + if (isset($deps['required'])) { + foreach ($deps['required'] as $type => $dep) { + // note: Dependency2 will never return a PEAR_Error if ignore-errors + // is specified, so soft is needed to turn off logging + if (!isset($dep[0])) { + if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + if (isset($deps['optional'])) { + foreach ($deps['optional'] as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + $groupname = $param->getGroup(); + if (isset($deps['group']) && $groupname) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + $found = false; + foreach ($deps['group'] as $group) { + if ($group['attribs']['name'] == $groupname) { + $found = true; + break; + } + } + if ($found) { + unset($group['attribs']); + foreach ($group as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + } + } else { + foreach ($deps as $dep) { + if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + $params[$i]->setValidated(); + } + if ($failed) { + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + } + } + PEAR::staticPopErrorHandling(); + if ($hasfailed && (isset($this->_options['ignore-errors']) || + isset($this->_options['nodeps']))) { + // this is probably not needed, but just in case + if (!isset($this->_options['soft'])) { + $this->log(0, 'WARNING: dependencies failed'); + } + } + } + + /** + * Retrieve the directory that downloads will happen in + * @access private + * @return string + */ + function getDownloadDir() + { + if (isset($this->_downloadDir)) { + return $this->_downloadDir; + } + $downloaddir = $this->config->get('download_dir'); + if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { + if (is_dir($downloaddir) && !is_writable($downloaddir)) { + $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir to avoid this warning'); + } + if (!class_exists('System')) { + require_once 'System.php'; + } + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $this->log(3, '+ tmp dir created at ' . $downloaddir); + } + if (!is_writable($downloaddir)) { + if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || + !is_writable($downloaddir)) { + return PEAR::raiseError('download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); + } + } + return $this->_downloadDir = $downloaddir; + } + + function setDownloadDir($dir) + { + if (!@is_writable($dir)) { + if (PEAR::isError(System::mkdir(array('-p', $dir)))) { + return PEAR::raiseError('download directory "' . $dir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); + } + } + $this->_downloadDir = $dir; + } + + // }}} + // {{{ configSet() + function configSet($key, $value, $layer = 'user', $channel = false) + { + $this->config->set($key, $value, $layer, $channel); + $this->_preferredState = $this->config->get('preferred_state', null, $channel); + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + } + + // }}} + // {{{ setOptions() + function setOptions($options) + { + $this->_options = $options; + } + + // }}} + // {{{ setOptions() + function getOptions() + { + return $this->_options; + } + + // }}} + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string + */ + function &getPackagefileObject(&$c, $d, $t = false) + { + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $a = &new PEAR_PackageFile($c, $d, $t); + return $a; + } + + // {{{ _getPackageDownloadUrl() + + /** + * @param array output of {@link parsePackageName()} + * @access private + */ + function _getPackageDownloadUrl($parr) + { + $curchannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $parr['channel']); + // getDownloadURL returns an array. On error, it only contains information + // on the latest release as array(version, info). On success it contains + // array(version, info, download url string) + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (!$this->_registry->channelExists($parr['channel'])) { + do { + if ($this->config->get('auto_discover')) { + if ($this->discover($parr['channel'])) { + break; + } + } + $this->configSet('default_channel', $curchannel); + return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); + } while (false); + } + $chan = &$this->_registry->getChannel($parr['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $version = $this->_registry->packageInfo($parr['package'], 'version', + $parr['channel']); + PEAR::staticPopErrorHandling(); + $base2 = false; + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + (($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror'))) || + ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))))) { + if ($base2) { + $rest = &$this->config->getREST('1.3', $this->_options); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', $this->_options); + } + if (!isset($parr['version']) && !isset($parr['state']) && $version + && !PEAR::isError($version) + && !isset($this->_options['downloadonly'])) { + $url = $rest->getDownloadURL($base, $parr, $state, $version, $chan->getName()); + } else { + $url = $rest->getDownloadURL($base, $parr, $state, false, $chan->getName()); + } + if (PEAR::isError($url)) { + $this->configSet('default_channel', $curchannel); + return $url; + } + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + if (!is_array($url)) { + return $url; + } + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); + } + if (!isset($this->_options['force']) && + !isset($this->_options['downloadonly']) && + $version && + !PEAR::isError($version) && + !isset($parr['group'])) { + if (version_compare($version, $url['version'], '>=')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is newer than detected ' . + 'release version ' . $url['version'], -976); + } + } + if (isset($url['info']['required']) || $url['compatible']) { + require_once 'PEAR/PackageFile/v2.php'; + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($parr['channel']); + if ($url['compatible']) { + $pf->setRawCompatible($url['compatible']); + } + } else { + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + } + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + if (is_array($url)) { + if (isset($url['url'])) { + $url['url'] .= $ext; + } + } + return $url; + } elseif ($chan->supports('xmlrpc', 'package.getDownloadURL', false, '1.1')) { + // don't install with the old version information unless we're doing a plain + // vanilla simple installation. If the user says to install a particular + // version or state, ignore the current installed version + if (!isset($parr['version']) && !isset($parr['state']) && $version + && !isset($this->_options['downloadonly'])) { + $url = $this->_remote->call('package.getDownloadURL', $parr, $state, $version); + } else { + $url = $this->_remote->call('package.getDownloadURL', $parr, $state); + } + } else { + $url = $this->_remote->call('package.getDownloadURL', $parr, $state); + } + if (PEAR::isError($url)) { + return $url; + } + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + if (isset($url['__PEAR_ERROR_CLASS__'])) { + return PEAR::raiseError($url['message']); + } + if (!is_array($url)) { + return $url; + } + $url['raw'] = $url['info']; + if (isset($this->_options['downloadonly'])) { + $pkg = &$this->getPackagefileObject($this->config, $this->debug); + } else { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $this->getDownloadDir())) { + PEAR::staticPopErrorHandling(); + return $dir; + } + PEAR::staticPopErrorHandling(); + $pkg = &$this->getPackagefileObject($this->config, $this->debug, $dir); + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote'); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pinfo)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $pinfo->getMessage()); + } + return PEAR::raiseError('Remote package.xml is not valid - this should never happen'); + } + $url['info'] = &$pinfo; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + if (is_array($url)) { + if (isset($url['url'])) { + $url['url'] .= $ext; + } + } + return $url; + } + // }}} + // {{{ getDepPackageDownloadUrl() + + /** + * @param array dependency array + * @access private + */ + function _getDepPackageDownloadUrl($dep, $parr) + { + $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; + $curchannel = $this->config->get('default_channel'); + if (isset($dep['uri'])) { + $xsdversion = '2.0'; + $chan = &$this->_registry->getChannel('__uri'); + if (PEAR::isError($chan)) { + return $chan; + } + $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); + $this->configSet('default_channel', '__uri'); + } else { + if (isset($dep['channel'])) { + $remotechannel = $dep['channel']; + } else { + $remotechannel = 'pear.php.net'; + } + if (!$this->_registry->channelExists($remotechannel)) { + do { + if ($this->config->get('auto_discover')) { + if ($this->discover($remotechannel)) { + break; + } + } + return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); + } while (false); + } + $chan = &$this->_registry->getChannel($remotechannel); + if (PEAR::isError($chan)) { + return $chan; + } + $version = $this->_registry->packageInfo($dep['name'], 'version', + $remotechannel); + $this->configSet('default_channel', $remotechannel); + } + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (isset($parr['state']) && isset($parr['version'])) { + unset($parr['state']); + } + if (isset($dep['uri'])) { + $info = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $info->initialize($dep); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + return PEAR::raiseError('Cannot initialize dependency'); + } + if (PEAR::isError($err)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $err->getMessage()); + } + if (is_object($info)) { + $param = $info->getChannel() . '/' . $info->getPackage(); + } + return PEAR::raiseError('Package "' . $param . '" is not valid'); + } + return $info; + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', $this->_options); + $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, + $state, $version, $chan->getName()); + if (PEAR::isError($url)) { + return $url; + } + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + if (!is_array($url)) { + return $url; + } + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); + } + if (isset($url['info']['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($remotechannel); + } else { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + } + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + if (is_array($url)) { + if (isset($url['url'])) { + $url['url'] .= $ext; + } + } + return $url; + } elseif ($chan->supports('xmlrpc', 'package.getDepDownloadURL', false, '1.1')) { + if ($version) { + $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, + $state, $version); + } else { + $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, + $state); + } + } else { + $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state); + } + if ($this->config->get('default_channel') != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + if (!is_array($url)) { + return $url; + } + if (isset($url['__PEAR_ERROR_CLASS__'])) { + return PEAR::raiseError($url['message']); + } + $url['raw'] = $url['info']; + $pkg = &$this->getPackagefileObject($this->config, $this->debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote'); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pinfo)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $pinfo->getMessage()); + } + return PEAR::raiseError('Remote package.xml is not valid - this should never happen'); + } + $url['info'] = &$pinfo; + if (is_array($url)) { + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + if (isset($url['url'])) { + $url['url'] .= $ext; + } + } + return $url; + } + // }}} + // {{{ getPackageDownloadUrl() + + /** + * @deprecated in favor of _getPackageDownloadUrl + */ + function getPackageDownloadUrl($package, $version = null, $channel = false) + { + if ($version) { + $package .= "-$version"; + } + if ($this === null || $this->_registry === null) { + $package = "http://pear.php.net/get/$package"; + } else { + $chan = $this->_registry->getChannel($channel); + if (PEAR::isError($chan)) { + return ''; + } + $package = "http://" . $chan->getServer() . "/get/$package"; + } + if (!extension_loaded("zlib")) { + $package .= '?uncompress=yes'; + } + return $package; + } + + // }}} + // {{{ getDownloadedPackages() + + /** + * Retrieve a list of downloaded packages after a call to {@link download()}. + * + * Also resets the list of downloaded packages. + * @return array + */ + function getDownloadedPackages() + { + $ret = $this->_downloadedPackages; + $this->_downloadedPackages = array(); + $this->_toDownload = array(); + return $ret; + } + + // }}} + // {{{ _downloadCallback() + + function _downloadCallback($msg, $params = null) + { + switch ($msg) { + case 'saveas': + $this->log(1, "downloading $params ..."); + break; + case 'done': + $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); + break; + case 'bytesread': + static $bytes; + if (empty($bytes)) { + $bytes = 0; + } + if (!($bytes % 10240)) { + $this->log(1, '.', false); + } + $bytes += $params; + break; + case 'start': + if($params[1] == -1) { + $length = "Unknown size"; + } else { + $length = number_format($params[1], 0, '', ',')." bytes"; + } + $this->log(1, "Starting to download {$params[0]} ($length)"); + break; + } + if (method_exists($this->ui, '_downloadCallback')) + $this->ui->_downloadCallback($msg, $params); + } + + // }}} + // {{{ _prependPath($path, $prepend) + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; + } + } + return $path; + } + // }}} + // {{{ pushError($errmsg, $code) + + /** + * @param string + * @param integer + */ + function pushError($errmsg, $code = -1) + { + array_push($this->_errorStack, array($errmsg, $code)); + } + + // }}} + // {{{ getErrorMsgs() + + function getErrorMsgs() + { + $msgs = array(); + $errs = $this->_errorStack; + foreach ($errs as $err) { + $msgs[] = $err[0]; + } + $this->_errorStack = array(); + return $msgs; + } + + // }}} + + /** + * for BC + */ + function sortPkgDeps(&$packages, $uninstall = false) + { + $uninstall ? + $this->sortPackagesForUninstall($packages) : + $this->sortPackagesForInstall($packages); + } + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * This uses the topological sort method from graph theory, and the + * Structures_Graph package to properly sort dependencies for installation. + * @param array an array of downloaded PEAR_Downloader_Packages + * @return array array of array(packagefilename, package.xml contents) + */ + function sortPackagesForInstall(&$packages) + { + require_once 'Structures/Graph.php'; + require_once 'Structures/Graph/Node.php'; + require_once 'Structures/Graph/Manipulator/TopologicalSorter.php'; + $depgraph = new Structures_Graph(true); + $nodes = array(); + $reg = &$this->config->getRegistry(); + foreach ($packages as $i => $package) { + $pname = $reg->parsedPackageNameToString( + array( + 'channel' => $package->getChannel(), + 'package' => strtolower($package->getPackage()), + )); + $nodes[$pname] = new Structures_Graph_Node; + $nodes[$pname]->setData($packages[$i]); + $depgraph->addNode($nodes[$pname]); + } + $deplinks = array(); + foreach ($nodes as $package => $node) { + $pf = &$node->getData(); + $pdeps = $pf->getDeps(true); + if (!$pdeps) { + continue; + } + if ($pf->getPackagexmlVersion() == '1.0') { + foreach ($pdeps as $dep) { + if ($dep['type'] != 'pkg' || + (isset($dep['optional']) && $dep['optional'] == 'yes')) { + continue; + } + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pear.php.net', + 'package' => strtolower($dep['name']), + )); + if (isset($nodes[$dname])) + { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pecl.php.net', + 'package' => strtolower($dep['name']), + )); + if (isset($nodes[$dname])) + { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } + } + } else { + // the only ordering we care about is: + // 1) subpackages must be installed before packages that depend on them + // 2) required deps must be installed before packages that depend on them + if (isset($pdeps['required']['subpackage'])) { + $t = $pdeps['required']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } + foreach ($pdeps['group'] as $group) { + if (isset($group['subpackage'])) { + $t = $group['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } + } + if (isset($pdeps['optional']['subpackage'])) { + $t = $pdeps['optional']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + if (isset($pdeps['required']['package'])) { + $t = $pdeps['required']['package']; + if (!isset($t[0])) { + $t = array($t); + } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } + foreach ($pdeps['group'] as $group) { + if (isset($group['package'])) { + $t = $group['package']; + if (!isset($t[0])) { + $t = array($t); + } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } + } + } + } + $this->_detectDepCycle($deplinks); + foreach ($deplinks as $dependent => $parents) { + foreach ($parents as $parent => $unused) { + $nodes[$dependent]->connectTo($nodes[$parent]); + } + } + $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); + $ret = array(); + for ($i = 0; $i < count($installOrder); $i++) { + foreach ($installOrder[$i] as $index => $sortedpackage) { + $data = &$installOrder[$i][$index]->getData(); + $ret[] = &$nodes[$reg->parsedPackageNameToString( + array( + 'channel' => $data->getChannel(), + 'package' => strtolower($data->getPackage()), + ))]->getData(); + } + } + $packages = $ret; + return; + } + + /** + * Detect recursive links between dependencies and break the cycles + * + * @param array + * @access private + */ + function _detectDepCycle(&$deplinks) + { + do { + $keepgoing = false; + foreach ($deplinks as $dep => $parents) { + foreach ($parents as $parent => $unused) { + // reset the parent cycle detector + $this->_testCycle(null, null, null); + if ($this->_testCycle($dep, $deplinks, $parent)) { + $keepgoing = true; + unset($deplinks[$dep][$parent]); + if (count($deplinks[$dep]) == 0) { + unset($deplinks[$dep]); + } + continue 3; + } + } + } + } while ($keepgoing); + } + + function _testCycle($test, $deplinks, $dep) + { + static $visited = array(); + if ($test === null) { + $visited = array(); + return; + } + // this happens when a parent has a dep cycle on another dependency + // but the child is not part of the cycle + if (isset($visited[$dep])) { + return false; + } + $visited[$dep] = 1; + if ($test == $dep) { + return true; + } + if (isset($deplinks[$dep])) { + if (in_array($test, array_keys($deplinks[$dep]), true)) { + return true; + } + foreach ($deplinks[$dep] as $parent => $unused) { + if ($this->_testCycle($test, $deplinks, $parent)) { + return true; + } + } + } + return false; + } + + /** + * Set up the dependency for installation parsing + * + * @param array $t dependency information + * @param PEAR_Registry $reg + * @param array $deplinks list of dependency links already established + * @param array $nodes all existing package nodes + * @param string $package parent package name + * @access private + */ + function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) + { + foreach ($t as $dep) { + $depchannel = !isset($dep['channel']) ? + '__uri': $dep['channel']; + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => $depchannel, + 'package' => strtolower($dep['name']), + )); + if (isset($nodes[$dname])) + { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; + } + } + } + + function _dependsOn($a, $b) + { + return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), + $b); + } + + function _checkDepTree($channel, $package, $b, $checked = array()) + { + $checked[$channel][$package] = true; + if (!isset($this->_depTree[$channel][$package])) { + return false; + } + if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] + [strtolower($b->getPackage())])) { + return true; + } + foreach ($this->_depTree[$channel][$package] as $ch => $packages) { + foreach ($packages as $pa => $true) { + if ($this->_checkDepTree($ch, $pa, $b, $checked)) { + return true; + } + } + } + return false; + } + + function _sortInstall($a, $b) + { + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant + } + if ($a->getDeps() && !$b->getDeps()) { + return 1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return -1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependsOn($a, $b)) { + return 1; + } + if ($this->_dependsOn($b, $a)) { + return -1; + } + return 0; + } + + /** + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP/SSL connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir directory to save file in + * @param mixed $callback function/method to call for status + * updates + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @param false|string $channel Channel to use for retrieving authentication + * @return string|array Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public + */ + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, + $accept = false, $channel = false) + { + static $redirect = 0; + // allways reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + if ($callback) { + call_user_func($callback, 'setup', array(&$ui)); + } + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + } else { + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; + } + if (isset($this)) { + $config = &$this->config; + } else { + $config = &PEAR_Config::singleton(); + } + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($config->get('http_proxy') && + $proxy = parse_url($config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'ssl://' . $proxy_host; + } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + + if ($callback) { + call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); + } + } + if (empty($port)) { + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $port = 443; + } else { + $port = 80; + } + } + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); + } + if ($lastmodified === false || $lastmodified) { + $request = "GET $url HTTP/1.1\r\n"; + } else { + $request = "GET $url HTTP/1.0\r\n"; + } + } else { + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $host = 'ssl://' . $host; + } + $fp = @fsockopen($host, $port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($host, $port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + if ($lastmodified === false || $lastmodified) { + $request = "GET $path HTTP/1.1\r\n"; + $request .= "Host: $host:$port\r\n"; + } else { + $request = "GET $path HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } + } + $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.7.2/PHP/" . + PHP_VERSION . "\r\n"; + if (isset($this)) { // only pass in authentication for non-static calls + $username = $config->get('username', null, $channel); + $password = $config->get('password', null, $channel); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } + } + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + fwrite($fp, $request); + $headers = array(); + $reply = 0; + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int) $matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } + if (! in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)"); + } + } + } + if ($reply != 200) { + if (isset($headers['location'])) { + if ($wasredirect < 5) { + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], + $ui, $save_dir, $callback, $lastmodified, $accept); + } else { + return PEAR::raiseError("File http://$host:$port$path not valid (redirection looped more than 5 times)"); + } + } else { + return PEAR::raiseError("File http://$host:$port$path not valid (redirected but no location)"); + } + } + if (isset($headers['content-disposition']) && + preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { + $save_as = basename($matches[1]); + } else { + $save_as = basename($url); + } + if ($callback) { + $tmp = call_user_func($callback, 'saveas', $save_as); + if ($tmp) { + $save_as = $tmp; + } + } + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("could not open $dest_file for writing"); + } + if (isset($headers['content-length'])) { + $length = $headers['content-length']; + } else { + $length = -1; + } + $bytes = 0; + if ($callback) { + call_user_func($callback, 'start', array(basename($dest_file), $length)); + } + while ($data = fread($fp, 1024)) { + $bytes += strlen($data); + if ($callback) { + call_user_func($callback, 'bytesread', $bytes); + } + if (!@fwrite($wp, $data)) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); + } + } + fclose($fp); + fclose($wp); + if ($callback) { + call_user_func($callback, 'done', $bytes); + } + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); + } + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; + } + } + return array($dest_file, $lastmodified, $headers); + } + return $dest_file; + } +} +// }}} + +?> diff --git a/vas/rest/class/PEAR/Downloader/Package.php b/vas/rest/class/PEAR/Downloader/Package.php new file mode 100755 index 0000000000000000000000000000000000000000..90eaa2d206eae899d24d7c5c804dc648197ecf40 --- /dev/null +++ b/vas/rest/class/PEAR/Downloader/Package.php @@ -0,0 +1,1853 @@ +<?php +/** + * PEAR_Downloader_Package + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Package.php,v 1.113 2008/03/29 14:18:36 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Error code when parameter initialization fails because no releases + * exist within preferred_state, but releases do exist + */ +define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); +/** + * Error code when parameter initialization fails because no releases + * exist that will work with the existing PHP version + */ +define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); +/** + * Coordinates download parameters and manages their dependencies + * prior to downloading them. + * + * Input can come from three sources: + * + * - local files (archives or package.xml) + * - remote files (downloadable urls) + * - abstract package names + * + * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires + * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the + * format returned of dependencies is slightly different from that used in package.xml. + * + * This class hides the differences between these elements, and makes automatic + * dependency resolution a piece of cake. It also manages conflicts when + * two classes depend on incompatible dependencies, or differing versions of the same + * package dependency. In addition, download will not be attempted if the php version is + * not supported, PEAR installer version is not supported, or non-PECL extensions are not + * installed. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Downloader_Package +{ + /** + * @var PEAR_Downloader + */ + var $_downloader; + /** + * @var PEAR_Config + */ + var $_config; + /** + * @var PEAR_Registry + */ + var $_registry; + /** + * Used to implement packagingroot properly + * @var PEAR_Registry + */ + var $_installRegistry; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 + */ + var $_packagefile; + /** + * @var array + */ + var $_parsedname; + /** + * @var array + */ + var $_downloadURL; + /** + * @var array + */ + var $_downloadDeps = array(); + /** + * @var boolean + */ + var $_valid = false; + /** + * @var boolean + */ + var $_analyzed = false; + /** + * if this or a parent package was invoked with Package-state, this is set to the + * state variable. + * + * This allows temporary reassignment of preferred_state for a parent package and all of + * its dependencies. + * @var string|false + */ + var $_explicitState = false; + /** + * If this package is invoked with Package#group, this variable will be true + */ + var $_explicitGroup = false; + /** + * Package type local|url|xmlrpc + * @var string + */ + var $_type; + /** + * Contents of package.xml, if downloaded from a remote channel + * @var string|false + * @access private + */ + var $_rawpackagefile; + /** + * @var boolean + * @access private + */ + var $_validated = false; + + /** + * @param PEAR_Downloader + */ + function PEAR_Downloader_Package(&$downloader) + { + $this->_downloader = &$downloader; + $this->_config = &$this->_downloader->config; + $this->_registry = &$this->_config->getRegistry(); + $options = $downloader->getOptions(); + if (isset($options['packagingroot'])) { + $this->_config->setInstallRoot($options['packagingroot']); + $this->_installRegistry = &$this->_config->getRegistry(); + $this->_config->setInstallRoot(false); + } else { + $this->_installRegistry = &$this->_registry; + } + $this->_valid = $this->_analyzed = false; + } + + /** + * Parse the input and determine whether this is a local file, a remote uri, or an + * abstract package name. + * + * This is the heart of the PEAR_Downloader_Package(), and is used in + * {@link PEAR_Downloader::download()} + * @param string + * @return bool|PEAR_Error + */ + function initialize($param) + { + $origErr = $this->_fromFile($param); + if (!$this->_valid) { + $options = $this->_downloader->getOptions(); + if (isset($options['offline'])) { + if (PEAR::isError($origErr)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $origErr->getMessage()); + } + } + return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); + } + $err = $this->_fromUrl($param); + if (PEAR::isError($err) || !$this->_valid) { + if ($this->_type == 'url') { + if (PEAR::isError($err)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + } + return PEAR::raiseError("Invalid or missing remote package file"); + } + $err = $this->_fromString($param); + if (PEAR::isError($err) || !$this->_valid) { + if (PEAR::isError($err) && + $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { + return false; // instruct the downloader to silently skip + } + if (isset($this->_type) && $this->_type == 'local' && + PEAR::isError($origErr)) { + if (is_array($origErr->getUserInfo())) { + foreach ($origErr->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err); + } + } + } + if (!isset($options['soft'])) { + $this->_downloader->log(0, $origErr->getMessage()); + } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, + true); + } + return PEAR::raiseError( + "Cannot initialize '$param', invalid or missing package file"); + } + if (PEAR::isError($err)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, true); + } + return PEAR::raiseError( + "Cannot initialize '$param', invalid or missing package file"); + } + } + } + return true; + } + + /** + * Retrieve any non-local packages + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error + */ + function &download() + { + if (isset($this->_packagefile)) { + return $this->_packagefile; + } + if (isset($this->_downloadURL['url'])) { + $this->_isvalid = false; + $info = $this->getParsedPackage(); + foreach ($info as $i => $p) { + $info[$i] = strtolower($p); + } + $err = $this->_fromUrl($this->_downloadURL['url'], + $this->_registry->parsedPackageNameToString($this->_parsedname, true)); + $newinfo = $this->getParsedPackage(); + foreach ($newinfo as $i => $p) { + $newinfo[$i] = strtolower($p); + } + if ($info != $newinfo) { + do { + if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') { + $info['package'] = 'pear.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } + return PEAR::raiseError('CRITICAL ERROR: We are ' . + $this->_registry->parsedPackageNameToString($info) . ', but the file ' . + 'downloaded claims to be ' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage())); + } while (false); + } + if (PEAR::isError($err) || !$this->_valid) { + return $err; + } + } + $this->_type = 'local'; + return $this->_packagefile; + } + + function &getPackageFile() + { + return $this->_packagefile; + } + + function &getDownloader() + { + return $this->_downloader; + } + + function getType() + { + return $this->_type; + } + + /** + * Like {@link initialize()}, but operates on a dependency + */ + function fromDepURL($dep) + { + $this->_downloadURL = $dep; + if (isset($dep['uri'])) { + $options = $this->_downloader->getOptions(); + if (!extension_loaded("zlib") || isset($options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->_fromUrl($dep['uri'] . $ext); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . + 'cannot download'); + } + } else { + $this->_parsedname = + array( + 'package' => $dep['info']->getPackage(), + 'channel' => $dep['info']->getChannel(), + 'version' => $dep['version'] + ); + if (!isset($dep['nodefault'])) { + $this->_parsedname['group'] = 'default'; // download the default dependency group + $this->_explicitGroup = false; + } + $this->_rawpackagefile = $dep['raw']; + } + } + + function detectDependencies($params) + { + $options = $this->_downloader->getOptions(); + if (isset($options['downloadonly'])) { + return; + } + if (isset($options['offline'])) { + $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); + return; + } + $pname = $this->getParsedPackage(); + if (!$pname) { + return; + } + $deps = $this->getDeps(); + if (!$deps) { + return; + } + if (isset($deps['required'])) { // package.xml 2.0 + return $this->_detect2($deps, $pname, $options, $params); + } else { + return $this->_detect1($deps, $pname, $options, $params); + } + } + + function setValidated() + { + $this->_validated = true; + } + + function alreadyValidated() + { + return $this->_validated; + } + + /** + * Remove packages to be downloaded that are already installed + * @param array of PEAR_Downloader_Package objects + * @static + */ + function removeInstalled(&$params) + { + if (!isset($params[0])) { + return; + } + $options = $params[0]->_downloader->getOptions(); + if (!isset($options['downloadonly'])) { + foreach ($params as $i => $param) { + // remove self if already installed with this version + // this does not need any pecl magic - we only remove exact matches + if ($param->_installRegistry->packageExists($param->getPackage(), $param->getChannel())) { + if (version_compare($param->_installRegistry->packageInfo($param->getPackage(), 'version', + $param->getChannel()), $param->getVersion(), '==')) { + if (!isset($options['force'])) { + $info = $param->getParsedPackage(); + unset($info['version']); + unset($info['state']); + if (!isset($options['soft'])) { + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . + $param->_installRegistry->packageInfo($param->getPackage(), + 'version', $param->getChannel())); + } + $params[$i] = false; + } + } elseif (!isset($options['force']) && !isset($options['upgrade']) && + !isset($options['soft'])) { + $info = $param->getParsedPackage(); + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . + $param->_installRegistry->packageInfo($param->getPackage(), 'version', + $param->getChannel())); + $params[$i] = false; + } + } + } + } + PEAR_Downloader_Package::removeDuplicates($params); + } + + function _detect2($deps, $pname, $options, $params) + { + $this->_downloadDeps = array(); + $groupnotfound = false; + foreach (array('package', 'subpackage') as $packagetype) { + // get required dependency group + if (isset($deps['required'][$packagetype])) { + if (isset($deps['required'][$packagetype][0])) { + foreach ($deps['required'][$packagetype] as $dep) { + if (isset($dep['conflicts'])) { + // skip any package that this package conflicts with + continue; + } + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + } else { + $dep = $deps['required'][$packagetype]; + if (!isset($dep['conflicts'])) { + // skip any package that this package conflicts with + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + } + } + // get optional dependency group, if any + if (isset($deps['optional'][$packagetype])) { + $skipnames = array(); + if (!isset($deps['optional'][$packagetype][0])) { + $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); + } + foreach ($deps['optional'][$packagetype] as $dep) { + $skip = false; + if (!isset($options['alldeps'])) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage(), + true) . '" optional dependency "' . + $this->_registry->parsedPackageNameToString(array('package' => + $dep['name'], 'channel' => 'pear.php.net'), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); + $skip = true; + unset($dep['package']); + } + if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) { + $dep['package'] = $dep['name']; + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + } + if (!$skip && is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download optional dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps to download automatically'); + } + } + } + // get requested dependency group, if any + $groupname = $this->getGroup(); + $explicit = $this->_explicitGroup; + if (!$groupname) { + if ($this->canDefault()) { + $groupname = 'default'; // try the default dependency group + } else { + continue; + } + } + if ($groupnotfound) { + continue; + } + if (isset($deps['group'])) { + if (isset($deps['group']['attribs'])) { + if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { + $group = $deps['group']; + } elseif ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); + } + $groupnotfound = true; + continue; + } + } else { + $found = false; + foreach ($deps['group'] as $group) { + if (strtolower($group['attribs']['name']) == strtolower($groupname)) { + $found = true; + break; + } + } + if (!$found) { + if ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); + } + } + $groupnotfound = true; + continue; + } + } + } + if (isset($group)) { + if (isset($group[$packagetype])) { + if (isset($group[$packagetype][0])) { + foreach ($group[$packagetype] as $dep) { + $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + } else { + $ret = $this->_detect2Dep($group[$packagetype], $pname, + 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + } + } + } + } + + function _detect2Dep($dep, $pname, $group, $params) + { + if (isset($dep['conflicts'])) { + return true; + } + $options = $this->_downloader->getOptions(); + if (isset($dep['uri'])) { + return array('uri' => $dep['uri'], 'dep' => $dep);; + } + $testdep = $dep; + $testdep['package'] = $dep['name']; + if (PEAR_Downloader_Package::willDownload($testdep, $params)) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); + } + return false; + } + $options = $this->_downloader->getOptions(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; + } + $url = + $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + return $url; + } + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + return false; + } else { + // check to see if a dep is already installed and is the same or newer + if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { + $oper = 'has'; + } else { + $oper = 'gt'; + } + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version', + $dep['channel']); + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '" version ' . $url['version'] . ', already installed as version ' . + $version); + } + return false; + } + } + if (isset($dep['nodefault'])) { + $ret['nodefault'] = true; + } + return $ret; + } + + function _detect1($deps, $pname, $options, $params) + { + $this->_downloadDeps = array(); + $skipnames = array(); + foreach ($deps as $dep) { + $nodownload = false; + if ($dep['type'] == 'pkg') { + $dep['channel'] = 'pear.php.net'; + $dep['package'] = $dep['name']; + switch ($dep['rel']) { + case 'not' : + continue 2; + case 'ge' : + case 'eq' : + case 'gt' : + case 'has' : + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + if (PEAR_Downloader_Package::willDownload($dep, $params)) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); + continue 2; + } + $fakedp = new PEAR_PackageFile_v1; + $fakedp->setPackage($dep['name']); + // skip internet check if we are not upgrading (bug #5810) + if (!isset($options['upgrade']) && $this->isInstalled( + $fakedp, $dep['rel'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", is already installed'); + continue 2; + } + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; + } + $url = + $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + $chan = 'pear.php.net'; + if (PEAR::isError($url)) { + // check to see if this is a pecl package that has jumped + // from pear.php.net to pecl.php.net channel + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $newdep = PEAR_Dependency2::normalizeDep($dep); + $newdep = $newdep[0]; + $newdep['channel'] = 'pecl.php.net'; + $chan = 'pecl.php.net'; + $url = + $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); + $obj = &$this->_installRegistry->getPackage($dep['name']); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . + ': Skipping ' . $group . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $obj->getVersion()); + } + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + continue; + } else { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $this->_downloader->log(2, $this->getShortName() . + ': Skipping optional dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", no releases exist'); + continue; + } else { + return $url; + } + } + } + } + PEAR::popErrorHandling(); + if (!isset($options['alldeps'])) { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" optional dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; + } + } + if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { + if (!isset($dep['optional']) || $dep['optional'] == 'no') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" required dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; + } + } + // check to see if a dep is already installed + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled( + $url, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (isset($newdep)) { + $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', + $newdep['channel']); + } else { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); + } + $dep['version'] = $url['version']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $version); + } + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + continue; + } + if ($nodownload) { + continue; + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (isset($newdep)) { + $dep = $newdep; + } + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, + isset($dep['optional']) && $dep['optional'] == 'yes' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + continue; + } + $this->_downloadDeps[] = $ret; + } + } + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps or --onlyreqdeps to download automatically'); + } + } + } + + function setDownloadURL($pkg) + { + $this->_downloadURL = $pkg; + } + + /** + * Set the package.xml object for this downloaded package + * + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg + */ + function setPackageFile(&$pkg) + { + $this->_packagefile = &$pkg; + } + + function getShortName() + { + return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), + 'package' => $this->getPackage()), true); + } + + function getParsedPackage() + { + if (isset($this->_packagefile) || isset($this->_parsedname)) { + return array('channel' => $this->getChannel(), + 'package' => $this->getPackage(), + 'version' => $this->getVersion()); + } + return false; + } + + function getDownloadURL() + { + return $this->_downloadURL; + } + + function canDefault() + { + if (isset($this->_downloadURL)) { + if (isset($this->_downloadURL['nodefault'])) { + return false; + } + } + return true; + } + + function getPackage() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackage(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackage(); + } else { + return false; + } + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function isSubpackage(&$pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isSubpackage($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isSubpackage($pf); + } else { + return false; + } + } + + function getPackageType() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackageType(); + } else { + return false; + } + } + + function isBundle() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType() == 'bundle'; + } else { + return false; + } + } + + function getPackageXmlVersion() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackagexmlVersion(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackagexmlVersion(); + } else { + return '1.0'; + } + } + + function getChannel() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getChannel(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getChannel(); + } else { + return false; + } + } + + function getURI() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getURI(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getURI(); + } else { + return false; + } + } + + function getVersion() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getVersion(); + } elseif (isset($this->_downloadURL['version'])) { + return $this->_downloadURL['version']; + } else { + return false; + } + } + + function isCompatible($pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isCompatible($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isCompatible($pf); + } else { + return true; + } + } + + function setGroup($group) + { + $this->_parsedname['group'] = $group; + } + + function getGroup() + { + if (isset($this->_parsedname['group'])) { + return $this->_parsedname['group']; + } else { + return ''; + } + } + + function isExtension($name) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isExtension($name); + } elseif (isset($this->_downloadURL['info'])) { + if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { + return $this->_downloadURL['info']->getProvidesExtension() == $name; + } else { + return false; + } + } else { + return false; + } + } + + function getDeps() + { + if (isset($this->_packagefile)) { + $ver = $this->_packagefile->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_packagefile->getDeps(true); + } else { + return $this->_packagefile->getDeps(); + } + } elseif (isset($this->_downloadURL['info'])) { + $ver = $this->_downloadURL['info']->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_downloadURL['info']->getDeps(true); + } else { + return $this->_downloadURL['info']->getDeps(); + } + } else { + return array(); + } + } + + /** + * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency + * returned from getDepDownloadURL() + */ + function isEqual($param) + { + if (is_object($param)) { + $channel = $param->getChannel(); + $package = $param->getPackage(); + if ($param->getURI()) { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + 'uri' => $param->getURI(), + ); + } else { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + ); + } + } else { + if (isset($param['uri'])) { + if ($this->getChannel() != '__uri') { + return false; + } + return $param['uri'] == $this->getURI(); + } + $package = isset($param['package']) ? $param['package'] : + $param['info']->getPackage(); + $channel = isset($param['channel']) ? $param['channel'] : + $param['info']->getChannel(); + if (isset($param['rel'])) { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $newdep = PEAR_Dependency2::normalizeDep($param); + $newdep = $newdep[0]; + } elseif (isset($param['min'])) { + $newdep = $param; + } + } + if (isset($newdep)) { + if (!isset($newdep['min'])) { + $newdep['min'] = '0'; + } + if (!isset($newdep['max'])) { + $newdep['max'] = '100000000000000000000'; + } + // use magic to support pecl packages suddenly jumping to the pecl channel + // we need to support both dependency possibilities + if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pecl.php.net'; + } + } + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pear.php.net'; + } + } + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + version_compare($newdep['min'], $this->getVersion(), '<=') && + version_compare($newdep['max'], $this->getVersion(), '>=')); + } + // use magic to support pecl packages suddenly jumping to the pecl channel + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if (strtolower($package) == strtolower($this->getPackage())) { + $channel = 'pear.php.net'; + } + } + if (isset($param['version'])) { + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + $param['version'] == $this->getVersion()); + } else { + return strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel(); + } + } + + function isInstalled($dep, $oper = '==') + { + if (!$dep) { + return false; + } + if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { + return false; + } + if (is_object($dep)) { + $package = $dep->getPackage(); + $channel = $dep->getChannel(); + if ($dep->getURI()) { + $dep = array( + 'uri' => $dep->getURI(), + 'version' => $dep->getVersion(), + ); + } else { + $dep = array( + 'version' => $dep->getVersion(), + ); + } + } else { + if (isset($dep['uri'])) { + $channel = '__uri'; + $package = $dep['dep']['name']; + } else { + $channel = $dep['info']->getChannel(); + $package = $dep['info']->getPackage(); + } + } + $options = $this->_downloader->getOptions(); + $test = $this->_installRegistry->packageExists($package, $channel); + if (!$test && $channel == 'pecl.php.net') { + // do magic to allow upgrading from old pecl packages to new ones + $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); + $channel = 'pear.php.net'; + } + if ($test) { + if (isset($dep['uri'])) { + if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { + return true; + } + } + if (isset($options['upgrade'])) { + if ($oper == 'has') { + if (version_compare($this->_installRegistry->packageInfo( + $package, 'version', $channel), + $dep['version'], '>=')) { + return true; + } else { + return false; + } + } else { + if (version_compare($this->_installRegistry->packageInfo( + $package, 'version', $channel), + $dep['version'], '>=')) { + return true; + } + return false; + } + } + return true; + } + return false; + } + + /** + * Detect duplicate package names with differing versions + * + * If a user requests to install Date 1.4.6 and Date 1.4.7, + * for instance, this is a logic error. This method + * detects this situation. + * + * @param array $params array of PEAR_Downloader_Package objects + * @param array $errorparams empty array + * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts + */ + function detectStupidDuplicates($params, &$errorparams) + { + $existing = array(); + foreach ($params as $i => $param) { + $package = $param->getPackage(); + $channel = $param->getChannel(); + $group = $param->getGroup(); + if (!isset($existing[$channel . '/' . $package])) { + $existing[$channel . '/' . $package] = array(); + } + if (!isset($existing[$channel . '/' . $package][$group])) { + $existing[$channel . '/' . $package][$group] = array(); + } + $existing[$channel . '/' . $package][$group][] = $i; + } + + $indices = array(); + foreach ($existing as $package => $groups) { + foreach ($groups as $group => $dupes) { + if (count($dupes) > 1) { + $indices = $indices + $dupes; + } + } + } + + $indices = array_unique($indices); + foreach ($indices as $index) { + $errorparams[] = $params[$index]; + } + return count($errorparams); + } + + /** + * @param array + * @param bool ignore install groups - for final removal of dupe packages + * @static + */ + function removeDuplicates(&$params, $ignoreGroups = false) + { + $pnames = array(); + foreach ($params as $i => $param) { + if (!$param) { + continue; + } + if ($param->getPackage()) { + if ($ignoreGroups) { + $group = ''; + } else { + $group = $param->getGroup(); + } + $pnames[$i] = $param->getChannel() . '/' . + $param->getPackage() . '-' . $param->getVersion() . '#' . $group; + } + } + $pnames = array_unique($pnames); + $unset = array_diff(array_keys($params), array_keys($pnames)); + $testp = array_flip($pnames); + foreach ($params as $i => $param) { + if (!$param) { + $unset[] = $i; + continue; + } + if (!is_a($param, 'PEAR_Downloader_Package')) { + $unset[] = $i; + continue; + } + if ($ignoreGroups) { + $group = ''; + } else { + $group = $param->getGroup(); + } + if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . + $param->getVersion() . '#' . $group])) { + $unset[] = $i; + } + } + foreach ($unset as $i) { + unset($params[$i]); + } + $ret = array(); + foreach ($params as $i => $param) { + $ret[] = &$params[$i]; + } + $params = array(); + foreach ($ret as $i => $param) { + $params[] = &$ret[$i]; + } + } + + function explicitState() + { + return $this->_explicitState; + } + + function setExplicitState($s) + { + $this->_explicitState = $s; + } + + /** + * @static + */ + function mergeDependencies(&$params) + { + $newparams = array(); + $bundles = array(); + foreach ($params as $i => $param) { + if (!$param->isBundle()) { + continue; + } + $bundles[] = $i; + $pf = &$param->getPackageFile(); + $newdeps = array(); + $contents = $pf->getBundledPackages(); + if (!is_array($contents)) { + $contents = array($contents); + } + foreach ($contents as $file) { + $filecontents = $pf->getFileContents($file); + $dl = &$param->getDownloader(); + $options = $dl->getOptions(); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + return $dir; + } + $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); + if (!$fp) { + continue; + } + fwrite($fp, $filecontents, strlen($filecontents)); + fclose($fp); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); + } + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + PEAR::popErrorHandling(); + return $dir; + } + $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $dl->log(0, $e->getMessage()); + } + continue; + } + $j = &$obj; + if (!PEAR_Downloader_Package::willDownload($j, + array_merge($params, $newparams)) && !$param->isInstalled($j)) { + $newparams[] = &$j; + } + } + } + foreach ($bundles as $i) { + unset($params[$i]); // remove bundles - only their contents matter for installation + } + PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices + if (count($newparams)) { // add in bundled packages for install + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; + } + $newparams = array(); + } + foreach ($params as $i => $param) { + $newdeps = array(); + foreach ($param->_downloadDeps as $dep) { + if (!PEAR_Downloader_Package::willDownload($dep, + array_merge($params, $newparams)) && !$param->isInstalled($dep)) { + $newdeps[] = $dep; + } else { + // detect versioning conflicts here + } + } + // convert the dependencies into PEAR_Downloader_Package objects for the next time + // around + $params[$i]->_downloadDeps = array(); + foreach ($newdeps as $dep) { + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $e = $obj->fromDepURL($dep); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); + } + continue; + } + $e = $obj->detectDependencies($params); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); + } + } + $j = &$obj; + $newparams[] = &$j; + } + } + if (count($newparams)) { + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; + } + return true; + } else { + return false; + } + } + + + /** + * @static + */ + function willDownload($param, $params) + { + if (!is_array($params)) { + return false; + } + foreach ($params as $obj) { + if ($obj->isEqual($param)) { + return true; + } + } + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string + */ + function &getPackagefileObject(&$c, $d, $t = false) + { + $a = &new PEAR_PackageFile($c, $d, $t); + return $a; + } + + + /** + * This will retrieve from a local file if possible, and parse out + * a group name as well. The original parameter will be modified to reflect this. + * @param string|array can be a parsed package name as well + * @access private + */ + function _fromFile(&$param) + { + $saveparam = $param; + if (is_string($param)) { + if (!@file_exists($param)) { + $test = explode('#', $param); + $group = array_pop($test); + if (@file_exists(implode('#', $test))) { + $this->setGroup($group); + $param = implode('#', $test); + $this->_explicitGroup = true; + } + } + if (@is_file($param)) { + $this->_type = 'local'; + $options = $this->_downloader->getOptions(); + if (isset($options['downloadonly'])) { + $pkg = &$this->getPackagefileObject($this->_config, + $this->_downloader->_debug); + } else { + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + return $dir; + } + $pkg = &$this->getPackagefileObject($this->_config, + $this->_downloader->_debug, $dir); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + $this->_valid = false; + $param = $saveparam; + return $pf; + } + $this->_packagefile = &$pf; + if (!$this->getGroup()) { + $this->setGroup('default'); // install the default dependency group + } + return $this->_valid = true; + } + } + $param = $saveparam; + return $this->_valid = false; + } + + function _fromUrl($param, $saveparam = '') + { + if (!is_array($param) && + (preg_match('#^(http|ftp)://#', $param))) { + $options = $this->_downloader->getOptions(); + $this->_type = 'url'; + $callback = $this->_downloader->ui ? + array(&$this->_downloader, '_downloadCallback') : null; + $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + $this->_downloader->popErrorHandling(); + return $dir; + } + $this->_downloader->log(3, 'Downloading "' . $param . '"'); + $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, + $dir, $callback, null, false, $this->getChannel()); + $this->_downloader->popErrorHandling(); + if (PEAR::isError($file)) { + if (!empty($saveparam)) { + $saveparam = ", cannot download \"$saveparam\""; + } + $err = PEAR::raiseError('Could not download from "' . $param . + '"' . $saveparam . ' (' . $file->getMessage() . ')'); + return $err; + } + if ($this->_rawpackagefile) { + require_once 'Archive/Tar.php'; + $tar = &new Archive_Tar($file); + $packagexml = $tar->extractInString('package2.xml'); + if (!$packagexml) { + $packagexml = $tar->extractInString('package.xml'); + } + if (str_replace(array("\n", "\r"), array('',''), $packagexml) != + str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { + if ($this->getChannel() == 'pear.php.net') { + // be more lax for the existing PEAR packages that have not-ok + // characters in their package.xml + $this->_downloader->log(0, 'CRITICAL WARNING: The "' . + $this->getPackage() . '" package has invalid characters in its ' . + 'package.xml. The next version of PEAR may not be able to install ' . + 'this package for security reasons. Please open a bug report at ' . + 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); + } else { + return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . + 'not match value returned from xml-rpc'); + } + } + } + // whew, download worked! + if (isset($options['downloadonly'])) { + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); + } else { + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + return $dir; + } + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, + $dir); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + if (!isset($options['soft'])) { + $this->_downloader->log(0, "Validation Error: $err"); + } + } + } + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pf->getMessage()); + } + $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam : + $param) . '" succeeded, but it is not a valid package archive'); + $this->_valid = false; + return $err; + } + $this->_packagefile = &$pf; + $this->setGroup('default'); // install the default dependency group + return $this->_valid = true; + } + return $this->_valid = false; + } + + /** + * + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',]) + * or a string of format [channame/]pname[-version|-state] + */ + function _fromString($param) + { + $options = $this->_downloader->getOptions(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, + $this->_config->get('default_channel')); + PEAR::popErrorHandling(); + if (PEAR::isError($pname)) { + if ($pname->getCode() == 'invalid') { + $this->_valid = false; + return false; + } + if ($pname->getCode() == 'channel') { + $parsed = $pname->getUserInfo(); + if ($this->_downloader->discover($parsed['channel'])) { + if ($this->_config->get('auto_discover')) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, + $this->_config->get('default_channel')); + PEAR::popErrorHandling(); + } else { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . + '" is not initialized, use ' . + '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . + 'or pear config-set auto_discover 1'); + } + } + } + if (PEAR::isError($pname)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param); + } + $err = PEAR::raiseError('invalid package name/package file "' . + $param . '"'); + $this->_valid = false; + return $err; + } + } else { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } + $err = PEAR::raiseError('invalid package name/package file "' . + $param . '"'); + $this->_valid = false; + return $err; + } + } + if (!isset($this->_type)) { + $this->_type = 'xmlrpc'; + } + $this->_parsedname = $pname; + if (isset($pname['state'])) { + $this->_explicitState = $pname['state']; + } else { + $this->_explicitState = false; + } + if (isset($pname['group'])) { + $this->_explicitGroup = true; + } else { + $this->_explicitGroup = false; + } + $info = $this->_downloader->_getPackageDownloadUrl($pname); + if (PEAR::isError($info)) { + if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { + // try pecl + $pname['channel'] = 'pecl.php.net'; + if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { + if (!PEAR::isError($test)) { + $info = PEAR::raiseError($info->getMessage() . ' - package ' . + $this->_registry->parsedPackageNameToString($pname, true) . + ' can be installed with "pecl install ' . $pname['package'] . + '"'); + } else { + $pname['channel'] = 'pear.php.net'; + } + } else { + $pname['channel'] = 'pear.php.net'; + } + } + return $info; + } + $this->_rawpackagefile = $info['raw']; + $ret = $this->_analyzeDownloadURL($info, $param, $pname); + if (PEAR::isError($ret)) { + return $ret; + } + if ($ret) { + $this->_downloadURL = $ret; + return $this->_valid = (bool) $ret; + } + } + + /** + * @param array output of package.getDownloadURL + * @param string|array|object information for detecting packages to be downloaded, and + * for errors + * @param array name information of the package + * @param array|null packages to be downloaded + * @param bool is this an optional dependency? + * @param bool is this any kind of dependency? + * @access private + */ + function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, + $isdependency = false) + { + if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { + return false; + } + if (!$info) { + if (!is_string($param)) { + $saveparam = ", cannot download \"$param\""; + } else { + $saveparam = ''; + } + // no releases exist + return PEAR::raiseError('No releases for package "' . + $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); + } + if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { + $err = false; + if ($pname['channel'] == 'pecl.php.net') { + if ($info['info']->getChannel() != 'pear.php.net') { + $err = true; + } + } elseif ($info['info']->getChannel() == 'pecl.php.net') { + if ($pname['channel'] != 'pear.php.net') { + $err = true; + } + } else { + $err = true; + } + if ($err) { + return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . + '" retrieved another channel\'s name for download! ("' . + $info['info']->getChannel() . '")'); + } + } + if (!isset($info['url'])) { + if ($this->isInstalled($info)) { + if ($isdependency && version_compare($info['version'], + $this->_registry->packageInfo($info['info']->getPackage(), + 'version', $info['info']->getChannel()), '<=')) { + // ignore bogus errors of "failed to download dependency" + // if it is already installed and the one that would be + // downloaded is older or the same version (Bug #7219) + return false; + } + } + $instead = ', will instead download version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '"'; + // releases exist, but we failed to get any + if (isset($this->_downloader->_options['force'])) { + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) { + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $this->_config->get('preferred_state') . + '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + $instead = ''; + } + } else { + $vs = ' within preferred state "' . $this->_config->get( + 'preferred_state') . '"'; + } + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . $vs . $instead); + } + // download the latest release + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } else { + if (isset($info['php']) && $info['php']) { + $err = PEAR::raiseError('Failed to download ' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], + 'package' => $pname['package']), + true) . + ', latest release is version ' . $info['php']['v'] . + ', but it requires PHP version "' . + $info['php']['m'] . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['php']['v'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_PHPVERSION); + return $err; + } + // construct helpful error message + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) { + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $this->_config->get('preferred_state') . + '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + } + } else { + $vs = ' within preferred state "' . $this->_downloader->config->get( + 'preferred_state') . '"'; + } + $options = $this->_downloader->getOptions(); + // this is only set by the "download-all" command + if (isset($options['ignorepreferred_state'])) { + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_STATE); + return $err; + } + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install'); + return $err; + } + } + if (isset($info['deprecated']) && $info['deprecated']) { + $this->_downloader->log(0, + 'WARNING: "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $info['info']->getChannel(), + 'package' => $info['info']->getPackage()), true) . + '" is deprecated in favor of "' . + $this->_registry->parsedPackageNameToString($info['deprecated'], true) . + '"'); + } + return $info; + } +} +?> diff --git a/vas/rest/class/PEAR/ErrorStack.php b/vas/rest/class/PEAR/ErrorStack.php new file mode 100755 index 0000000000000000000000000000000000000000..ad0490110dd16dff3d6b89e1a2dfbe9b1e950a94 --- /dev/null +++ b/vas/rest/class/PEAR/ErrorStack.php @@ -0,0 +1,985 @@ +<?php +/** + * Error Stack Implementation + * + * This is an incredibly simple implementation of a very complex error handling + * facility. It contains the ability + * to track multiple errors from multiple packages simultaneously. In addition, + * it can track errors of many levels, save data along with the error, context + * information such as the exact file, line number, class and function that + * generated the error, and if necessary, it can raise a traditional PEAR_Error. + * It has built-in support for PEAR::Log, to log errors as they occur + * + * Since version 0.2alpha, it is also possible to selectively ignore errors, + * through the use of an error callback, see {@link pushCallback()} + * + * Since version 0.3alpha, it is possible to specify the exception class + * returned from {@link push()} + * + * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can + * still be done quite handily in an error callback or by manipulating the returned array + * @category Debugging + * @package PEAR_ErrorStack + * @author Greg Beaver <cellog@php.net> + * @copyright 2004-2008 Greg Beaver + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ + +/** + * Singleton storage + * + * Format: + * <pre> + * array( + * 'package1' => PEAR_ErrorStack object, + * 'package2' => PEAR_ErrorStack object, + * ... + * ) + * </pre> + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; + +/** + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + +/**#@+ + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() + */ +/** + * If this is returned, then the error will be both pushed onto the stack + * and logged. + */ +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); +/**#@-*/ + +/** + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. + */ +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * <code> + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * </code> + * @author Greg Beaver <cellog@php.net> + * @version 1.7.2 + * @package PEAR_ErrorStack + * @category Debugging + * @copyright 2004-2008 Greg Beaver + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array + * @access private + */ + var $_errors = array(); + + /** + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array + * @access private + */ + var $_errorsByLevel = array(); + + /** + * Package name this error stack represents + * @var string + * @access protected + */ + var $_package; + + /** + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean + * @access private + */ + var $_compat = false; + + /** + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array + * @access private + */ + var $_msgCallback = false; + + /** + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array + * @access protected + */ + var $_contextCallback = false; + + /** + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected + */ + var $_errorCallback = array(); + + /** + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; + } + + /** + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate + * @static + * @return PEAR_ErrorStack + */ + function &singleton($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') + { + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); + } + $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); + + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + + /** + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private + */ + function _handleError($err) + { + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '<br />'; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); + } + } + + /** + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log + * @static + */ + function setDefaultLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } + } + + /** + * Set up a PEAR::Log object for this error stack + * @param Log $log + */ + function setLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; + } + } + + /** + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method + */ + function setMessageCallback($msgCallback) + { + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); + } else { + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; + } + } + } + + /** + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none + */ + function getMessageCallback() + { + return $this->_msgCallback; + } + + /** + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages + * @static + */ + function setDefaultCallback($callback = false, $package = false) + { + if (!is_callable($callback)) { + $callback = false; + } + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; + } + + /** + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; + } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; + } + } + } + + /** + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb + */ + function pushCallback($cb) + { + array_push($this->_errorCallback, $cb); + } + + /** + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false + */ + function popCallback() + { + if (!count($this->_errorCallback)) { + return false; + } + return array_pop($this->_errorCallback); + } + + /** + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + * @static + */ + function staticPushCallback($cb) + { + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); + } + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + * @static + */ + function staticPopCallback() + { + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + } + return $ret; + } + + /** + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. If a PEAR_Error is returned, the userinfo + * property is set to the following array: + * + * <code> + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * </code> + * + * Normally, the previous array is returned. + */ + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) + { + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); + } + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + if ($repackage) { + $err['repackage'] = $repackage; + } + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); + } + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + if (!isset($this->_errorsByLevel[$err['level']])) { + $this->_errorsByLevel[$err['level']] = array(); + } + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); + } + } + if ($die) { + die(); + } + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; + } + + /** + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. see docs for {@link push()} + * @static + */ + function staticPush($package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false) + { + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); + } + } + } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); + } + + /** + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map + * @access protected + */ + function _log($err) + { + if ($this->_logger) { + $logger = &$this->_logger; + } else { + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; + } + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); + } + } + + + /** + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead + */ + function pop() + { + $err = @array_shift($this->_errors); + if (!is_null($err)) { + @array_pop($this->_errorsByLevel[$err['level']]); + if (!count($this->_errorsByLevel[$err['level']])) { + unset($this->_errorsByLevel[$err['level']]); + } + } + return $err; + } + + /** + * Pop an error off of the error stack, static method + * + * @param string package name + * @return boolean + * @since PEAR1.5.0a1 + */ + function staticPop($package) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); + } + } + + /** + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean + */ + function hasErrors($level = false) + { + if ($level) { + return isset($this->_errorsByLevel[$level]); + } + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; + } + } else { + return $this->_errors; + } + } + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; + } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; + } + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; + } + + /** + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + * @static + */ + function staticHasErrors($package = false, $level = false) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; + } + } + return false; + } + + /** + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * @static + * @return array + */ + function staticGetErrors($purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) + { + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); + } + return $ret; + } + + /** + * Error sorting function, sorts by time + * @access private + */ + function _sortErrors($a, $b) + { + if ($a['time'] == $b['time']) { + return 0; + } + if ($a['time'] < $b['time']) { + return 1; + } + return -1; + } + + /** + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + * @static + */ + function getFileLine($code, $params, $backtrace = null) + { + if ($backtrace === null) { + return false; + } + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; + } + return false; + } + + /** + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * <code> + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * </code> + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * @static + * @return string + */ + function getErrorMessage(&$stack, $err, $template = false) + { + if ($template) { + $mainmsg = $template; + } else { + $mainmsg = $stack->getErrorMessageTemplate($err['code']); + } + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (is_array($err['params']) && count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } + } + return $mainmsg; + } + + /** + * Standard Error Message Template generator from code + * @return string + */ + function getErrorMessageTemplate($code) + { + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; + } + return $this->_errorMsgs[$code]; + } + + /** + * Set the Error Message Template array + * + * The array format must be: + * <pre> + * array(error code => 'message template',...) + * </pre> + * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string + */ + function setErrorMessageTemplate($template) + { + $this->_errorMsgs = $template; + } + + + /** + * emulate PEAR::raiseError() + * + * @return PEAR_Error + */ + function raiseError() + { + require_once 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); + } +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> diff --git a/vas/rest/class/PEAR/Exception.php b/vas/rest/class/PEAR/Exception.php new file mode 100755 index 0000000000000000000000000000000000000000..b3d75b20c9cfe886530994469f0275d059ab665a --- /dev/null +++ b/vas/rest/class/PEAR/Exception.php @@ -0,0 +1,397 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ +/** + * PEAR_Exception + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Hans Lellelid <hans@velum.net> + * @author Bertrand Mansion <bmansion@mamasam.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * <code> + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * </code> + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Hans Lellelid <hans@velum.net> + * @author Bertrand Mansion <bmansion@mamasam.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + * <pre> + * array('name' => $name, 'context' => array(...)) + * </pre> + * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '<table border="1" cellspacing="0">' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '<tr><td colspan="3" bgcolor="#ff9999">' + . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: ' + . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> ' + . 'on line <b>' . $cause['line'] . '</b>' + . "</td></tr>\n"; + } + $html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n" + . '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>' + . '<td align="center" bgcolor="#cccccc"><b>Function</b></td>' + . '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '<tr><td align="center">' . $k . '</td>' + . '<td>'; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '</td>' + . '<td>' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '</td></tr>' . "\n"; + } + $html .= '<tr><td align="center">' . ($k+1) . '</td>' + . '<td>{main}</td>' + . '<td> </td></tr>' . "\n" + . '</table>'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} + +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/FixPHP5PEARWarnings.php b/vas/rest/class/PEAR/FixPHP5PEARWarnings.php new file mode 100755 index 0000000000000000000000000000000000000000..be5dc3ce707c3e06189b89395819ae49edbab19c --- /dev/null +++ b/vas/rest/class/PEAR/FixPHP5PEARWarnings.php @@ -0,0 +1,7 @@ +<?php +if ($skipmsg) { + $a = &new $ec($code, $mode, $options, $userinfo); +} else { + $a = &new $ec($message, $code, $mode, $options, $userinfo); +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Frontend.php b/vas/rest/class/PEAR/Frontend.php new file mode 100755 index 0000000000000000000000000000000000000000..bf7d4ba6aa1d703e6e093367948904e64918569a --- /dev/null +++ b/vas/rest/class/PEAR/Frontend.php @@ -0,0 +1,223 @@ +<?php +/** + * PEAR_Frontend, the singleton-based frontend for user input/output + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Frontend.php,v 1.13 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; + +/** + * Instance of $_PEAR_Command_uiclass. + * @var object + */ +$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; + +/** + * Singleton-based frontend for PEAR user input/output + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Frontend extends PEAR +{ + /** + * Retrieve the frontend object + * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk + * @static + */ + function &singleton($type = null) + { + if ($type === null) { + if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { + $a = false; + return $a; + } + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } else { + $a = PEAR_Frontend::setFrontendClass($type); + return $a; + } + } + + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to conform to the PEAR naming standard of + * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) + * @param string $uiclass full class name + * @return PEAR_Frontend + * @static + */ + function &setFrontendClass($uiclass) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + if (!class_exists($uiclass)) { + $file = str_replace('_', '/', $uiclass) . '.php'; + if (PEAR_Frontend::isIncludeable($file)) { + include_once $file; + } + } + if (class_exists($uiclass)) { + $obj = &new $uiclass; + // quick test to see if this class implements a few of the most + // important frontend methods + if (is_a($obj, 'PEAR_Frontend')) { + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; + return $obj; + } else { + $err = PEAR::raiseError("not a frontend class: $uiclass"); + return $err; + } + } + $err = PEAR::raiseError("no such class: $uiclass"); + return $err; + } + + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to be a descendant of PEAR_Frontend + * @param PEAR_Frontend + * @return PEAR_Frontend + * @static + */ + function &setFrontendObject($uiobject) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + if (!is_a($uiobject, 'PEAR_Frontend')) { + $err = PEAR::raiseError('not a valid frontend class: (' . + get_class($uiobject) . ')'); + return $err; + } + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); + return $uiobject; + } + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + $fp = @fopen($path, 'r', true); + if ($fp) { + fclose($fp); + return true; + } + return false; + } + + /** + * @param PEAR_Config + */ + function setConfig(&$config) + { + } + + /** + * This can be overridden to allow session-based temporary file management + * + * By default, all files are deleted at the end of a session. The web installer + * needs to be able to sustain a list over many sessions in order to support + * user interaction with install scripts + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + /** + * Log an action + * + * @param string $msg the message to log + * @param boolean $append_crlf + * @return boolean true + * @abstract + */ + function log($msg, $append_crlf = true) + { + } + + /** + * Run a post-installation script + * + * @param array $scripts array of post-install scripts + * @abstract + */ + function runPostinstallScripts(&$scripts) + { + } + + /** + * Display human-friendly output formatted depending on the + * $command parameter. + * + * This should be able to handle basic output data with no command + * @param mixed $data data structure containing the information to display + * @param string $command command from which this method was called + * @abstract + */ + function outputData($data, $command = '_default') + { + } + + /** + * Display a modal form dialog and return the given input + * + * A frontend that requires multiple requests to retrieve and process + * data must take these needs into account, and implement the request + * handling code. + * @param string $command command from which this method was called + * @param array $prompts associative array. keys are the input field names + * and values are the description + * @param array $types array of input field types (text, password, + * etc.) keys have to be the same like in $prompts + * @param array $defaults array of default values. again keys have + * to be the same like in $prompts. Do not depend + * on a default value being set. + * @return array input sent by the user + * @abstract + */ + function userDialog($command, $prompts, $types = array(), $defaults = array()) + { + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Frontend/CLI.php b/vas/rest/class/PEAR/Frontend/CLI.php new file mode 100755 index 0000000000000000000000000000000000000000..0655aba161686fcb28b4fb1c0cb2ea38760f6bdb --- /dev/null +++ b/vas/rest/class/PEAR/Frontend/CLI.php @@ -0,0 +1,794 @@ +<?php +/** + * PEAR_Frontend_CLI + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: CLI.php,v 1.68 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ +/** + * base class + */ +require_once 'PEAR/Frontend.php'; + +/** + * Command-line Frontend for the PEAR Installer + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Frontend_CLI extends PEAR_Frontend +{ + // {{{ properties + + /** + * What type of user interface this frontend is for. + * @var string + * @access public + */ + var $type = 'CLI'; + var $lp = ''; // line prefix + + var $params = array(); + var $term = array( + 'bold' => '', + 'normal' => '', + ); + + // }}} + + // {{{ constructor + + function PEAR_Frontend_CLI() + { + parent::PEAR(); + $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 + if (function_exists('posix_isatty') && !posix_isatty(1)) { + // output is being redirected to a file or through a pipe + } elseif ($term) { + // XXX can use ncurses extension here, if available + if (preg_match('/^(xterm|vt220|linux)/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); + $this->term['normal']=sprintf("%c%c%c", 27, 91, 109); + } elseif (preg_match('/^vt100/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); + $this->term['normal']=sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); + } + } elseif (OS_WINDOWS) { + // XXX add ANSI codes here + } + } + + // }}} + + // {{{ displayLine(text) + + function displayLine($text) + { + trigger_error("PEAR_Frontend_CLI::displayLine deprecated", E_USER_ERROR); + } + + function _displayLine($text) + { + print "$this->lp$text\n"; + } + + // }}} + // {{{ display(text) + + function display($text) + { + trigger_error("PEAR_Frontend_CLI::display deprecated", E_USER_ERROR); + } + + function _display($text) + { + print $text; + } + + // }}} + // {{{ displayError(eobj) + + /** + * @param object PEAR_Error object + */ + function displayError($eobj) + { + return $this->_displayLine($eobj->getMessage()); + } + + // }}} + // {{{ displayFatalError(eobj) + + /** + * @param object PEAR_Error object + */ + function displayFatalError($eobj) + { + $this->displayError($eobj); + if (class_exists('PEAR_Config')) { + $config = &PEAR_Config::singleton(); + if ($config->get('verbose') > 5) { + if (function_exists('debug_print_backtrace')) { + debug_print_backtrace(); + } elseif (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + $raised = false; + foreach ($trace as $i => $frame) { + if (!$raised) { + if (isset($frame['class']) && strtolower($frame['class']) == + 'pear' && strtolower($frame['function']) == 'raiseerror') { + $raised = true; + } else { + continue; + } + } + if (!isset($frame['class'])) { + $frame['class'] = ''; + } + if (!isset($frame['type'])) { + $frame['type'] = ''; + } + if (!isset($frame['function'])) { + $frame['function'] = ''; + } + if (!isset($frame['line'])) { + $frame['line'] = ''; + } + $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); + } + } + } + } + exit(1); + } + + // }}} + // {{{ displayHeading(title) + + function displayHeading($title) + { + trigger_error("PEAR_Frontend_CLI::displayHeading deprecated", E_USER_ERROR); + } + + function _displayHeading($title) + { + print $this->lp.$this->bold($title)."\n"; + print $this->lp.str_repeat("=", strlen($title))."\n"; + } + + // }}} + + /** + * Instruct the runInstallScript method to skip a paramgroup that matches the + * id value passed in. + * + * This method is useful for dynamically configuring which sections of a post-install script + * will be run based on the user's setup, which is very useful for making flexible + * post-install scripts without losing the cross-Frontend ability to retrieve user input + * @param string + */ + function skipParamgroup($id) + { + $this->_skipSections[$id] = true; + } + + function runPostinstallScripts(&$scripts) + { + foreach ($scripts as $i => $script) { + $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); + } + } + + /** + * @param array $xml contents of postinstallscript tag + * @param object $script post-installation script + * @param string install|upgrade + */ + function runInstallScript($xml, &$script) + { + $this->_skipSections = array(); + if (!is_array($xml) || !isset($xml['paramgroup'])) { + $script->run(array(), '_default'); + } else { + $completedPhases = array(); + if (!isset($xml['paramgroup'][0])) { + $xml['paramgroup'] = array($xml['paramgroup']); + } + foreach ($xml['paramgroup'] as $group) { + if (isset($this->_skipSections[$group['id']])) { + // the post-install script chose to skip this section dynamically + continue; + } + if (isset($group['name'])) { + $paramname = explode('::', $group['name']); + if ($lastgroup['id'] != $paramname[0]) { + continue; + } + $group['name'] = $paramname[1]; + if (isset($answers)) { + if (isset($answers[$group['name']])) { + switch ($group['conditiontype']) { + case '=' : + if ($answers[$group['name']] != $group['value']) { + continue 2; + } + break; + case '!=' : + if ($answers[$group['name']] == $group['value']) { + continue 2; + } + break; + case 'preg_match' : + if (!@preg_match('/' . $group['value'] . '/', + $answers[$group['name']])) { + continue 2; + } + break; + default : + return; + } + } + } else { + return; + } + } + $lastgroup = $group; + if (isset($group['instructions'])) { + $this->_display($group['instructions']); + } + if (!isset($group['param'][0])) { + $group['param'] = array($group['param']); + } + if (isset($group['param'])) { + if (method_exists($script, 'postProcessPrompts')) { + $prompts = $script->postProcessPrompts($group['param'], $group['id']); + if (!is_array($prompts) || count($prompts) != count($group['param'])) { + $this->outputData('postinstall', 'Error: post-install script did not ' . + 'return proper post-processed prompts'); + $prompts = $group['param']; + } else { + foreach ($prompts as $i => $var) { + if (!is_array($var) || !isset($var['prompt']) || + !isset($var['name']) || + ($var['name'] != $group['param'][$i]['name']) || + ($var['type'] != $group['param'][$i]['type'])) { + $this->outputData('postinstall', 'Error: post-install script ' . + 'modified the variables or prompts, severe security risk. ' . + 'Will instead use the defaults from the package.xml'); + $prompts = $group['param']; + } + } + } + $answers = $this->confirmDialog($prompts); + } else { + $answers = $this->confirmDialog($group['param']); + } + } + if ((isset($answers) && $answers) || !isset($group['param'])) { + if (!isset($answers)) { + $answers = array(); + } + array_unshift($completedPhases, $group['id']); + if (!$script->run($answers, $group['id'])) { + $script->run($completedPhases, '_undoOnError'); + return; + } + } else { + $script->run($completedPhases, '_undoOnError'); + return; + } + } + } + } + + /** + * Ask for user input, confirm the answers and continue until the user is satisfied + * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => + * 'text to display', 'type' => 'string'[, default => 'default value']) + * @return array + */ + function confirmDialog($params) + { + $answers = array(); + $prompts = $types = array(); + foreach ($params as $param) { + $prompts[$param['name']] = $param['prompt']; + $types[$param['name']] = $param['type']; + if (isset($param['default'])) { + $answers[$param['name']] = $param['default']; + } else { + $answers[$param['name']] = ''; + } + } + $tried = false; + do { + if ($tried) { + $i = 1; + foreach ($answers as $var => $value) { + if (!strlen($value)) { + echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); + } + $i++; + } + } + $answers = $this->userDialog('', $prompts, $types, $answers); + $tried = true; + } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); + return $answers; + } + // {{{ userDialog(prompt, [type], [default]) + + function userDialog($command, $prompts, $types = array(), $defaults = array(), + $screensize = 20) + { + if (!is_array($prompts)) { + return array(); + } + $testprompts = array_keys($prompts); + $result = $defaults; + if (!defined('STDIN')) { + $fp = fopen('php://stdin', 'r'); + } else { + $fp = STDIN; + } + reset($prompts); + if (count($prompts) == 1 && $types[key($prompts)] == 'yesno') { + foreach ($prompts as $key => $prompt) { + $type = $types[$key]; + $default = @$defaults[$key]; + print "$prompt "; + if ($default) { + print "[$default] "; + } + print ": "; + if (version_compare(phpversion(), '5.0.0', '<')) { + $line = fgets($fp, 2048); + } else { + if (!defined('STDIN')) { + define('STDIN', fopen('php://stdin', 'r')); + } + $line = fgets(STDIN, 2048); + } + if ($default && trim($line) == "") { + $result[$key] = $default; + } else { + $result[$key] = trim($line); + } + } + return $result; + } + while (true) { + $descLength = max(array_map('strlen', $prompts)); + $descFormat = "%-{$descLength}s"; + $last = count($prompts); + + $i = 0; + foreach ($prompts as $n => $var) { + printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], isset($result[$n]) ? + $result[$n] : null); + } + + print "\n1-$last, 'all', 'abort', or Enter to continue: "; + $tmp = trim(fgets($fp, 1024)); + if (empty($tmp)) { + break; + } + if ($tmp == 'abort') { + return false; + } + if (isset($testprompts[(int)$tmp - 1])) { + $var = $testprompts[(int)$tmp - 1]; + $desc = $prompts[$var]; + $current = @$result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets($fp, 1024)); + if (trim($tmp) !== '') { + $result[$var] = trim($tmp); + } + } elseif ($tmp == 'all') { + foreach ($prompts as $var => $desc) { + $current = $result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets($fp, 1024)); + if (trim($tmp) !== '') { + $result[$var] = trim($tmp); + } + } + } + } + if (!defined('STDIN')) { + fclose($fp); + } + return $result; + } + + // }}} + // {{{ userConfirm(prompt, [default]) + + function userConfirm($prompt, $default = 'yes') + { + trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); + static $positives = array('y', 'yes', 'on', '1'); + static $negatives = array('n', 'no', 'off', '0'); + print "$this->lp$prompt [$default] : "; + $fp = fopen("php://stdin", "r"); + $line = fgets($fp, 2048); + fclose($fp); + $answer = strtolower(trim($line)); + if (empty($answer)) { + $answer = $default; + } + if (in_array($answer, $positives)) { + return true; + } + if (in_array($answer, $negatives)) { + return false; + } + if (in_array($default, $positives)) { + return true; + } + return false; + } + + // }}} + // {{{ startTable([params]) + + function startTable($params = array()) + { + trigger_error("PEAR_Frontend_CLI::startTable deprecated", E_USER_ERROR); + } + + function _startTable($params = array()) + { + $params['table_data'] = array(); + $params['widest'] = array(); // indexed by column + $params['highest'] = array(); // indexed by row + $params['ncols'] = 0; + $this->params = $params; + } + + // }}} + // {{{ tableRow(columns, [rowparams], [colparams]) + + function tableRow($columns, $rowparams = array(), $colparams = array()) + { + trigger_error("PEAR_Frontend_CLI::tableRow deprecated", E_USER_ERROR); + } + + function _tableRow($columns, $rowparams = array(), $colparams = array()) + { + $highest = 1; + for ($i = 0; $i < sizeof($columns); $i++) { + $col = &$columns[$i]; + if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { + $col = wordwrap($col, $colparams[$i]['wrap'], "\n", 0); + } + if (strpos($col, "\n") !== false) { + $multiline = explode("\n", $col); + $w = 0; + foreach ($multiline as $n => $line) { + if (strlen($line) > $w) { + $w = strlen($line); + } + } + $lines = sizeof($multiline); + } else { + $w = strlen($col); + } + + if (isset($this->params['widest'][$i])) { + if ($w > $this->params['widest'][$i]) { + $this->params['widest'][$i] = $w; + } + } else { + $this->params['widest'][$i] = $w; + } + $tmp = count_chars($columns[$i], 1); + // handle unix, mac and windows formats + $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; + if ($lines > $highest) { + $highest = $lines; + } + } + if (sizeof($columns) > $this->params['ncols']) { + $this->params['ncols'] = sizeof($columns); + } + $new_row = array( + 'data' => $columns, + 'height' => $highest, + 'rowparams' => $rowparams, + 'colparams' => $colparams, + ); + $this->params['table_data'][] = $new_row; + } + + // }}} + // {{{ endTable() + + function endTable() + { + trigger_error("PEAR_Frontend_CLI::endTable deprecated", E_USER_ERROR); + } + + function _endTable() + { + extract($this->params); + if (!empty($caption)) { + $this->_displayHeading($caption); + } + if (count($table_data) == 0) { + return; + } + if (!isset($width)) { + $width = $widest; + } else { + for ($i = 0; $i < $ncols; $i++) { + if (!isset($width[$i])) { + $width[$i] = $widest[$i]; + } + } + } + $border = false; + if (empty($border)) { + $cellstart = ''; + $cellend = ' '; + $rowend = ''; + $padrowend = false; + $borderline = ''; + } else { + $cellstart = '| '; + $cellend = ' '; + $rowend = '|'; + $padrowend = true; + $borderline = '+'; + foreach ($width as $w) { + $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); + $borderline .= '+'; + } + } + if ($borderline) { + $this->_displayLine($borderline); + } + for ($i = 0; $i < sizeof($table_data); $i++) { + extract($table_data[$i]); + if (!is_array($rowparams)) { + $rowparams = array(); + } + if (!is_array($colparams)) { + $colparams = array(); + } + $rowlines = array(); + if ($height > 1) { + for ($c = 0; $c < sizeof($data); $c++) { + $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); + if (sizeof($rowlines[$c]) < $height) { + $rowlines[$c] = array_pad($rowlines[$c], $height, ''); + } + } + } else { + for ($c = 0; $c < sizeof($data); $c++) { + $rowlines[$c] = array($data[$c]); + } + } + for ($r = 0; $r < $height; $r++) { + $rowtext = ''; + for ($c = 0; $c < sizeof($data); $c++) { + if (isset($colparams[$c])) { + $attribs = array_merge($rowparams, $colparams); + } else { + $attribs = $rowparams; + } + $w = isset($width[$c]) ? $width[$c] : 0; + //$cell = $data[$c]; + $cell = $rowlines[$c][$r]; + $l = strlen($cell); + if ($l > $w) { + $cell = substr($cell, 0, $w); + } + if (isset($attribs['bold'])) { + $cell = $this->bold($cell); + } + if ($l < $w) { + // not using str_pad here because we may + // add bold escape characters to $cell + $cell .= str_repeat(' ', $w - $l); + } + + $rowtext .= $cellstart . $cell . $cellend; + } + if (!$border) { + $rowtext = rtrim($rowtext); + } + $rowtext .= $rowend; + $this->_displayLine($rowtext); + } + } + if ($borderline) { + $this->_displayLine($borderline); + } + } + + // }}} + // {{{ outputData() + + function outputData($data, $command = '_default') + { + switch ($command) { + case 'channel-info': + foreach ($data as $type => $section) { + if ($type == 'main') { + $section['data'] = array_values($section['data']); + } + $this->outputData($section); + } + break; + case 'install': + case 'upgrade': + case 'upgrade-all': + if (isset($data['release_warnings'])) { + $this->_displayLine(''); + $this->_startTable(array( + 'border' => false, + 'caption' => 'Release Warnings' + )); + $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); + $this->_endTable(); + $this->_displayLine(''); + } + $this->_displayLine($data['data']); + break; + case 'search': + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + foreach($data['data'] as $category) { + foreach($category as $pkg) { + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + }; + $this->_endTable(); + break; + case 'list-all': + if (!isset($data['data'])) { + $this->_displayLine('No packages in channel'); + break; + } + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + foreach($data['data'] as $category) { + foreach($category as $pkg) { + unset($pkg[4]); + unset($pkg[5]); + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + }; + $this->_endTable(); + break; + case 'config-show': + $data['border'] = false; + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35)); + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); + } + foreach($data['data'] as $group) { + foreach($group as $value) { + if ($value[2] == '') { + $value[2] = "<not set>"; + } + $this->_tableRow($value, null, $opts); + } + } + $this->_endTable(); + break; + case 'remote-info': + $d = $data; + $data = array( + 'caption' => 'Package details:', + 'border' => false, + 'data' => array( + array("Latest", $data['stable']), + array("Installed", $data['installed']), + array("Package", $data['name']), + array("License", $data['license']), + array("Category", $data['category']), + array("Summary", $data['summary']), + array("Description", $data['description']), + ), + ); + if (isset($d['deprecated']) && $d['deprecated']) { + $conf = &PEAR_Config::singleton(); + $reg = $conf->getRegistry(); + $name = $reg->parsedPackageNameToString($d['deprecated'], true); + $data['data'][] = array('Deprecated! use', $name); + } + default: { + if (is_array($data)) { + $this->_startTable($data); + $count = count($data['data'][0]); + if ($count == 2) { + $opts = array(0 => array('wrap' => 25), + 1 => array('wrap' => 48) + ); + } elseif ($count == 3) { + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); + } else { + $opts = null; + } + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); + } + foreach($data['data'] as $row) { + $this->_tableRow($row, null, $opts); + } + $this->_endTable(); + } else { + $this->_displayLine($data); + } + } + } + } + + // }}} + // {{{ log(text) + + + function log($text, $append_crlf = true) + { + if ($append_crlf) { + return $this->_displayLine($text); + } + return $this->_display($text); + } + + + // }}} + // {{{ bold($text) + + function bold($text) + { + if (empty($this->term['bold'])) { + return strtoupper($text); + } + return $this->term['bold'] . $text . $this->term['normal']; + } + + // }}} +} + +?> diff --git a/vas/rest/class/PEAR/Installer.php b/vas/rest/class/PEAR/Installer.php new file mode 100755 index 0000000000000000000000000000000000000000..d3f316217b29cb085a40161490e8e189151b5028 --- /dev/null +++ b/vas/rest/class/PEAR/Installer.php @@ -0,0 +1,1723 @@ +<?php +/** + * PEAR_Installer + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Installer.php,v 1.253 2008/05/13 22:46:07 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Used for installation groups in package.xml 2.0 and platform exceptions + */ +require_once 'OS/Guess.php'; +require_once 'PEAR/Downloader.php'; + +define('PEAR_INSTALLER_NOBINARY', -240); +/** + * Administration class used to install PEAR packages and maintain the + * installed package database. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Martin Jansen <mj@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Installer extends PEAR_Downloader +{ + // {{{ properties + + /** name of the package directory, for example Foo-1.0 + * @var string + */ + var $pkgdir; + + /** directory where PHP code files go + * @var string + */ + var $phpdir; + + /** directory where PHP extension files go + * @var string + */ + var $extdir; + + /** directory where documentation goes + * @var string + */ + var $docdir; + + /** installation root directory (ala PHP's INSTALL_ROOT or + * automake's DESTDIR + * @var string + */ + var $installroot = ''; + + /** debug level + * @var int + */ + var $debug = 1; + + /** temporary directory + * @var string + */ + var $tmpdir; + + /** + * PEAR_Registry object used by the installer + * @var PEAR_Registry + */ + var $registry; + + /** + * array of PEAR_Downloader_Packages + * @var array + */ + var $_downloadedPackages; + + /** List of file transactions queued for an install/upgrade/uninstall. + * + * Format: + * array( + * 0 => array("rename => array("from-file", "to-file")), + * 1 => array("delete" => array("file-to-delete")), + * ... + * ) + * + * @var array + */ + var $file_operations = array(); + + // }}} + + // {{{ constructor + + /** + * PEAR_Installer constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Installer(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + $this->debug = $this->config->get('verbose'); + } + + function setOptions($options) + { + $this->_options = $options; + } + + function setConfig(&$config) + { + $this->config = &$config; + $this->_registry = &$config->getRegistry(); + } + + // }}} + + function _removeBackups($files) + { + foreach ($files as $path) { + $this->addFileOperation('removebackup', array($path)); + } + } + + // {{{ _deletePackageFiles() + + /** + * Delete a package's installed files, does not remove empty directories. + * + * @param string package name + * @param string channel name + * @param bool if true, then files are backed up first + * @return bool TRUE on success, or a PEAR error on failure + * @access protected + */ + function _deletePackageFiles($package, $channel = false, $backup = false) + { + if (!$channel) { + $channel = 'pear.php.net'; + } + if (!strlen($package)) { + return $this->raiseError("No package to uninstall given"); + } + if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { + // to avoid race conditions, include all possible needed files + require_once 'PEAR/Task/Common.php'; + require_once 'PEAR/Task/Replace.php'; + require_once 'PEAR/Task/Unixeol.php'; + require_once 'PEAR/Task/Windowseol.php'; + require_once 'PEAR/PackageFile/v1.php'; + require_once 'PEAR/PackageFile/v2.php'; + require_once 'PEAR/PackageFile/Generator/v1.php'; + require_once 'PEAR/PackageFile/Generator/v2.php'; + } + $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); + if ($filelist == null) { + return $this->raiseError("$channel/$package not installed"); + } + $ret = array(); + foreach ($filelist as $file => $props) { + if (empty($props['installed_as'])) { + continue; + } + $path = $props['installed_as']; + if ($backup) { + $this->addFileOperation('backup', array($path)); + $ret[] = $path; + } + $this->addFileOperation('delete', array($path)); + } + if ($backup) { + return $ret; + } + return true; + } + + // }}} + // {{{ _installFile() + + /** + * @param string filename + * @param array attributes from <file> tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private + */ + function _installFile($file, $atts, $tmp_path, $options) + { + // {{{ return if this file is meant for another platform + static $os; + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + if (isset($atts['platform'])) { + if (empty($os)) { + $os = new OS_Guess(); + } + if (strlen($atts['platform']) && $atts['platform']{0} == '!') { + $negate = true; + $platform = substr($atts['platform'], 1); + } else { + $negate = false; + $platform = $atts['platform']; + } + if ((bool) $os->matchSignature($platform) === $negate) { + $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); + return PEAR_INSTALLER_SKIPPED; + } + } + // }}} + + $channel = $this->pkginfo->getChannel(); + // {{{ assemble the destination paths + switch ($atts['role']) { + case 'src': + case 'extsrc': + $this->source_files++; + return; + case 'doc': + case 'data': + case 'test': + $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . + DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); + unset($atts['baseinstalldir']); + break; + case 'ext': + case 'php': + $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); + break; + case 'script': + $dest_dir = $this->config->get('bin_dir', null, $channel); + break; + default: + return $this->raiseError("Invalid role `$atts[role]' for file $file"); + } + $save_destdir = $dest_dir; + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + } + if (empty($atts['install-as'])) { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); + } else { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; + + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + array($dest_file, $orig_file)); + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $installedas_dest_dir = dirname($final_dest_file); + $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + $final_dest_file = $this->_prependPath($final_dest_file, + $this->_options['packagingroot']); + } else { + $installedas_dest_dir = dirname($final_dest_file); + $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + } + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { + return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); + } + // }}} + + if (empty($this->_options['register-only']) && + (!file_exists($dest_dir) || !is_dir($dest_dir))) { + if (!$this->mkDirHier($dest_dir)) { + return $this->raiseError("failed to mkdir $dest_dir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $dest_dir"); + } + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (empty($atts['replacements'])) { + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($atts['md5sum'])) { + $md5sum = md5_file($dest_file); + } + } else { + // {{{ file with replacements + if (!file_exists($orig_file)) { + return $this->raiseError("file does not exist", + PEAR_INSTALLER_FAILED); + } + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } + if (isset($atts['md5sum'])) { + $md5sum = md5($contents); + } + $subst_from = $subst_to = array(); + foreach ($atts['replacements'] as $a) { + $to = ''; + if ($a['type'] == 'php-const') { + if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { + eval("\$to = $a[to];"); + } else { + if (!isset($options['soft'])) { + $this->log(0, "invalid php-const replacement: $a[to]"); + } + continue; + } + } elseif ($a['type'] == 'pear-config') { + if ($a['to'] == 'master_server') { + $chan = $this->_registry->getChannel($channel); + if (!PEAR::isError($chan)) { + $to = $chan->getServer(); + } else { + $to = $this->config->get($a['to'], null, $channel); + } + } else { + $to = $this->config->get($a['to'], null, $channel); + } + if (is_null($to)) { + if (!isset($options['soft'])) { + $this->log(0, "invalid pear-config replacement: $a[to]"); + } + continue; + } + } elseif ($a['type'] == 'package-info') { + if ($t = $this->pkginfo->packageInfo($a['to'])) { + $to = $t; + } else { + if (!isset($options['soft'])) { + $this->log(0, "invalid package-info replacement: $a[to]"); + } + continue; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + if (@fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + fclose($wp); + // }}} + } + // {{{ check the md5 + if (isset($md5sum)) { + if (strtolower($md5sum) === strtolower($atts['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } + } + // }}} + // {{{ set file permissions + if (!OS_WINDOWS) { + if ($atts['role'] == 'script') { + $mode = 0777 & ~(int)octdec($this->config->get('umask')); + $this->log(3, "+ chmod +x $dest_file"); + } else { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + } + if ($atts['role'] != 'src') { + $this->addFileOperation("chmod", array($mode, $dest_file)); + if (!@chmod($dest_file, $mode)) { + if (!isset($options['soft'])) { + $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); + } + } + } + } + // }}} + if ($atts['role'] == 'src') { + rename($dest_file, $final_dest_file); + $this->log(2, "renamed source file $dest_file to $final_dest_file"); + } else { + $this->addFileOperation("rename", array($dest_file, $final_dest_file, + $atts['role'] == 'ext')); + } + } + // Store the full path where the file was installed for easy unistall + if ($atts['role'] != 'script') { + $loc = $this->config->get($atts['role'] . '_dir'); + } else { + $loc = $this->config->get('bin_dir'); + } + if ($atts['role'] != 'src') { + $this->addFileOperation("installed_as", array($file, $installed_as, + $loc, + dirname(substr($installedas_dest_file, strlen($loc))))); + } + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; + } + + // }}} + // {{{ _installFile2() + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string filename + * @param array attributes from <file> tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private + */ + function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) + { + $atts = $real_atts; + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + + $channel = $pkg->getChannel(); + // {{{ assemble the destination paths + if (!in_array($atts['attribs']['role'], + PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . + "' for file $file"); + } + $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); + $err = $role->setup($this, $pkg, $atts['attribs'], $file); + if (PEAR::isError($err)) { + return $err; + } + if (!$role->isInstallable()) { + return; + } + $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); + if (PEAR::isError($info)) { + return $info; + } else { + list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; + } + if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { + return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); + } + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $final_dest_file = $this->_prependPath($final_dest_file, + $this->_options['packagingroot']); + } + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + // }}} + + if (empty($this->_options['register-only'])) { + if (!file_exists($dest_dir) || !is_dir($dest_dir)) { + if (!$this->mkDirHier($dest_dir)) { + return $this->raiseError("failed to mkdir $dest_dir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $dest_dir"); + } + } + $attribs = $atts['attribs']; + unset($atts['attribs']); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!count($atts)) { // no tasks + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($attribs['md5sum'])) { + $md5sum = md5_file($dest_file); + } + } else { // file with tasks + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } + if (isset($attribs['md5sum'])) { + $md5sum = md5($contents); + } + foreach ($atts as $tag => $raw) { + $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), + array('', '_'), $tag); + $task = "PEAR_Task_$tag"; + $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); + if (!$task->isScript()) { // scripts are only handled after installation + $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); + $res = $task->startSession($pkg, $contents, $final_dest_file); + if ($res === false) { + continue; // skip this file + } + if (PEAR::isError($res)) { + return $res; + } + $contents = $res; // save changes + } + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + if (fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + fclose($wp); + } + } + // {{{ check the md5 + if (isset($md5sum)) { + if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } + } else { + $real_atts['attribs']['md5sum'] = md5_file($dest_file); + } + // }}} + // {{{ set file permissions + if (!OS_WINDOWS) { + if ($role->isExecutable()) { + $mode = 0777 & ~(int)octdec($this->config->get('umask')); + $this->log(3, "+ chmod +x $dest_file"); + } else { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + } + if ($attribs['role'] != 'src') { + $this->addFileOperation("chmod", array($mode, $dest_file)); + if (!@chmod($dest_file, $mode)) { + if (!isset($options['soft'])) { + $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); + } + } + } + } + // }}} + if ($attribs['role'] == 'src') { + rename($dest_file, $final_dest_file); + $this->log(2, "renamed source file $dest_file to $final_dest_file"); + } else { + $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); + } + } + // Store the full path where the file was installed for easy uninstall + if ($attribs['role'] != 'src') { + $loc = $this->config->get($role->getLocationConfig(), null, $channel); + $this->addFileOperation("installed_as", array($file, $installed_as, + $loc, + dirname(substr($installed_as, strlen($loc))))); + } + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; + } + + // }}} + // {{{ addFileOperation() + + /** + * Add a file operation to the current file transaction. + * + * @see startFileTransaction() + * @param string $type This can be one of: + * - rename: rename a file ($data has 3 values) + * - backup: backup an existing file ($data has 1 value) + * - removebackup: clean up backups created during install ($data has 1 value) + * - chmod: change permissions on a file ($data has 2 values) + * - delete: delete a file ($data has 1 value) + * - rmdir: delete a directory if empty ($data has 1 value) + * - installed_as: mark a file as installed ($data has 4 values). + * @param array $data For all file operations, this array must contain the + * full path to the file or directory that is being operated on. For + * the rename command, the first parameter must be the file to rename, + * the second its new name, the third whether this is a PHP extension. + * + * The installed_as operation contains 4 elements in this order: + * 1. Filename as listed in the filelist element from package.xml + * 2. Full path to the installed file + * 3. Full path from the php_dir configuration variable used in this + * installation + * 4. Relative path from the php_dir that this file is installed in + */ + function addFileOperation($type, $data) + { + if (!is_array($data)) { + return $this->raiseError('Internal Error: $data in addFileOperation' + . ' must be an array, was ' . gettype($data)); + } + if ($type == 'chmod') { + $octmode = decoct($data[0]); + $this->log(3, "adding to transaction: $type $octmode $data[1]"); + } else { + $this->log(3, "adding to transaction: $type " . implode(" ", $data)); + } + $this->file_operations[] = array($type, $data); + } + + // }}} + // {{{ startFileTransaction() + + function startFileTransaction($rollback_in_case = false) + { + if (count($this->file_operations) && $rollback_in_case) { + $this->rollbackFileTransaction(); + } + $this->file_operations = array(); + } + + // }}} + // {{{ commitFileTransaction() + + function commitFileTransaction() + { + $n = count($this->file_operations); + $this->log(2, "about to commit $n file operations"); + // {{{ first, check permissions and such manually + $errors = array(); + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'rename': + if (!file_exists($data[0])) { + $errors[] = "cannot rename file $data[0], doesn't exist"; + } + // check that dest dir. is writable + if (!is_writable(dirname($data[1]))) { + $errors[] = "permission denied ($type): $data[1]"; + } + break; + case 'chmod': + // check that file is writable + if (!is_writable($data[1])) { + $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); + } + break; + case 'delete': + if (!file_exists($data[0])) { + $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); + } + // check that directory is writable + if (file_exists($data[0])) { + if (!is_writable(dirname($data[0]))) { + $errors[] = "permission denied ($type): $data[0]"; + } else { + // make sure the file to be deleted can be opened for writing + $fp = false; + if (!is_dir($data[0]) && + (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { + $errors[] = "permission denied ($type): $data[0]"; + } elseif ($fp) { + fclose($fp); + } + } + } + break; + } + + } + // }}} + $m = sizeof($errors); + if ($m > 0) { + foreach ($errors as $error) { + if (!isset($this->_options['soft'])) { + $this->log(1, $error); + } + } + if (!isset($this->_options['ignore-errors'])) { + return false; + } + } + $this->_dirtree = array(); + // {{{ really commit the transaction + foreach ($this->file_operations as $i => $tr) { + if (!$tr) { + // support removal of non-existing backups + continue; + } + list($type, $data) = $tr; + switch ($type) { + case 'backup': + if (!file_exists($data[0])) { + $this->file_operations[$i] = false; + break; + } + if (!@copy($data[0], $data[0] . '.bak')) { + $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . + '.bak ' . $php_errormsg); + return false; + } + $this->log(3, "+ backup $data[0] to $data[0].bak"); + break; + case 'removebackup': + if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { + unlink($data[0] . '.bak'); + $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); + } + break; + case 'rename': + if (file_exists($data[1])) { + $test = @unlink($data[1]); + } else { + $test = null; + } + if (!$test && file_exists($data[1])) { + if ($data[2]) { + $extra = ', this extension must be installed manually. Rename to "' . + basename($data[1]) . '"'; + } else { + $extra = ''; + } + if (!isset($this->_options['soft'])) { + $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . + $data[0] . $extra); + } + if (!isset($this->_options['ignore-errors'])) { + return false; + } + } + // permissions issues with rename - copy() is far superior + $perms = @fileperms($data[0]); + if (!@copy($data[0], $data[1])) { + $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . + ' ' . $php_errormsg); + return false; + } + // copy over permissions, otherwise they are lost + @chmod($data[1], $perms); + @unlink($data[0]); + $this->log(3, "+ mv $data[0] $data[1]"); + break; + case 'chmod': + if (!@chmod($data[1], $data[0])) { + $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . + decoct($data[0]) . ' ' . $php_errormsg); + return false; + } + $octmode = decoct($data[0]); + $this->log(3, "+ chmod $octmode $data[1]"); + break; + case 'delete': + if (file_exists($data[0])) { + if (!@unlink($data[0])) { + $this->log(1, 'Could not delete ' . $data[0] . ' ' . + $php_errormsg); + return false; + } + $this->log(3, "+ rm $data[0]"); + } + break; + case 'rmdir': + if (file_exists($data[0])) { + do { + $testme = opendir($data[0]); + while (false !== ($entry = readdir($testme))) { + if ($entry == '.' || $entry == '..') { + continue; + } + closedir($testme); + break 2; // this directory is not empty and can't be + // deleted + } + closedir($testme); + if (!@rmdir($data[0])) { + $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . + $php_errormsg); + return false; + } + $this->log(3, "+ rmdir $data[0]"); + } while (false); + } + break; + case 'installed_as': + $this->pkginfo->setInstalledAs($data[0], $data[1]); + if (!isset($this->_dirtree[dirname($data[1])])) { + $this->_dirtree[dirname($data[1])] = true; + $this->pkginfo->setDirtree(dirname($data[1])); + + while(!empty($data[3]) && dirname($data[3]) != $data[3] && + $data[3] != '/' && $data[3] != '\\') { + $this->pkginfo->setDirtree($pp = + $this->_prependPath($data[3], $data[2])); + $this->_dirtree[$pp] = true; + $data[3] = dirname($data[3]); + } + } + break; + } + } + // }}} + $this->log(2, "successfully committed $n file operations"); + $this->file_operations = array(); + return true; + } + + // }}} + // {{{ rollbackFileTransaction() + + function rollbackFileTransaction() + { + $n = count($this->file_operations); + $this->log(2, "rolling back $n file operations"); + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'backup': + if (file_exists($data[0] . '.bak')) { + if (file_exists($data[0] && is_writable($data[0]))) { + unlink($data[0]); + } + @copy($data[0] . '.bak', $data[0]); + $this->log(3, "+ restore $data[0] from $data[0].bak"); + } + break; + case 'removebackup': + if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { + unlink($data[0] . '.bak'); + $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); + } + break; + case 'rename': + @unlink($data[0]); + $this->log(3, "+ rm $data[0]"); + break; + case 'mkdir': + @rmdir($data[0]); + $this->log(3, "+ rmdir $data[0]"); + break; + case 'chmod': + break; + case 'delete': + break; + case 'installed_as': + $this->pkginfo->setInstalledAs($data[0], false); + break; + } + } + $this->pkginfo->resetDirtree(); + $this->file_operations = array(); + } + + // }}} + // {{{ mkDirHier($dir) + + function mkDirHier($dir) + { + $this->addFileOperation('mkdir', array($dir)); + return parent::mkDirHier($dir); + } + + // }}} + // {{{ download() + + /** + * Download any files and their dependencies, if necessary + * + * @param array a mixed list of package names, local files, or package.xml + * @param PEAR_Config + * @param array options from the command line + * @param array this is the array that will be populated with packages to + * install. Format of each entry: + * + * <code> + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * </code> + * @param array this will be populated with any error messages + * @param false private recursion variable + * @param false private recursion variable + * @param false private recursion variable + * @deprecated in favor of PEAR_Downloader + */ + function download($packages, $options, &$config, &$installpackages, + &$errors, $installed = false, $willinstall = false, $state = false) + { + // trickiness: initialize here + parent::PEAR_Downloader($this->ui, $options, $config); + $ret = parent::download($packages); + $errors = $this->getErrorMsgs(); + $installpackages = $this->getDownloadedPackages(); + trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . + "in favor of PEAR_Downloader class", E_USER_WARNING); + return $ret; + } + + // }}} + // {{{ _parsePackageXml() + + function _parsePackageXml(&$descfile, &$tmpdir) + { + if (substr($descfile, -4) == '.xml') { + $tmpdir = false; + } else { + // {{{ Decompress pack in tmp dir ------------------------------------- + + // To allow relative package file names + $descfile = realpath($descfile); + + if (PEAR::isError($tmpdir = System::mktemp('-d'))) { + return $tmpdir; + } + $this->log(3, '+ tmp dir created at ' . $tmpdir); + // }}} + } + // Parse xml file ----------------------------------------------- + $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($p)) { + if (is_array($p->getUserInfo())) { + foreach ($p->getUserInfo() as $err) { + $loglevel = $err['level'] == 'error' ? 0 : 1; + if (!isset($this->_options['soft'])) { + $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); + } + } + } + return $this->raiseError('Installation failed: invalid package file'); + } else { + $descfile = $p->getPackageFile(); + } + return $p; + } + + // }}} + /** + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array + */ + function setDownloadedPackages(&$pkgs) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($pkgs); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return $err; + } + $this->_downloadedPackages = &$pkgs; + } + + /** + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array + */ + function setUninstallPackages(&$pkgs) + { + $this->_downloadedPackages = &$pkgs; + } + + function getInstallPackages() + { + return $this->_downloadedPackages; + } + + // {{{ install() + + /** + * Installs the files within the package file specified. + * + * @param string|PEAR_Downloader_Package $pkgfile path to the package file, + * or a pre-initialized packagefile object + * @param array $options + * recognized options: + * - installroot : optional prefix directory for installation + * - force : force installation + * - register-only : update registry but don't install files + * - upgrade : upgrade existing install + * - soft : fail silently + * - nodeps : ignore dependency conflicts/missing dependencies + * - alldeps : install all dependencies + * - onlyreqdeps : install only required dependencies + * + * @return array|PEAR_Error package info if successful + */ + + function install($pkgfile, $options = array()) + { + $this->_options = $options; + $this->_registry = &$this->config->getRegistry(); + if (is_object($pkgfile)) { + $dlpkg = &$pkgfile; + $pkg = $pkgfile->getPackageFile(); + $pkgfile = $pkg->getArchiveFile(); + $descfile = $pkg->getPackageFile(); + $tmpdir = dirname($descfile); + } else { + $descfile = $pkgfile; + $tmpdir = ''; + if (PEAR::isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir))) { + return $pkg; + } + } + + if (realpath($descfile) != realpath($pkgfile)) { + $tar = new Archive_Tar($pkgfile); + if (!$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); + } + } + + $pkgname = $pkg->getName(); + $channel = $pkg->getChannel(); + if (isset($this->_options['packagingroot'])) { + $regdir = $this->_prependPath( + $this->config->get('php_dir', null, 'pear.php.net'), + $this->_options['packagingroot']); + $packrootphp_dir = $this->_prependPath( + $this->config->get('php_dir', null, $channel), + $this->_options['packagingroot']); + } + + if (isset($options['installroot'])) { + $this->config->setInstallRoot($options['installroot']); + $this->_registry = &$this->config->getRegistry(); + $installregistry = &$this->_registry; + $this->installroot = ''; // all done automagically now + $php_dir = $this->config->get('php_dir', null, $channel); + } else { + $this->config->setInstallRoot(false); + $this->_registry = &$this->config->getRegistry(); + if (isset($this->_options['packagingroot'])) { + $installregistry = &new PEAR_Registry($regdir); + if (!$installregistry->channelExists($channel, true)) { + // we need to fake a channel-discover of this channel + $chanobj = $this->_registry->getChannel($channel, true); + $installregistry->addChannel($chanobj); + } + $php_dir = $packrootphp_dir; + } else { + $installregistry = &$this->_registry; + $php_dir = $this->config->get('php_dir', null, $channel); + } + $this->installroot = ''; + } + + // {{{ checks to do when not in "force" mode + if (empty($options['force']) && + (file_exists($this->config->get('php_dir')) && + is_dir($this->config->get('php_dir')))) { + $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); + $instfilelist = $pkg->getInstallationFileList(true); + if (PEAR::isError($instfilelist)) { + return $instfilelist; + } + // ensure we have the most accurate registry + $installregistry->flushFileMap(); + $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); + if (PEAR::isError($test)) { + return $test; + } + if (sizeof($test)) { + $pkgs = $this->getInstallPackages(); + $found = false; + foreach ($pkgs as $param) { + if ($pkg->isSubpackageOf($param)) { + $found = true; + break; + } + } + if ($found) { + // subpackages can conflict with earlier versions of parent packages + $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_array($info)) { + if (strtolower($info[1]) == strtolower($param->getPackage()) && + strtolower($info[0]) == strtolower($param->getChannel())) { + unset($test[$file]); + unset($parentreg['filelist'][$file]); + } + } else { + if (strtolower($param->getChannel()) != 'pear.php.net') { + continue; + } + if (strtolower($info) == strtolower($param->getPackage())) { + unset($test[$file]); + unset($parentreg['filelist'][$file]); + } + } + } + $pfk = &new PEAR_PackageFile($this->config); + $parentpkg = &$pfk->fromArray($parentreg); + $installregistry->updatePackage2($parentpkg); + } + if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_string($info)) { + // pear.php.net packages are always stored as strings + if (strtolower($info) == strtolower($param->getPackage())) { + // upgrading existing package + unset($test[$file]); + } + } + } + } + if (sizeof($test)) { + $msg = "$channel/$pkgname: conflicting files found:\n"; + $longest = max(array_map("strlen", array_keys($test))); + $fmt = "%${longest}s (%s)\n"; + foreach ($test as $file => $info) { + if (!is_array($info)) { + $info = array('pear.php.net', $info); + } + $info = $info[0] . '/' . $info[1]; + $msg .= sprintf($fmt, $file, $info); + } + if (!isset($options['ignore-errors'])) { + return $this->raiseError($msg); + } else { + if (!isset($options['soft'])) { + $this->log(0, "WARNING: $msg"); + } + } + } + } + } + // }}} + + $this->startFileTransaction(); + + if (empty($options['upgrade']) && empty($options['soft'])) { + // checks to do only when installing new packages + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + if (empty($options['force']) && $test) { + return $this->raiseError("$channel/$pkgname is already installed"); + } + } else { + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + if ($test) { + $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $v2 = $pkg->getVersion(); + $cmp = version_compare("$v1", "$v2", 'gt'); + if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { + return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + } + if (empty($options['register-only'])) { + // when upgrading, remove old release's files first: + if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, + true))) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } else { + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } + } else { + $backedup = $err; + } + } + } + } + + // {{{ Copy files to dest dir --------------------------------------- + + // info from the package it self we want to access from _installFile + $this->pkginfo = &$pkg; + // used to determine whether we should build any C code + $this->source_files = 0; + + $savechannel = $this->config->get('default_channel'); + if (empty($options['register-only']) && !is_dir($php_dir)) { + if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { + return $this->raiseError("no installation destination directory '$php_dir'\n"); + } + } + + $tmp_path = dirname($descfile); + if (substr($pkgfile, -4) != '.xml') { + $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); + } + + $this->configSet('default_channel', $channel); + // {{{ install files + + $ver = $pkg->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + $filelist = $pkg->getInstallationFilelist(); + } else { + $filelist = $pkg->getFileList(); + } + if (PEAR::isError($filelist)) { + return $filelist; + } + $p = &$installregistry->getPackage($pkgname, $channel); + if (empty($options['register-only']) && $p) { + $dirtree = $p->getDirTree(); + } else { + $dirtree = false; + } + $pkg->resetFilelist(); + $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), + 'version', $pkg->getChannel())); + foreach ($filelist as $file => $atts) { + if ($pkg->getPackagexmlVersion() == '1.0') { + $this->expectError(PEAR_INSTALLER_FAILED); + $res = $this->_installFile($file, $atts, $tmp_path, $options); + $this->popExpect(); + } else { + $this->expectError(PEAR_INSTALLER_FAILED); + $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); + $this->popExpect(); + } + if (PEAR::isError($res)) { + if (empty($options['ignore-errors'])) { + $this->rollbackFileTransaction(); + if ($res->getMessage() == "file does not exist") { + $this->raiseError("file $file in package.xml does not exist"); + } + return $this->raiseError($res); + } else { + if (!isset($options['soft'])) { + $this->log(0, "Warning: " . $res->getMessage()); + } + } + } + $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; + if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { + // Register files that were installed + $pkg->installedFile($file, $atts); + } + } + // }}} + + // {{{ compile and install source files + if ($this->source_files > 0 && empty($options['nobuild'])) { + if (PEAR::isError($err = + $this->_compileSourceFiles($savechannel, $pkg))) { + return $err; + } + } + // }}} + + if (isset($backedup)) { + $this->_removeBackups($backedup); + } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); + } + // }}} + + $ret = false; + $installphase = 'install'; + $oldversion = false; + // {{{ Register that the package is installed ----------------------- + if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + if (!empty($options['force']) && $test) { + $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $installregistry->deletePackage($pkgname, $usechannel); + } + $ret = $installregistry->addPackage2($pkg); + } else { + if ($dirtree) { + $this->startFileTransaction(); + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + $this->commitFileTransaction(); + } + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + // new: upgrade installs a package if it isn't installed + if (!$test) { + $ret = $installregistry->addPackage2($pkg); + } else { + if ($usechannel != $channel) { + $installregistry->deletePackage($pkgname, $usechannel); + $ret = $installregistry->addPackage2($pkg); + } else { + $ret = $installregistry->updatePackage2($pkg); + } + $installphase = 'upgrade'; + } + } + if (!$ret) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError("Adding package $channel/$pkgname to registry failed"); + } + // }}} + $this->configSet('default_channel', $savechannel); + if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist + if (PEAR_Task_Common::hasPostinstallTasks()) { + PEAR_Task_Common::runPostinstallTasks($installphase); + } + } + return $pkg->toArray(true); + } + + // }}} + + // {{{ _compileSourceFiles() + /** + * @param string + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function _compileSourceFiles($savechannel, &$filelist) + { + require_once 'PEAR/Builder.php'; + $this->log(1, "$this->source_files source files, building"); + $bob = &new PEAR_Builder($this->ui); + $bob->debug = $this->debug; + $built = $bob->build($filelist, array(&$this, '_buildCallback')); + if (PEAR::isError($built)) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $built; + } + $this->log(1, "\nBuild process completed successfully"); + foreach ($built as $ext) { + $bn = basename($ext['file']); + list($_ext_name, $_ext_suff) = explode('.', $bn); + if ($_ext_suff == '.so' || $_ext_suff == '.dll') { + if (extension_loaded($_ext_name)) { + $this->raiseError("Extension '$_ext_name' already loaded. " . + 'Please unload it in your php.ini file ' . + 'prior to install or upgrade'); + } + $role = 'ext'; + } else { + $role = 'src'; + } + $dest = $ext['dest']; + $packagingroot = ''; + if (isset($this->_options['packagingroot'])) { + $packagingroot = $this->_options['packagingroot']; + } + $copyto = $this->_prependPath($dest, $packagingroot); + if ($copyto != $dest) { + $this->log(1, "Installing '$dest' as '$copyto'"); + } else { + $this->log(1, "Installing '$dest'"); + } + $copydir = dirname($copyto); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!file_exists($copydir) || !is_dir($copydir)) { + if (!$this->mkDirHier($copydir)) { + return $this->raiseError("failed to mkdir $copydir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $copydir"); + } + if (!@copy($ext['file'], $copyto)) { + return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ cp $ext[file] $copyto"); + $this->addFileOperation('rename', array($ext['file'], $copyto)); + if (!OS_WINDOWS) { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + $this->addFileOperation('chmod', array($mode, $copyto)); + if (!@chmod($copyto, $mode)) { + $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); + } + } + } + + if ($filelist->getPackageXmlVersion() == '1.0') { + $filelist->installedFile($bn, array( + 'role' => $role, + 'name' => $bn, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + )); + } else { + $filelist->installedFile($bn, array('attribs' => array( + 'role' => $role, + 'name' => $bn, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + ))); + } + } + } + + // }}} + function &getUninstallPackages() + { + return $this->_downloadedPackages; + } + // {{{ uninstall() + + /** + * Uninstall a package + * + * This method removes all files installed by the application, and then + * removes any empty directories. + * @param string package name + * @param array Command-line options. Possibilities include: + * + * - installroot: base installation dir, if not the default + * - register-only : update registry but don't remove files + * - nodeps: do not process dependencies of other packages to ensure + * uninstallation does not break things + */ + function uninstall($package, $options = array()) + { + if (isset($options['installroot'])) { + $this->config->setInstallRoot($options['installroot']); + $this->installroot = ''; + } else { + $this->config->setInstallRoot(''); + $this->installroot = ''; + } + $this->_registry = &$this->config->getRegistry(); + if (is_object($package)) { + $channel = $package->getChannel(); + $pkg = $package; + $package = $pkg->getPackage(); + } else { + $pkg = false; + $info = $this->_registry->parsePackageName($package, + $this->config->get('default_channel')); + $channel = $info['channel']; + $package = $info['package']; + } + $savechannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $channel); + if (!is_object($pkg)) { + $pkg = $this->_registry->getPackage($package, $channel); + } + if (!$pkg) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError($this->_registry->parsedPackageNameToString( + array( + 'channel' => $channel, + 'package' => $package + ), true) . ' not installed'); + } + if ($pkg->getInstalledBinary()) { + // this is just an alias for a binary package + return $this->_registry->deletePackage($package, $channel); + } + $filelist = $pkg->getFilelist(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $depchecker = &new PEAR_Dependency2($this->config, $options, + array('channel' => $channel, 'package' => $package), + PEAR_VALIDATE_UNINSTALLING); + $e = $depchecker->validatePackageUninstall($this); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($e); + } else { + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $e->getMessage()); + } + } + } elseif (is_array($e)) { + if (!isset($options['soft'])) { + $this->log(0, $e[0]); + } + } + $this->pkginfo = &$pkg; + // pretty much nothing happens if we are only registering the uninstall + if (empty($options['register-only'])) { + // {{{ Delete the files + $this->startFileTransaction(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { + PEAR::popErrorHandling(); + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } else { + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } + } else { + PEAR::popErrorHandling(); + } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } elseif (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } else { + $this->startFileTransaction(); + if ($dirtree = $pkg->getDirTree()) { + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + } else { + $this->configSet('default_channel', $savechannel); + return $this->_registry->deletePackage($package, $channel); + } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } elseif (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } + } + // }}} + } + + $this->configSet('default_channel', $savechannel); + // Register that the package is no longer installed + return $this->_registry->deletePackage($package, $channel); + } + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * It also removes duplicate dependencies + * @param array an array of PEAR_PackageFile_v[1/2] objects + * @return array|PEAR_Error array of array(packagefilename, package.xml contents) + */ + function sortPackagesForUninstall(&$packages) + { + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); + if (PEAR::isError($this->_dependencyDB)) { + return $this->_dependencyDB; + } + usort($packages, array(&$this, '_sortUninstall')); + } + + function _sortUninstall($a, $b) + { + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant + } + if ($a->getDeps() && !$b->getDeps()) { + return -1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return 1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependencyDB->dependsOn($a, $b)) { + return -1; + } + if ($this->_dependencyDB->dependsOn($b, $a)) { + return 1; + } + return 0; + } + + // }}} + // {{{ _sortDirs() + function _sortDirs($a, $b) + { + if (strnatcmp($a, $b) == -1) return 1; + if (strnatcmp($a, $b) == 1) return -1; + return 0; + } + + // }}} + + // {{{ _buildCallback() + + function _buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } + + // }}} +} + +// {{{ md5_file() utility function +if (!function_exists("md5_file")) { + function md5_file($filename) { + if (!$fd = @fopen($file, 'r')) { + return false; + } + fclose($fd); + return md5(file_get_contents($filename)); + } +} +// }}} + +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role.php b/vas/rest/class/PEAR/Installer/Role.php new file mode 100755 index 0000000000000000000000000000000000000000..3b50db3c5a753554262f5b97ddf6f39629570f4f --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role.php @@ -0,0 +1,253 @@ +<?php +/** + * PEAR_Installer_Role + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Role.php,v 1.20 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class for installer roles + */ +require_once 'PEAR/Installer/Role/Common.php'; +require_once 'PEAR/XMLParser.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role +{ + /** + * Set up any additional configuration variables that file roles require + * + * Never call this directly, it is called by the PEAR_Config constructor + * @param PEAR_Config + * @access private + * @static + */ + function initializeConfig(&$config) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { + if (!$info['config_vars']) { + continue; + } + $config->_addConfigVars($class, $info['config_vars']); + } + } + + /** + * @param PEAR_PackageFile_v2 + * @param string role name + * @param PEAR_Config + * @return PEAR_Installer_Role_Common + * @static + */ + function &factory($pkg, $role, &$config) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + $a = false; + return $a; + } + $a = 'PEAR_Installer_Role_' . ucfirst($role); + if (!class_exists($a)) { + require_once str_replace('_', '/', $a) . '.php'; + } + $b = new $a($config); + return $b; + } + + /** + * Get a list of file roles that are valid for the particular release type. + * + * For instance, src files serve no purpose in regular php releases. + * @param string + * @param bool clear cache + * @return array + * @static + */ + function getValidRoles($release, $clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + static $ret = array(); + if ($clear) { + $ret = array(); + } + if (isset($ret[$release])) { + return $ret[$release]; + } + $ret[$release] = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if (in_array($release, $okreleases['releasetypes'])) { + $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + return $ret[$release]; + } + + /** + * Get a list of roles that require their files to be installed + * + * Most roles must be installed, but src and package roles, for instance + * are pseudo-roles. src files are compiled into a new extension. Package + * roles are actually fully bundled releases of a package + * @param bool clear cache + * @return array + * @static + */ + function getInstallableRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + static $ret; + if ($clear) { + unset($ret); + } + if (!isset($ret)) { + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['installable']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + } + return $ret; + } + + /** + * Return an array of roles that are affected by the baseinstalldir attribute + * + * Most roles ignore this attribute, and instead install directly into: + * PackageName/filepath + * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php + * @param bool clear cache + * @return array + * @static + */ + function getBaseinstallRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + static $ret; + if ($clear) { + unset($ret); + } + if (!isset($ret)) { + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['honorsbaseinstall']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + } + return $ret; + } + + /** + * Return an array of file roles that should be analyzed for PHP content at package time, + * like the "php" role. + * @param bool clear cache + * @return array + * @static + */ + function getPhpRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + static $ret; + if ($clear) { + unset($ret); + } + if (!isset($ret)) { + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['phpfile']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + } + return $ret; + } + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * @param string which directory to look for classes, defaults to + * the Installer/Roles subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * @access public + * @static + */ + function registerRoles($dir = null) + { + $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Role'; + } + if (!file_exists($dir) || !is_dir($dir)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); + } + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); + } + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + continue; + } + $class = "PEAR_Installer_Role_".substr($entry, 0, -4); + // List of roles + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { + $file = "$dir/$entry"; + $parser->parse(file_get_contents($file)); + $data = $parser->getData(); + if (!is_array($data['releasetypes'])) { + $data['releasetypes'] = array($data['releasetypes']); + } + $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; + } + } + closedir($dp); + ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); + PEAR_Installer_Role::getBaseinstallRoles(true); + PEAR_Installer_Role::getInstallableRoles(true); + PEAR_Installer_Role::getPhpRoles(true); + PEAR_Installer_Role::getValidRoles('****', true); + return true; + } +} +?> diff --git a/vas/rest/class/PEAR/Installer/Role/Cfg.php b/vas/rest/class/PEAR/Installer/Role/Cfg.php new file mode 100755 index 0000000000000000000000000000000000000000..1f85ebb5a1970e71adc58591b992776fb3c3d34d --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Cfg.php @@ -0,0 +1,108 @@ +<?php +/** + * PEAR_Installer_Role_Cfg + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2007-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Cfg.php,v 1.8 2008/05/14 21:26:30 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.7.0 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2007-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.7.0 + */ +class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common +{ + /** + * @var PEAR_Installer + */ + var $installer; + /** + * the md5 of the original file + * + * @var unknown_type + */ + var $md5 = null; + /** + * Do any unusual setup here + * @param PEAR_Installer + * @param PEAR_PackageFile_v2 + * @param array file attributes + * @param string file name + */ + function setup(&$installer, $pkg, $atts, $file) + { + $this->installer = &$installer; + $reg = &$this->installer->config->getRegistry(); + $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel()); + if ($package) { + $filelist = $package->getFilelist(); + if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) { + $this->md5 = $filelist[$file]['md5sum']; + } + } + } + + function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + { + $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer); + if (@file_exists($test[2]) && @file_exists($test[3])) { + $md5 = md5_file($test[2]); + // configuration has already been installed, check for mods + if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) { + // configuration has been modified, so save our version as + // configfile-version + $old = $test[2]; + $test[2] .= '.new-' . $pkg->getVersion(); + // backup original and re-install it + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $tmpcfg = $this->config->get('temp_dir'); + $newloc = System::mkdir(array('-p', $tmpcfg)); + if (!$newloc) { + // try temp_dir + $newloc = System::mktemp(array('-d')); + if (!$newloc || PEAR::isError($newloc)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Could not save existing configuration file '. + $old . ', unable to install. Please set temp_dir ' . + 'configuration variable to a writeable location and try again'); + } + } else { + $newloc = $tmpcfg; + } + $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile'); + if (!@copy($old, $temp_file)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Could not save existing configuration file '. + $old . ', unable to install. Please set temp_dir ' . + 'configuration variable to a writeable location and try again'); + } + PEAR::popErrorHandling(); + $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file"); + $this->installer->addFileOperation('rename', array($temp_file, $old, false)); + $this->installer->addFileOperation('delete', array($temp_file)); + } + } + return $test; + } +} +?> diff --git a/vas/rest/class/PEAR/Installer/Role/Cfg.xml b/vas/rest/class/PEAR/Installer/Role/Cfg.xml new file mode 100755 index 0000000000000000000000000000000000000000..7a415dc466ab9a58607c4bed3dc2900f7414e76d --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Cfg.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>cfg_dir</locationconfig> + <honorsbaseinstall /> + <unusualbaseinstall>1</unusualbaseinstall> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Common.php b/vas/rest/class/PEAR/Installer/Role/Common.php new file mode 100755 index 0000000000000000000000000000000000000000..32cd821751b15cda89184a6c1793ac591cdf8e80 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Common.php @@ -0,0 +1,180 @@ +<?php +/** + * Base class for all installation roles. + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Common.php,v 1.12 2006/10/19 23:55:32 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class for all installation roles. + * + * This class allows extensibility of file roles. Packages with complex + * customization can now provide custom file roles along with the possibility of + * adding configuration values to match. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Common +{ + /** + * @var PEAR_Config + * @access protected + */ + var $config; + + /** + * @param PEAR_Config + */ + function PEAR_Installer_Role_Common(&$config) + { + $this->config = $config; + } + + /** + * Retrieve configuration information about a file role from its XML info + * + * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" + * @return array + */ + function getInfo($role) + { + if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { + return PEAR::raiseError('Unknown Role class: "' . $role . '"'); + } + return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; + } + + /** + * This is called for each file to set up the directories and files + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array attributes from the <file> tag + * @param string file name + * @return array an array consisting of: + * + * 1 the original, pre-baseinstalldir installation directory + * 2 the final installation directory + * 3 the full path to the final location of the file + * 4 the location of the pre-installation file + */ + function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + if (!$roleInfo['locationconfig']) { + return false; + } + if ($roleInfo['honorsbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, + $pkg->getChannel()); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + } elseif ($roleInfo['unusualbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + } else { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); + } + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + } + if (empty($atts['install-as'])) { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); + } else { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; + + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + + list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + array($dest_dir, $dest_file, $orig_file)); + return array($save_destdir, $dest_dir, $dest_file, $orig_file); + } + + /** + * Get the name of the configuration variable that specifies the location of this file + * @return string|false + */ + function getLocationConfig() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['locationconfig']; + } + + /** + * Do any unusual setup here + * @param PEAR_Installer + * @param PEAR_PackageFile_v2 + * @param array file attributes + * @param string file name + */ + function setup(&$installer, $pkg, $atts, $file) + { + } + + function isExecutable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['executable']; + } + + function isInstallable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['installable']; + } + + function isExtension() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['phpextension']; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Data.php b/vas/rest/class/PEAR/Installer/Role/Data.php new file mode 100755 index 0000000000000000000000000000000000000000..394f68ce26bb0b07c60faee5fe2970372d040d1d --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Data.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Data + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Data.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Data.xml b/vas/rest/class/PEAR/Installer/Role/Data.xml new file mode 100755 index 0000000000000000000000000000000000000000..eae63720d3ba4022846e7ed36880cd71af734139 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Data.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>data_dir</locationconfig> + <honorsbaseinstall /> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Doc.php b/vas/rest/class/PEAR/Installer/Role/Doc.php new file mode 100755 index 0000000000000000000000000000000000000000..b974dc6846c03efc198bbcfa57958fb2e1f7db42 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Doc.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Doc + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Doc.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Doc.xml b/vas/rest/class/PEAR/Installer/Role/Doc.xml new file mode 100755 index 0000000000000000000000000000000000000000..173afba011a0f45e88da18659bd47c3cb47471a1 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Doc.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>doc_dir</locationconfig> + <honorsbaseinstall /> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Ext.php b/vas/rest/class/PEAR/Installer/Role/Ext.php new file mode 100755 index 0000000000000000000000000000000000000000..38c0e9af40b7fa9e46106614e6cd1d7a13defe7d --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Ext.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Ext + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Ext.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Ext.xml b/vas/rest/class/PEAR/Installer/Role/Ext.xml new file mode 100755 index 0000000000000000000000000000000000000000..e2940fe1f22cbe7dc1c7a1b02e97e0c6ab9ca7ef --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Ext.xml @@ -0,0 +1,12 @@ +<role version="1.0"> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>ext_dir</locationconfig> + <honorsbaseinstall>1</honorsbaseinstall> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension>1</phpextension> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Php.php b/vas/rest/class/PEAR/Installer/Role/Php.php new file mode 100755 index 0000000000000000000000000000000000000000..f232b723df8613b7277400e90b3aeace97c413b6 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Php.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Php + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Php.php,v 1.8 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Php.xml b/vas/rest/class/PEAR/Installer/Role/Php.xml new file mode 100755 index 0000000000000000000000000000000000000000..6b9a0e67af9ac8d90543de9575988a7da3427da8 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Php.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>php_dir</locationconfig> + <honorsbaseinstall>1</honorsbaseinstall> + <unusualbaseinstall /> + <phpfile>1</phpfile> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Script.php b/vas/rest/class/PEAR/Installer/Role/Script.php new file mode 100755 index 0000000000000000000000000000000000000000..b8affdbb450a4b5c236cb3de6b15076ae9764b2b --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Script.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Script + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Script.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Script.xml b/vas/rest/class/PEAR/Installer/Role/Script.xml new file mode 100755 index 0000000000000000000000000000000000000000..e732cf2af6f8e3731d0f91068053787eb23ad4eb --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Script.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>bin_dir</locationconfig> + <honorsbaseinstall>1</honorsbaseinstall> + <unusualbaseinstall /> + <phpfile /> + <executable>1</executable> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Src.php b/vas/rest/class/PEAR/Installer/Role/Src.php new file mode 100755 index 0000000000000000000000000000000000000000..68d07e4dc9bf4cee6215139d85bef37c8f042f4d --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Src.php @@ -0,0 +1,40 @@ +<?php +/** + * PEAR_Installer_Role_Src + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Src.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common +{ + function setup(&$installer, $pkg, $atts, $file) + { + $installer->source_files++; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Src.xml b/vas/rest/class/PEAR/Installer/Role/Src.xml new file mode 100755 index 0000000000000000000000000000000000000000..103483402f04d40d2630ffa2e46d866c039d806a --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Src.xml @@ -0,0 +1,12 @@ +<role version="1.0"> + <releasetypes>extsrc</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <installable>1</installable> + <locationconfig>temp_dir</locationconfig> + <honorsbaseinstall /> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Test.php b/vas/rest/class/PEAR/Installer/Role/Test.php new file mode 100755 index 0000000000000000000000000000000000000000..63979b93735886f33e7a33064f53a3443bc2317c --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Test.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Test + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Test.php,v 1.7 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Test.xml b/vas/rest/class/PEAR/Installer/Role/Test.xml new file mode 100755 index 0000000000000000000000000000000000000000..51d5b894e07b695f5766bf10a7c70a8630eefa61 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Test.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>test_dir</locationconfig> + <honorsbaseinstall /> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Www.php b/vas/rest/class/PEAR/Installer/Role/Www.php new file mode 100755 index 0000000000000000000000000000000000000000..801097f998180c7d0a530788ba81be9ef73d0bce --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Www.php @@ -0,0 +1,34 @@ +<?php +/** + * PEAR_Installer_Role_Www + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2007-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Www.php,v 1.2 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.7.0 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 2007-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.7.0 + */ +class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Installer/Role/Www.xml b/vas/rest/class/PEAR/Installer/Role/Www.xml new file mode 100755 index 0000000000000000000000000000000000000000..7598be38892571d3eca2d32d24b5413377ad6099 --- /dev/null +++ b/vas/rest/class/PEAR/Installer/Role/Www.xml @@ -0,0 +1,15 @@ +<role version="1.0"> + <releasetypes>php</releasetypes> + <releasetypes>extsrc</releasetypes> + <releasetypes>extbin</releasetypes> + <releasetypes>zendextsrc</releasetypes> + <releasetypes>zendextbin</releasetypes> + <installable>1</installable> + <locationconfig>www_dir</locationconfig> + <honorsbaseinstall>1</honorsbaseinstall> + <unusualbaseinstall /> + <phpfile /> + <executable /> + <phpextension /> + <config_vars /> +</role> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Mail.php b/vas/rest/class/PEAR/Mail.php new file mode 100755 index 0000000000000000000000000000000000000000..51421869e0e2e995926a7b90e17112e9b056fe6b --- /dev/null +++ b/vas/rest/class/PEAR/Mail.php @@ -0,0 +1,245 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ +// +// $Id: Mail.php,v 1.20 2007/10/06 17:00:00 chagenbu Exp $ + +require_once 'PEAR.php'; + +/** + * PEAR's Mail:: interface. Defines the interface for implementing + * mailers under the PEAR hierarchy, and provides supporting functions + * useful in multiple mailer backends. + * + * @access public + * @version $Revision: 1.20 $ + * @package Mail + */ +class Mail +{ + /** + * Line terminator used for separating header lines. + * @var string + */ + var $sep = "\r\n"; + + /** + * Provides an interface for generating Mail:: objects of various + * types + * + * @param string $driver The kind of Mail:: object to instantiate. + * @param array $params The parameters to pass to the Mail:: object. + * @return object Mail a instance of the driver class or if fails a PEAR Error + * @access public + */ + function &factory($driver, $params = array()) + { + $driver = strtolower($driver); + @include_once 'Mail/' . $driver . '.php'; + $class = 'Mail_' . $driver; + if (class_exists($class)) { + $mailer = new $class($params); + return $mailer; + } else { + return PEAR::raiseError('Unable to find class for driver ' . $driver); + } + } + + /** + * Implements Mail::send() function using php's built-in mail() + * command. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * + * @access public + * @deprecated use Mail_mail::send instead + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // if we're passed an array of recipients, implode it. + if (is_array($recipients)) { + $recipients = implode(', ', $recipients); + } + + // get the Subject out of the headers array so that we can + // pass it as a seperate argument to mail(). + $subject = ''; + if (isset($headers['Subject'])) { + $subject = $headers['Subject']; + unset($headers['Subject']); + } + + // flatten the headers out. + list(, $text_headers) = Mail::prepareHeaders($headers); + + return mail($recipients, $subject, $body, $text_headers); + } + + /** + * Sanitize an array of mail headers by removing any additional header + * strings present in a legitimate header's value. The goal of this + * filter is to prevent mail injection attacks. + * + * @param array $headers The associative array of headers to sanitize. + * + * @access private + */ + function _sanitizeHeaders(&$headers) + { + foreach ($headers as $key => $value) { + $headers[$key] = + preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', + null, $value); + } + } + + /** + * Take an array of mail headers and return a string containing + * text usable in sending a message. + * + * @param array $headers The array of headers to prepare, in an associative + * array, where the array key is the header name (ie, + * 'Subject'), and the array value is the header + * value (ie, 'test'). The header produced from those + * values would be 'Subject: test'. + * + * @return mixed Returns false if it encounters a bad address, + * otherwise returns an array containing two + * elements: Any From: address found in the headers, + * and the plain text version of the headers. + * @access private + */ + function prepareHeaders($headers) + { + $lines = array(); + $from = null; + + foreach ($headers as $key => $value) { + if (strcasecmp($key, 'From') === 0) { + include_once 'Mail/RFC822.php'; + $parser = new Mail_RFC822(); + $addresses = $parser->parseAddressList($value, 'localhost', false); + if (is_a($addresses, 'PEAR_Error')) { + return $addresses; + } + + $from = $addresses[0]->mailbox . '@' . $addresses[0]->host; + + // Reject envelope From: addresses with spaces. + if (strstr($from, ' ')) { + return false; + } + + $lines[] = $key . ': ' . $value; + } elseif (strcasecmp($key, 'Received') === 0) { + $received = array(); + if (is_array($value)) { + foreach ($value as $line) { + $received[] = $key . ': ' . $line; + } + } + else { + $received[] = $key . ': ' . $value; + } + // Put Received: headers at the top. Spam detectors often + // flag messages with Received: headers after the Subject: + // as spam. + $lines = array_merge($received, $lines); + } else { + // If $value is an array (i.e., a list of addresses), convert + // it to a comma-delimited string of its elements (addresses). + if (is_array($value)) { + $value = implode(', ', $value); + } + $lines[] = $key . ': ' . $value; + } + } + + return array($from, join($this->sep, $lines)); + } + + /** + * Take a set of recipients and parse them, returning an array of + * bare addresses (forward paths) that can be passed to sendmail + * or an smtp server with the rcpt to: command. + * + * @param mixed Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. + * + * @return mixed An array of forward paths (bare addresses) or a PEAR_Error + * object if the address list could not be parsed. + * @access private + */ + function parseRecipients($recipients) + { + include_once 'Mail/RFC822.php'; + + // if we're passed an array, assume addresses are valid and + // implode them before parsing. + if (is_array($recipients)) { + $recipients = implode(', ', $recipients); + } + + // Parse recipients, leaving out all personal info. This is + // for smtp recipients, etc. All relevant personal information + // should already be in the headers. + $addresses = Mail_RFC822::parseAddressList($recipients, 'localhost', false); + + // If parseAddressList() returned a PEAR_Error object, just return it. + if (is_a($addresses, 'PEAR_Error')) { + return $addresses; + } + + $recipients = array(); + if (is_array($addresses)) { + foreach ($addresses as $ob) { + $recipients[] = $ob->mailbox . '@' . $ob->host; + } + } + + return $recipients; + } + +} diff --git a/vas/rest/class/PEAR/Mail/RFC822.php b/vas/rest/class/PEAR/Mail/RFC822.php new file mode 100755 index 0000000000000000000000000000000000000000..09938c48d5c349e182b1ec55e97d478b0611afa5 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/RFC822.php @@ -0,0 +1,940 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Copyright (c) 2001-2002, Richard Heyes | +// | All rights reserved. | +// | | +// | Redistribution and use in source and binary forms, with or without | +// | modification, are permitted provided that the following conditions | +// | are met: | +// | | +// | o Redistributions of source code must retain the above copyright | +// | notice, this list of conditions and the following disclaimer. | +// | o Redistributions in binary form must reproduce the above copyright | +// | notice, this list of conditions and the following disclaimer in the | +// | documentation and/or other materials provided with the distribution.| +// | o The names of the authors may not be used to endorse or promote | +// | products derived from this software without specific prior written | +// | permission. | +// | | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | +// | | +// +-----------------------------------------------------------------------+ +// | Authors: Richard Heyes <richard@phpguru.org> | +// | Chuck Hagenbuch <chuck@horde.org> | +// +-----------------------------------------------------------------------+ + +/** + * RFC 822 Email address list validation Utility + * + * What is it? + * + * This class will take an address string, and parse it into it's consituent + * parts, be that either addresses, groups, or combinations. Nested groups + * are not supported. The structure it returns is pretty straight forward, + * and is similar to that provided by the imap_rfc822_parse_adrlist(). Use + * print_r() to view the structure. + * + * How do I use it? + * + * $address_string = 'My Group: "Richard" <richard@localhost> (A comment), ted@example.com (Ted Bloggs), Barney;'; + * $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', true) + * print_r($structure); + * + * @author Richard Heyes <richard@phpguru.org> + * @author Chuck Hagenbuch <chuck@horde.org> + * @version $Revision: 1.24 $ + * @license BSD + * @package Mail + */ +class Mail_RFC822 { + + /** + * The address being parsed by the RFC822 object. + * @var string $address + */ + var $address = ''; + + /** + * The default domain to use for unqualified addresses. + * @var string $default_domain + */ + var $default_domain = 'localhost'; + + /** + * Should we return a nested array showing groups, or flatten everything? + * @var boolean $nestGroups + */ + var $nestGroups = true; + + /** + * Whether or not to validate atoms for non-ascii characters. + * @var boolean $validate + */ + var $validate = true; + + /** + * The array of raw addresses built up as we parse. + * @var array $addresses + */ + var $addresses = array(); + + /** + * The final array of parsed address information that we build up. + * @var array $structure + */ + var $structure = array(); + + /** + * The current error message, if any. + * @var string $error + */ + var $error = null; + + /** + * An internal counter/pointer. + * @var integer $index + */ + var $index = null; + + /** + * The number of groups that have been found in the address list. + * @var integer $num_groups + * @access public + */ + var $num_groups = 0; + + /** + * A variable so that we can tell whether or not we're inside a + * Mail_RFC822 object. + * @var boolean $mailRFC822 + */ + var $mailRFC822 = true; + + /** + * A limit after which processing stops + * @var int $limit + */ + var $limit = null; + + /** + * Sets up the object. The address must either be set here or when + * calling parseAddressList(). One or the other. + * + * @access public + * @param string $address The address(es) to validate. + * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. + * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. + * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. + * + * @return object Mail_RFC822 A new Mail_RFC822 object. + */ + function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) + { + if (isset($address)) $this->address = $address; + if (isset($default_domain)) $this->default_domain = $default_domain; + if (isset($nest_groups)) $this->nestGroups = $nest_groups; + if (isset($validate)) $this->validate = $validate; + if (isset($limit)) $this->limit = $limit; + } + + /** + * Starts the whole process. The address must either be set here + * or when creating the object. One or the other. + * + * @access public + * @param string $address The address(es) to validate. + * @param string $default_domain Default domain/host etc. + * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. + * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. + * + * @return array A structured array of addresses. + */ + function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) + { + if (!isset($this) || !isset($this->mailRFC822)) { + $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); + return $obj->parseAddressList(); + } + + if (isset($address)) $this->address = $address; + if (isset($default_domain)) $this->default_domain = $default_domain; + if (isset($nest_groups)) $this->nestGroups = $nest_groups; + if (isset($validate)) $this->validate = $validate; + if (isset($limit)) $this->limit = $limit; + + $this->structure = array(); + $this->addresses = array(); + $this->error = null; + $this->index = null; + + // Unfold any long lines in $this->address. + $this->address = preg_replace('/\r?\n/', "\r\n", $this->address); + $this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address); + + while ($this->address = $this->_splitAddresses($this->address)); + + if ($this->address === false || isset($this->error)) { + require_once 'PEAR/PEAR.php'; + return PEAR::raiseError($this->error); + } + + // Validate each address individually. If we encounter an invalid + // address, stop iterating and return an error immediately. + foreach ($this->addresses as $address) { + $valid = $this->_validateAddress($address); + + if ($valid === false || isset($this->error)) { + require_once 'PEAR/PEAR.php'; + return PEAR::raiseError($this->error); + } + + if (!$this->nestGroups) { + $this->structure = array_merge($this->structure, $valid); + } else { + $this->structure[] = $valid; + } + } + + return $this->structure; + } + + /** + * Splits an address into separate addresses. + * + * @access private + * @param string $address The addresses to split. + * @return boolean Success or failure. + */ + function _splitAddresses($address) + { + if (!empty($this->limit) && count($this->addresses) == $this->limit) { + return ''; + } + + if ($this->_isGroup($address) && !isset($this->error)) { + $split_char = ';'; + $is_group = true; + } elseif (!isset($this->error)) { + $split_char = ','; + $is_group = false; + } elseif (isset($this->error)) { + return false; + } + + // Split the string based on the above ten or so lines. + $parts = explode($split_char, $address); + $string = $this->_splitCheck($parts, $split_char); + + // If a group... + if ($is_group) { + // If $string does not contain a colon outside of + // brackets/quotes etc then something's fubar. + + // First check there's a colon at all: + if (strpos($string, ':') === false) { + $this->error = 'Invalid address: ' . $string; + return false; + } + + // Now check it's outside of brackets/quotes: + if (!$this->_splitCheck(explode(':', $string), ':')) { + return false; + } + + // We must have a group at this point, so increase the counter: + $this->num_groups++; + } + + // $string now contains the first full address/group. + // Add to the addresses array. + $this->addresses[] = array( + 'address' => trim($string), + 'group' => $is_group + ); + + // Remove the now stored address from the initial line, the +1 + // is to account for the explode character. + $address = trim(substr($address, strlen($string) + 1)); + + // If the next char is a comma and this was a group, then + // there are more addresses, otherwise, if there are any more + // chars, then there is another address. + if ($is_group && substr($address, 0, 1) == ','){ + $address = trim(substr($address, 1)); + return $address; + + } elseif (strlen($address) > 0) { + return $address; + + } else { + return ''; + } + + // If you got here then something's off + return false; + } + + /** + * Checks for a group at the start of the string. + * + * @access private + * @param string $address The address to check. + * @return boolean Whether or not there is a group at the start of the string. + */ + function _isGroup($address) + { + // First comma not in quotes, angles or escaped: + $parts = explode(',', $address); + $string = $this->_splitCheck($parts, ','); + + // Now we have the first address, we can reliably check for a + // group by searching for a colon that's not escaped or in + // quotes or angle brackets. + if (count($parts = explode(':', $string)) > 1) { + $string2 = $this->_splitCheck($parts, ':'); + return ($string2 !== $string); + } else { + return false; + } + } + + /** + * A common function that will check an exploded string. + * + * @access private + * @param array $parts The exloded string. + * @param string $char The char that was exploded on. + * @return mixed False if the string contains unclosed quotes/brackets, or the string on success. + */ + function _splitCheck($parts, $char) + { + $string = $parts[0]; + + for ($i = 0; $i < count($parts); $i++) { + if ($this->_hasUnclosedQuotes($string) + || $this->_hasUnclosedBrackets($string, '<>') + || $this->_hasUnclosedBrackets($string, '[]') + || $this->_hasUnclosedBrackets($string, '()') + || substr($string, -1) == '\\') { + if (isset($parts[$i + 1])) { + $string = $string . $char . $parts[$i + 1]; + } else { + $this->error = 'Invalid address spec. Unclosed bracket or quotes'; + return false; + } + } else { + $this->index = $i; + break; + } + } + + return $string; + } + + /** + * Checks if a string has unclosed quotes or not. + * + * @access private + * @param string $string The string to check. + * @return boolean True if there are unclosed quotes inside the string, + * false otherwise. + */ + function _hasUnclosedQuotes($string) + { + $string = trim($string); + $iMax = strlen($string); + $in_quote = false; + $i = $slashes = 0; + + for (; $i < $iMax; ++$i) { + switch ($string[$i]) { + case '\\': + ++$slashes; + break; + + case '"': + if ($slashes % 2 == 0) { + $in_quote = !$in_quote; + } + // Fall through to default action below. + + default: + $slashes = 0; + break; + } + } + + return $in_quote; + } + + /** + * Checks if a string has an unclosed brackets or not. IMPORTANT: + * This function handles both angle brackets and square brackets; + * + * @access private + * @param string $string The string to check. + * @param string $chars The characters to check for. + * @return boolean True if there are unclosed brackets inside the string, false otherwise. + */ + function _hasUnclosedBrackets($string, $chars) + { + $num_angle_start = substr_count($string, $chars[0]); + $num_angle_end = substr_count($string, $chars[1]); + + $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]); + $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]); + + if ($num_angle_start < $num_angle_end) { + $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')'; + return false; + } else { + return ($num_angle_start > $num_angle_end); + } + } + + /** + * Sub function that is used only by hasUnclosedBrackets(). + * + * @access private + * @param string $string The string to check. + * @param integer &$num The number of occurences. + * @param string $char The character to count. + * @return integer The number of occurences of $char in $string, adjusted for backslashes. + */ + function _hasUnclosedBracketsSub($string, &$num, $char) + { + $parts = explode($char, $string); + for ($i = 0; $i < count($parts); $i++){ + if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) + $num--; + if (isset($parts[$i + 1])) + $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1]; + } + + return $num; + } + + /** + * Function to begin checking the address. + * + * @access private + * @param string $address The address to validate. + * @return mixed False on failure, or a structured array of address information on success. + */ + function _validateAddress($address) + { + $is_group = false; + $addresses = array(); + + if ($address['group']) { + $is_group = true; + + // Get the group part of the name + $parts = explode(':', $address['address']); + $groupname = $this->_splitCheck($parts, ':'); + $structure = array(); + + // And validate the group part of the name. + if (!$this->_validatePhrase($groupname)){ + $this->error = 'Group name did not validate.'; + return false; + } else { + // Don't include groups if we are not nesting + // them. This avoids returning invalid addresses. + if ($this->nestGroups) { + $structure = new stdClass; + $structure->groupname = $groupname; + } + } + + $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':'))); + } + + // If a group then split on comma and put into an array. + // Otherwise, Just put the whole address in an array. + if ($is_group) { + while (strlen($address['address']) > 0) { + $parts = explode(',', $address['address']); + $addresses[] = $this->_splitCheck($parts, ','); + $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ','))); + } + } else { + $addresses[] = $address['address']; + } + + // Check that $addresses is set, if address like this: + // Groupname:; + // Then errors were appearing. + if (!count($addresses)){ + $this->error = 'Empty group.'; + return false; + } + + // Trim the whitespace from all of the address strings. + array_map('trim', $addresses); + + // Validate each mailbox. + // Format could be one of: name <geezer@domain.com> + // geezer@domain.com + // geezer + // ... or any other format valid by RFC 822. + for ($i = 0; $i < count($addresses); $i++) { + if (!$this->validateMailbox($addresses[$i])) { + if (empty($this->error)) { + $this->error = 'Validation failed for: ' . $addresses[$i]; + } + return false; + } + } + + // Nested format + if ($this->nestGroups) { + if ($is_group) { + $structure->addresses = $addresses; + } else { + $structure = $addresses[0]; + } + + // Flat format + } else { + if ($is_group) { + $structure = array_merge($structure, $addresses); + } else { + $structure = $addresses; + } + } + + return $structure; + } + + /** + * Function to validate a phrase. + * + * @access private + * @param string $phrase The phrase to check. + * @return boolean Success or failure. + */ + function _validatePhrase($phrase) + { + // Splits on one or more Tab or space. + $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); + + $phrase_parts = array(); + while (count($parts) > 0){ + $phrase_parts[] = $this->_splitCheck($parts, ' '); + for ($i = 0; $i < $this->index + 1; $i++) + array_shift($parts); + } + + foreach ($phrase_parts as $part) { + // If quoted string: + if (substr($part, 0, 1) == '"') { + if (!$this->_validateQuotedString($part)) { + return false; + } + continue; + } + + // Otherwise it's an atom: + if (!$this->_validateAtom($part)) return false; + } + + return true; + } + + /** + * Function to validate an atom which from rfc822 is: + * atom = 1*<any CHAR except specials, SPACE and CTLs> + * + * If validation ($this->validate) has been turned off, then + * validateAtom() doesn't actually check anything. This is so that you + * can split a list of addresses up before encoding personal names + * (umlauts, etc.), for example. + * + * @access private + * @param string $atom The string to check. + * @return boolean Success or failure. + */ + function _validateAtom($atom) + { + if (!$this->validate) { + // Validation has been turned off; assume the atom is okay. + return true; + } + + // Check for any char from ASCII 0 - ASCII 127 + if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) { + return false; + } + + // Check for specials: + if (preg_match('/[][()<>@,;\\:" ]/', $atom)) { + return false; + } + + // Check for control characters (ASCII 0-31): + if (preg_match('/[\\x00-\\x1F]+/', $atom)) { + return false; + } + + return true; + } + + /** + * Function to validate quoted string, which is: + * quoted-string = <"> *(qtext/quoted-pair) <"> + * + * @access private + * @param string $qstring The string to check + * @return boolean Success or failure. + */ + function _validateQuotedString($qstring) + { + // Leading and trailing " + $qstring = substr($qstring, 1, -1); + + // Perform check, removing quoted characters first. + return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring)); + } + + /** + * Function to validate a mailbox, which is: + * mailbox = addr-spec ; simple address + * / phrase route-addr ; name and route-addr + * + * @access public + * @param string &$mailbox The string to check. + * @return boolean Success or failure. + */ + function validateMailbox(&$mailbox) + { + // A couple of defaults. + $phrase = ''; + $comment = ''; + $comments = array(); + + // Catch any RFC822 comments and store them separately. + $_mailbox = $mailbox; + while (strlen(trim($_mailbox)) > 0) { + $parts = explode('(', $_mailbox); + $before_comment = $this->_splitCheck($parts, '('); + if ($before_comment != $_mailbox) { + // First char should be a (. + $comment = substr(str_replace($before_comment, '', $_mailbox), 1); + $parts = explode(')', $comment); + $comment = $this->_splitCheck($parts, ')'); + $comments[] = $comment; + + // +1 is for the trailing ) + $_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1); + } else { + break; + } + } + + foreach ($comments as $comment) { + $mailbox = str_replace("($comment)", '', $mailbox); + } + + $mailbox = trim($mailbox); + + // Check for name + route-addr + if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') { + $parts = explode('<', $mailbox); + $name = $this->_splitCheck($parts, '<'); + + $phrase = trim($name); + $route_addr = trim(substr($mailbox, strlen($name.'<'), -1)); + + if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) { + return false; + } + + // Only got addr-spec + } else { + // First snip angle brackets if present. + if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') { + $addr_spec = substr($mailbox, 1, -1); + } else { + $addr_spec = $mailbox; + } + + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } + + // Construct the object that will be returned. + $mbox = new stdClass(); + + // Add the phrase (even if empty) and comments + $mbox->personal = $phrase; + $mbox->comment = isset($comments) ? $comments : array(); + + if (isset($route_addr)) { + $mbox->mailbox = $route_addr['local_part']; + $mbox->host = $route_addr['domain']; + $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : ''; + } else { + $mbox->mailbox = $addr_spec['local_part']; + $mbox->host = $addr_spec['domain']; + } + + $mailbox = $mbox; + return true; + } + + /** + * This function validates a route-addr which is: + * route-addr = "<" [route] addr-spec ">" + * + * Angle brackets have already been removed at the point of + * getting to this function. + * + * @access private + * @param string $route_addr The string to check. + * @return mixed False on failure, or an array containing validated address/route information on success. + */ + function _validateRouteAddr($route_addr) + { + // Check for colon. + if (strpos($route_addr, ':') !== false) { + $parts = explode(':', $route_addr); + $route = $this->_splitCheck($parts, ':'); + } else { + $route = $route_addr; + } + + // If $route is same as $route_addr then the colon was in + // quotes or brackets or, of course, non existent. + if ($route === $route_addr){ + unset($route); + $addr_spec = $route_addr; + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } else { + // Validate route part. + if (($route = $this->_validateRoute($route)) === false) { + return false; + } + + $addr_spec = substr($route_addr, strlen($route . ':')); + + // Validate addr-spec part. + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } + + if (isset($route)) { + $return['adl'] = $route; + } else { + $return['adl'] = ''; + } + + $return = array_merge($return, $addr_spec); + return $return; + } + + /** + * Function to validate a route, which is: + * route = 1#("@" domain) ":" + * + * @access private + * @param string $route The string to check. + * @return mixed False on failure, or the validated $route on success. + */ + function _validateRoute($route) + { + // Split on comma. + $domains = explode(',', trim($route)); + + foreach ($domains as $domain) { + $domain = str_replace('@', '', trim($domain)); + if (!$this->_validateDomain($domain)) return false; + } + + return $route; + } + + /** + * Function to validate a domain, though this is not quite what + * you expect of a strict internet domain. + * + * domain = sub-domain *("." sub-domain) + * + * @access private + * @param string $domain The string to check. + * @return mixed False on failure, or the validated domain on success. + */ + function _validateDomain($domain) + { + // Note the different use of $subdomains and $sub_domains + $subdomains = explode('.', $domain); + + while (count($subdomains) > 0) { + $sub_domains[] = $this->_splitCheck($subdomains, '.'); + for ($i = 0; $i < $this->index + 1; $i++) + array_shift($subdomains); + } + + foreach ($sub_domains as $sub_domain) { + if (!$this->_validateSubdomain(trim($sub_domain))) + return false; + } + + // Managed to get here, so return input. + return $domain; + } + + /** + * Function to validate a subdomain: + * subdomain = domain-ref / domain-literal + * + * @access private + * @param string $subdomain The string to check. + * @return boolean Success or failure. + */ + function _validateSubdomain($subdomain) + { + if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){ + if (!$this->_validateDliteral($arr[1])) return false; + } else { + if (!$this->_validateAtom($subdomain)) return false; + } + + // Got here, so return successful. + return true; + } + + /** + * Function to validate a domain literal: + * domain-literal = "[" *(dtext / quoted-pair) "]" + * + * @access private + * @param string $dliteral The string to check. + * @return boolean Success or failure. + */ + function _validateDliteral($dliteral) + { + return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\'; + } + + /** + * Function to validate an addr-spec. + * + * addr-spec = local-part "@" domain + * + * @access private + * @param string $addr_spec The string to check. + * @return mixed False on failure, or the validated addr-spec on success. + */ + function _validateAddrSpec($addr_spec) + { + $addr_spec = trim($addr_spec); + + // Split on @ sign if there is one. + if (strpos($addr_spec, '@') !== false) { + $parts = explode('@', $addr_spec); + $local_part = $this->_splitCheck($parts, '@'); + $domain = substr($addr_spec, strlen($local_part . '@')); + + // No @ sign so assume the default domain. + } else { + $local_part = $addr_spec; + $domain = $this->default_domain; + } + + if (($local_part = $this->_validateLocalPart($local_part)) === false) return false; + if (($domain = $this->_validateDomain($domain)) === false) return false; + + // Got here so return successful. + return array('local_part' => $local_part, 'domain' => $domain); + } + + /** + * Function to validate the local part of an address: + * local-part = word *("." word) + * + * @access private + * @param string $local_part + * @return mixed False on failure, or the validated local part on success. + */ + function _validateLocalPart($local_part) + { + $parts = explode('.', $local_part); + $words = array(); + + // Split the local_part into words. + while (count($parts) > 0){ + $words[] = $this->_splitCheck($parts, '.'); + for ($i = 0; $i < $this->index + 1; $i++) { + array_shift($parts); + } + } + + // Validate each word. + foreach ($words as $word) { + // If this word contains an unquoted space, it is invalid. (6.2.4) + if (strpos($word, ' ') && $word[0] !== '"') + { + return false; + } + + if ($this->_validatePhrase(trim($word)) === false) return false; + } + + // Managed to get here, so return the input. + return $local_part; + } + + /** + * Returns an approximate count of how many addresses are in the + * given string. This is APPROXIMATE as it only splits based on a + * comma which has no preceding backslash. Could be useful as + * large amounts of addresses will end up producing *large* + * structures when used with parseAddressList(). + * + * @param string $data Addresses to count + * @return int Approximate count + */ + function approximateCount($data) + { + return count(preg_split('/(?<!\\\\),/', $data)); + } + + /** + * This is a email validating function separate to the rest of the + * class. It simply validates whether an email is of the common + * internet form: <user>@<domain>. This can be sufficient for most + * people. Optional stricter mode can be utilised which restricts + * mailbox characters allowed to alphanumeric, full stop, hyphen + * and underscore. + * + * @param string $data Address to check + * @param boolean $strict Optional stricter mode + * @return mixed False if it fails, an indexed array + * username/domain if it matches + */ + function isValidInetAddress($data, $strict = false) + { + $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; + if (preg_match($regex, trim($data), $matches)) { + return array($matches[1], $matches[2]); + } else { + return false; + } + } + +} diff --git a/vas/rest/class/PEAR/Mail/mail.php b/vas/rest/class/PEAR/Mail/mail.php new file mode 100755 index 0000000000000000000000000000000000000000..b13d695656f5445c348017c7e6f8653e19fd433e --- /dev/null +++ b/vas/rest/class/PEAR/Mail/mail.php @@ -0,0 +1,143 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ +// +// $Id: mail.php,v 1.20 2007/10/06 17:00:00 chagenbu Exp $ + +/** + * internal PHP-mail() implementation of the PEAR Mail:: interface. + * @package Mail + * @version $Revision: 1.20 $ + */ +class Mail_mail extends Mail { + + /** + * Any arguments to pass to the mail() function. + * @var string + */ + var $_params = ''; + + /** + * Constructor. + * + * Instantiates a new Mail_mail:: object based on the parameters + * passed in. + * + * @param array $params Extra arguments for the mail() function. + */ + function Mail_mail($params = null) + { + // The other mail implementations accept parameters as arrays. + // In the interest of being consistent, explode an array into + // a string of parameter arguments. + if (is_array($params)) { + $this->_params = join(' ', $params); + } else { + $this->_params = $params; + } + + /* Because the mail() function may pass headers as command + * line arguments, we can't guarantee the use of the standard + * "\r\n" separator. Instead, we use the system's native line + * separator. */ + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } + } + + /** + * Implements Mail_mail::send() function using php's built-in mail() + * command. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * + * @access public + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // If we're passed an array of recipients, implode it. + if (is_array($recipients)) { + $recipients = implode(', ', $recipients); + } + + // Get the Subject out of the headers array so that we can + // pass it as a seperate argument to mail(). + $subject = ''; + if (isset($headers['Subject'])) { + $subject = $headers['Subject']; + unset($headers['Subject']); + } + + // Also remove the To: header. The mail() function will add its own + // To: header based on the contents of $recipients. + unset($headers['To']); + + // Flatten the headers out. + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list(, $text_headers) = $headerElements; + + // We only use mail()'s optional fifth parameter if the additional + // parameters have been provided and we're not running in safe mode. + if (empty($this->_params) || ini_get('safe_mode')) { + $result = mail($recipients, $subject, $body, $text_headers); + } else { + $result = mail($recipients, $subject, $body, $text_headers, + $this->_params); + } + + // If the mail() function returned failure, we need to create a + // PEAR_Error object and return it instead of the boolean result. + if ($result === false) { + $result = PEAR::raiseError('mail() returned failure'); + } + + return $result; + } + +} diff --git a/vas/rest/class/PEAR/Mail/mime.php b/vas/rest/class/PEAR/Mail/mime.php new file mode 100755 index 0000000000000000000000000000000000000000..30d876f04a55c176375f96a5dd54474aea55a737 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/mime.php @@ -0,0 +1,1495 @@ +<?php +/** + * The Mail_Mime class is used to create MIME E-mail messages + * + * The Mail_Mime class provides an OO interface to create MIME + * enabled email messages. This way you can create emails that + * contain plain-text bodies, HTML bodies, attachments, inline + * images and specific headers. + * + * Compatible with PHP versions 4 and 5 + * + * LICENSE: This LICENSE is in the BSD license style. + * Copyright (c) 2002-2003, Richard Heyes <richard@phpguru.org> + * Copyright (c) 2003-2006, PEAR <pear-group@php.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the authors, nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes <richard@phpguru.org> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Cipriano Groenendal <cipri@php.net> + * @author Sean Coates <sean@php.net> + * @author Aleksander Machniak <alec@php.net> + * @copyright 2003-2006 PEAR <pear-group@php.net> + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id$ + * @link http://pear.php.net/package/Mail_mime + * + * This class is based on HTML Mime Mail class from + * Richard Heyes <richard@phpguru.org> which was based also + * in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> + * and Sascha Schumann <sascha@schumann.cx> + */ + + +/** + * require PEAR + * + * This package depends on PEAR to raise errors. + */ +require_once 'PEAR/PEAR.php'; + +/** + * require Mail_mimePart + * + * Mail_mimePart contains the code required to + * create all the different parts a mail can + * consist of. + */ +require_once 'mimePart.php'; + + +/** + * The Mail_Mime class provides an OO interface to create MIME + * enabled email messages. This way you can create emails that + * contain plain-text bodies, HTML bodies, attachments, inline + * images and specific headers. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes <richard@phpguru.org> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Cipriano Groenendal <cipri@php.net> + * @author Sean Coates <sean@php.net> + * @copyright 2003-2006 PEAR <pear-group@php.net> + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/Mail_mime + */ +class Mail_mime +{ + /** + * Contains the plain text part of the email + * + * @var string + * @access private + */ + var $_txtbody; + + /** + * Contains the html part of the email + * + * @var string + * @access private + */ + var $_htmlbody; + + /** + * list of the attached images + * + * @var array + * @access private + */ + var $_html_images = array(); + + /** + * list of the attachements + * + * @var array + * @access private + */ + var $_parts = array(); + + /** + * Headers for the mail + * + * @var array + * @access private + */ + var $_headers = array(); + + /** + * Build parameters + * + * @var array + * @access private + */ + var $_build_params = array( + // What encoding to use for the headers + // Options: quoted-printable or base64 + 'head_encoding' => 'quoted-printable', + // What encoding to use for plain text + // Options: 7bit, 8bit, base64, or quoted-printable + 'text_encoding' => 'quoted-printable', + // What encoding to use for html + // Options: 7bit, 8bit, base64, or quoted-printable + 'html_encoding' => 'quoted-printable', + // The character set to use for html + 'html_charset' => 'ISO-8859-1', + // The character set to use for text + 'text_charset' => 'ISO-8859-1', + // The character set to use for headers + 'head_charset' => 'ISO-8859-1', + // End-of-line sequence + 'eol' => "\r\n", + // Delay attachment files IO until building the message + 'delay_file_io' => false + ); + + /** + * Constructor function + * + * @param mixed $params Build parameters that change the way the email + * is built. Should be an associative array. + * See $_build_params. + * + * @return void + * @access public + */ + function __construct($params = array()) + { + // Backward-compatible EOL setting + if (is_string($params)) { + $this->_build_params['eol'] = $params; + } else if (defined('MAIL_MIME_CRLF') && !isset($params['eol'])) { + $this->_build_params['eol'] = MAIL_MIME_CRLF; + } + + // Update build parameters + if (!empty($params) && is_array($params)) { + while (list($key, $value) = each($params)) { + $this->_build_params[$key] = $value; + } + } + } + + /** + * Set build parameter value + * + * @param string $name Parameter name + * @param string $value Parameter value + * + * @return void + * @access public + * @since 1.6.0 + */ + function setParam($name, $value) + { + $this->_build_params[$name] = $value; + } + + /** + * Get build parameter value + * + * @param string $name Parameter name + * + * @return mixed Parameter value + * @access public + * @since 1.6.0 + */ + function getParam($name) + { + return isset($this->_build_params[$name]) ? $this->_build_params[$name] : null; + } + + /** + * Accessor function to set the body text. Body text is used if + * it's not an html mail being sent or else is used to fill the + * text/plain part that emails clients who don't support + * html should show. + * + * @param string $data Either a string or + * the file name with the contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @param bool $append If true the text or file is appended to + * the existing body, else the old body is + * overwritten + * + * @return mixed True on success or PEAR_Error object + * @access public + */ + function setTXTBody($data, $isfile = false, $append = false) + { + if (!$isfile) { + if (!$append) { + $this->_txtbody = $data; + } else { + $this->_txtbody .= $data; + } + } else { + $cont = $this->_file2str($data); + if ($this->_isError($cont)) { + return $cont; + } + if (!$append) { + $this->_txtbody = $cont; + } else { + $this->_txtbody .= $cont; + } + } + + return true; + } + + /** + * Get message text body + * + * @return string Text body + * @access public + * @since 1.6.0 + */ + function getTXTBody() + { + return $this->_txtbody; + } + + /** + * Adds a html part to the mail. + * + * @param string $data Either a string or the file name with the + * contents + * @param bool $isfile A flag that determines whether $data is a + * filename, or a string(false, default) + * + * @return bool True on success + * @access public + */ + function setHTMLBody($data, $isfile = false) + { + if (!$isfile) { + $this->_htmlbody = $data; + } else { + $cont = $this->_file2str($data); + if ($this->_isError($cont)) { + return $cont; + } + $this->_htmlbody = $cont; + } + + return true; + } + + /** + * Get message HTML body + * + * @return string HTML body + * @access public + * @since 1.6.0 + */ + function getHTMLBody() + { + return $this->_htmlbody; + } + + /** + * Adds an image to the list of embedded images. + * + * @param string $file The image file name OR image data itself + * @param string $c_type The content type + * @param string $name The filename of the image. + * Only used if $file is the image data. + * @param bool $isfile Whether $file is a filename or not. + * Defaults to true + * @param string $content_id Desired Content-ID of MIME part + * Defaults to generated unique ID + * + * @return bool True on success + * @access public + */ + function addHTMLImage($file, + $c_type='application/octet-stream', + $name = '', + $isfile = true, + $content_id = null + ) { + $bodyfile = null; + + if ($isfile) { + // Don't load file into memory + if ($this->_build_params['delay_file_io']) { + $filedata = null; + $bodyfile = $file; + } else { + if ($this->_isError($filedata = $this->_file2str($file))) { + return $filedata; + } + } + $filename = ($name ? $name : $file); + } else { + $filedata = $file; + $filename = $name; + } + + if (!$content_id) { + $content_id = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true)); + } + + $this->_html_images[] = array( + 'body' => $filedata, + 'body_file' => $bodyfile, + 'name' => $filename, + 'c_type' => $c_type, + 'cid' => $content_id + ); + + return true; + } + + /** + * Adds a file to the list of attachments. + * + * @param string $file The file name of the file to attach + * or the file contents itself + * @param string $c_type The content type + * @param string $name The filename of the attachment + * Only use if $file is the contents + * @param bool $isfile Whether $file is a filename or not. Defaults to true + * @param string $encoding The type of encoding to use. Defaults to base64. + * Possible values: 7bit, 8bit, base64 or quoted-printable. + * @param string $disposition The content-disposition of this file + * Defaults to attachment. + * Possible values: attachment, inline. + * @param string $charset The character set of attachment's content. + * @param string $language The language of the attachment + * @param string $location The RFC 2557.4 location of the attachment + * @param string $n_encoding Encoding of the attachment's name in Content-Type + * By default filenames are encoded using RFC2231 method + * Here you can set RFC2047 encoding (quoted-printable + * or base64) instead + * @param string $f_encoding Encoding of the attachment's filename + * in Content-Disposition header. + * @param string $description Content-Description header + * @param string $h_charset The character set of the headers e.g. filename + * If not specified, $charset will be used + * @param array $add_headers Additional part headers. Array keys can be in form + * of <header_name>:<parameter_name> + * + * @return mixed True on success or PEAR_Error object + * @access public + */ + function addAttachment($file, + $c_type = 'application/octet-stream', + $name = '', + $isfile = true, + $encoding = 'base64', + $disposition = 'attachment', + $charset = '', + $language = '', + $location = '', + $n_encoding = null, + $f_encoding = null, + $description = '', + $h_charset = null, + $add_headers = array() + ) { + $bodyfile = null; + + if ($isfile) { + // Don't load file into memory + if ($this->_build_params['delay_file_io']) { + $filedata = null; + $bodyfile = $file; + } else { + if ($this->_isError($filedata = $this->_file2str($file))) { + return $filedata; + } + } + // Force the name the user supplied, otherwise use $file + $filename = ($name ? $name : $this->_basename($file)); + } else { + $filedata = $file; + $filename = $name; + } + + if (!strlen($filename)) { + $msg = "The supplied filename for the attachment can't be empty"; + return $this->_raiseError($msg); + } + + $this->_parts[] = array( + 'body' => $filedata, + 'body_file' => $bodyfile, + 'name' => $filename, + 'c_type' => $c_type, + 'charset' => $charset, + 'encoding' => $encoding, + 'language' => $language, + 'location' => $location, + 'disposition' => $disposition, + 'description' => $description, + 'add_headers' => $add_headers, + 'name_encoding' => $n_encoding, + 'filename_encoding' => $f_encoding, + 'headers_charset' => $h_charset, + ); + + return true; + } + + /** + * Get the contents of the given file name as string + * + * @param string $file_name Path of file to process + * + * @return string Contents of $file_name + * @access private + */ + function _file2str($file_name) + { + // Check state of file and raise an error properly + if (!file_exists($file_name)) { + return $this->_raiseError('File not found: ' . $file_name); + } + if (!is_file($file_name)) { + return $this->_raiseError('Not a regular file: ' . $file_name); + } + if (!is_readable($file_name)) { + return $this->_raiseError('File is not readable: ' . $file_name); + } + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + $cont = file_get_contents($file_name); + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + return $cont; + } + + /** + * Adds a text subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed &$obj The object to add the part to, or + * null if a new object is to be created. + * @param string $text The text to add. + * + * @return object The text mimePart object + * @access private + */ + function &_addTextPart(&$obj = null, $text = '') + { + $params['content_type'] = 'text/plain'; + $params['encoding'] = $this->_build_params['text_encoding']; + $params['charset'] = $this->_build_params['text_charset']; + $params['eol'] = $this->_build_params['eol']; + + if (is_object($obj)) { + $ret = $obj->addSubpart($text, $params); + } else { + $ret = new Mail_mimePart($text, $params); + } + + return $ret; + } + + /** + * Adds a html subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed &$obj The object to add the part to, or + * null if a new object is to be created. + * + * @return object The html mimePart object + * @access private + */ + function &_addHtmlPart(&$obj = null) + { + $params['content_type'] = 'text/html'; + $params['encoding'] = $this->_build_params['html_encoding']; + $params['charset'] = $this->_build_params['html_charset']; + $params['eol'] = $this->_build_params['eol']; + + if (is_object($obj)) { + $ret = $obj->addSubpart($this->_htmlbody, $params); + } else { + $ret = new Mail_mimePart($this->_htmlbody, $params); + } + + return $ret; + } + + /** + * Creates a new mimePart object, using multipart/mixed as + * the initial content-type and returns it during the + * build process. + * + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addMixedPart() + { + $params['content_type'] = 'multipart/mixed'; + $params['eol'] = $this->_build_params['eol']; + + // Create empty multipart/mixed Mail_mimePart object to return + $ret = new Mail_mimePart('', $params); + return $ret; + } + + /** + * Adds a multipart/alternative part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed &$obj The object to add the part to, or + * null if a new object is to be created. + * + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addAlternativePart(&$obj = null) + { + $params['content_type'] = 'multipart/alternative'; + $params['eol'] = $this->_build_params['eol']; + + if (is_object($obj)) { + $ret = $obj->addSubpart('', $params); + } else { + $ret = new Mail_mimePart('', $params); + } + + return $ret; + } + + /** + * Adds a multipart/related part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed &$obj The object to add the part to, or + * null if a new object is to be created + * + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addRelatedPart(&$obj = null) + { + $params['content_type'] = 'multipart/related'; + $params['eol'] = $this->_build_params['eol']; + + if (is_object($obj)) { + $ret = $obj->addSubpart('', $params); + } else { + $ret = new Mail_mimePart('', $params); + } + + return $ret; + } + + /** + * Adds an html image subpart to a mimePart object + * and returns it during the build process. + * + * @param object &$obj The mimePart to add the image to + * @param array $value The image information + * + * @return object The image mimePart object + * @access private + */ + function &_addHtmlImagePart(&$obj, $value) + { + $params['content_type'] = $value['c_type']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'inline'; + $params['filename'] = $value['name']; + $params['cid'] = $value['cid']; + $params['body_file'] = $value['body_file']; + $params['eol'] = $this->_build_params['eol']; + + if (!empty($value['name_encoding'])) { + $params['name_encoding'] = $value['name_encoding']; + } + if (!empty($value['filename_encoding'])) { + $params['filename_encoding'] = $value['filename_encoding']; + } + + $ret = $obj->addSubpart($value['body'], $params); + return $ret; + } + + /** + * Adds an attachment subpart to a mimePart object + * and returns it during the build process. + * + * @param object &$obj The mimePart to add the image to + * @param array $value The attachment information + * + * @return object The image mimePart object + * @access private + */ + function &_addAttachmentPart(&$obj, $value) + { + $params['eol'] = $this->_build_params['eol']; + $params['filename'] = $value['name']; + $params['encoding'] = $value['encoding']; + $params['content_type'] = $value['c_type']; + $params['body_file'] = $value['body_file']; + $params['disposition'] = isset($value['disposition']) ? + $value['disposition'] : 'attachment'; + + // content charset + if (!empty($value['charset'])) { + $params['charset'] = $value['charset']; + } + // headers charset (filename, description) + if (!empty($value['headers_charset'])) { + $params['headers_charset'] = $value['headers_charset']; + } + if (!empty($value['language'])) { + $params['language'] = $value['language']; + } + if (!empty($value['location'])) { + $params['location'] = $value['location']; + } + if (!empty($value['name_encoding'])) { + $params['name_encoding'] = $value['name_encoding']; + } + if (!empty($value['filename_encoding'])) { + $params['filename_encoding'] = $value['filename_encoding']; + } + if (!empty($value['description'])) { + $params['description'] = $value['description']; + } + if (is_array($value['add_headers'])) { + $params['headers'] = $value['add_headers']; + } + + $ret = $obj->addSubpart($value['body'], $params); + return $ret; + } + + /** + * Returns the complete e-mail, ready to send using an alternative + * mail delivery method. Note that only the mailpart that is made + * with Mail_Mime is created. This means that, + * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF + * using the $headers parameter! + * + * @param string $separation The separation between these two parts. + * @param array $params The Build parameters passed to the + * get() function. See get() for more info. + * @param array $headers The extra headers that should be passed + * to the headers() method. + * See that function for more info. + * @param bool $overwrite Overwrite the existing headers with new. + * + * @return mixed The complete e-mail or PEAR error object + * @access public + */ + function getMessage($separation = null, $params = null, $headers = null, + $overwrite = false + ) { + if ($separation === null) { + $separation = $this->_build_params['eol']; + } + + $body = $this->get($params); + + if ($this->_isError($body)) { + return $body; + } + + return $this->txtHeaders($headers, $overwrite) . $separation . $body; + } + + /** + * Returns the complete e-mail body, ready to send using an alternative + * mail delivery method. + * + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * + * @return mixed The e-mail body or PEAR error object + * @access public + * @since 1.6.0 + */ + function getMessageBody($params = null) + { + return $this->get($params, null, true); + } + + /** + * Writes (appends) the complete e-mail into file. + * + * @param string $filename Output file location + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * @param array $headers The extra headers that should be passed + * to the headers() function. + * See that function for more info. + * @param bool $overwrite Overwrite the existing headers with new. + * + * @return mixed True or PEAR error object + * @access public + * @since 1.6.0 + */ + function saveMessage($filename, $params = null, $headers = null, $overwrite = false) + { + // Check state of file and raise an error properly + if (file_exists($filename) && !is_writable($filename)) { + return $this->_raiseError('File is not writable: ' . $filename); + } + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + if (!($fh = fopen($filename, 'ab'))) { + return $this->_raiseError('Unable to open file: ' . $filename); + } + + // Write message headers into file (skipping Content-* headers) + $head = $this->txtHeaders($headers, $overwrite, true); + if (fwrite($fh, $head) === false) { + return $this->_raiseError('Error writing to file: ' . $filename); + } + + fclose($fh); + + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + // Write the rest of the message into file + $res = $this->get($params, $filename); + + return $res ? $res : true; + } + + /** + * Writes (appends) the complete e-mail body into file. + * + * @param string $filename Output file location + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * + * @return mixed True or PEAR error object + * @access public + * @since 1.6.0 + */ + function saveMessageBody($filename, $params = null) + { + // Check state of file and raise an error properly + if (file_exists($filename) && !is_writable($filename)) { + return $this->_raiseError('File is not writable: ' . $filename); + } + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + if (!($fh = fopen($filename, 'ab'))) { + return $this->_raiseError('Unable to open file: ' . $filename); + } + + // Write the rest of the message into file + $res = $this->get($params, $filename, true); + + return $res ? $res : true; + } + + /** + * Builds the multipart message from the list ($this->_parts) and + * returns the mime content. + * + * @param array $params Build parameters that change the way the email + * is built. Should be associative. See $_build_params. + * @param resource $filename Output file where to save the message instead of + * returning it + * @param boolean $skip_head True if you want to return/save only the message + * without headers + * + * @return mixed The MIME message content string, null or PEAR error object + * @access public + */ + function get($params = null, $filename = null, $skip_head = false) + { + if (isset($params)) { + while (list($key, $value) = each($params)) { + $this->_build_params[$key] = $value; + } + } + + if (isset($this->_headers['From'])) { + // Bug #11381: Illegal characters in domain ID + if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->_headers['From'], $matches)) { + $domainID = $matches[1]; + } else { + $domainID = '@localhost'; + } + foreach ($this->_html_images as $i => $img) { + $cid = $this->_html_images[$i]['cid']; + if (!preg_match('#'.preg_quote($domainID).'$#', $cid)) { + $this->_html_images[$i]['cid'] = $cid . $domainID; + } + } + } + + if (count($this->_html_images) && isset($this->_htmlbody)) { + foreach ($this->_html_images as $key => $value) { + $regex = array(); + $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . + preg_quote($value['name'], '#') . '\3#'; + $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' . + preg_quote($value['name'], '#') . '\1\s*\)#'; + + $rep = array(); + $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3'; + $rep[] = 'url(\1cid:' . $value['cid'] . '\1)'; + + $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody); + $this->_html_images[$key]['name'] + = $this->_basename($this->_html_images[$key]['name']); + } + } + + $this->_checkParams(); + + $null = null; + $attachments = count($this->_parts) ? true : false; + $html_images = count($this->_html_images) ? true : false; + $html = strlen($this->_htmlbody) ? true : false; + $text = (!$html && strlen($this->_txtbody)) ? true : false; + + switch (true) { + case $text && !$attachments: + $message =& $this->_addTextPart($null, $this->_txtbody); + break; + + case !$text && !$html && $attachments: + $message =& $this->_addMixedPart(); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $text && $attachments: + $message =& $this->_addMixedPart(); + $this->_addTextPart($message, $this->_txtbody); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html && !$attachments && !$html_images: + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + $this->_addHtmlPart($message); + } else { + $message =& $this->_addHtmlPart($null); + } + break; + + case $html && !$attachments && $html_images: + // * Content-Type: multipart/alternative; + // * text + // * Content-Type: multipart/related; + // * html + // * image... + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + + $ht =& $this->_addRelatedPart($message); + $this->_addHtmlPart($ht); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($ht, $this->_html_images[$i]); + } + } else { + // * Content-Type: multipart/related; + // * html + // * image... + $message =& $this->_addRelatedPart($null); + $this->_addHtmlPart($message); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($message, $this->_html_images[$i]); + } + } + /* + // #13444, #9725: the code below was a non-RFC compliant hack + // * Content-Type: multipart/related; + // * Content-Type: multipart/alternative; + // * text + // * html + // * image... + $message =& $this->_addRelatedPart($null); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $this->_addHtmlPart($alt); + } else { + $this->_addHtmlPart($message); + } + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($message, $this->_html_images[$i]); + } + */ + break; + + case $html && $attachments && !$html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $this->_addHtmlPart($alt); + } else { + $this->_addHtmlPart($message); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html && $attachments && $html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $rel =& $this->_addRelatedPart($alt); + } else { + $rel =& $this->_addRelatedPart($message); + } + $this->_addHtmlPart($rel); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($rel, $this->_html_images[$i]); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + } + + if (!isset($message)) { + return null; + } + + // Use saved boundary + if (!empty($this->_build_params['boundary'])) { + $boundary = $this->_build_params['boundary']; + } else { + $boundary = null; + } + + // Write output to file + if ($filename) { + // Append mimePart message headers and body into file + $headers = $message->encodeToFile($filename, $boundary, $skip_head); + if ($this->_isError($headers)) { + return $headers; + } + $this->_headers = array_merge($this->_headers, $headers); + return null; + } else { + $output = $message->encode($boundary, $skip_head); + if ($this->_isError($output)) { + return $output; + } + $this->_headers = array_merge($this->_headers, $output['headers']); + return $output['body']; + } + } + + /** + * Returns an array with the headers needed to prepend to the email + * (MIME-Version and Content-Type). Format of argument is: + * $array['header-name'] = 'header-value'; + * + * @param array $xtra_headers Assoc array with any extra headers (optional) + * (Don't set Content-Type for multipart messages here!) + * @param bool $overwrite Overwrite already existing headers. + * @param bool $skip_content Don't return content headers: Content-Type, + * Content-Disposition and Content-Transfer-Encoding + * + * @return array Assoc array with the mime headers + * @access public + */ + function headers($xtra_headers = null, $overwrite = false, $skip_content = false) + { + // Add mime version header + $headers['MIME-Version'] = '1.0'; + + // Content-Type and Content-Transfer-Encoding headers should already + // be present if get() was called, but we'll re-set them to make sure + // we got them when called before get() or something in the message + // has been changed after get() [#14780] + if (!$skip_content) { + $headers += $this->_contentHeaders(); + } + + if (!empty($xtra_headers)) { + $headers = array_merge($headers, $xtra_headers); + } + + if ($overwrite) { + $this->_headers = array_merge($this->_headers, $headers); + } else { + $this->_headers = array_merge($headers, $this->_headers); + } + + $headers = $this->_headers; + + if ($skip_content) { + unset($headers['Content-Type']); + unset($headers['Content-Transfer-Encoding']); + unset($headers['Content-Disposition']); + } else if (!empty($this->_build_params['ctype'])) { + $headers['Content-Type'] = $this->_build_params['ctype']; + } + + $encodedHeaders = $this->_encodeHeaders($headers); + return $encodedHeaders; + } + + /** + * Get the text version of the headers + * (usefull if you want to use the PHP mail() function) + * + * @param array $xtra_headers Assoc array with any extra headers (optional) + * (Don't set Content-Type for multipart messages here!) + * @param bool $overwrite Overwrite the existing headers with new. + * @param bool $skip_content Don't return content headers: Content-Type, + * Content-Disposition and Content-Transfer-Encoding + * + * @return string Plain text headers + * @access public + */ + function txtHeaders($xtra_headers = null, $overwrite = false, $skip_content = false) + { + $headers = $this->headers($xtra_headers, $overwrite, $skip_content); + + // Place Received: headers at the beginning of the message + // Spam detectors often flag messages with it after the Subject: as spam + if (isset($headers['Received'])) { + $received = $headers['Received']; + unset($headers['Received']); + $headers = array('Received' => $received) + $headers; + } + + $ret = ''; + $eol = $this->_build_params['eol']; + + foreach ($headers as $key => $val) { + if (is_array($val)) { + foreach ($val as $value) { + $ret .= "$key: $value" . $eol; + } + } else { + $ret .= "$key: $val" . $eol; + } + } + + return $ret; + } + + /** + * Sets message Content-Type header. + * Use it to build messages with various content-types e.g. miltipart/raport + * not supported by _contentHeaders() function. + * + * @param string $type Type name + * @param array $params Hash array of header parameters + * + * @return void + * @access public + * @since 1.7.0 + */ + function setContentType($type, $params = array()) + { + $header = $type; + + $eol = !empty($this->_build_params['eol']) + ? $this->_build_params['eol'] : "\r\n"; + + // add parameters + $token_regexp = '#([^\x21\x23-\x27\x2A\x2B\x2D' + . '\x2E\x30-\x39\x41-\x5A\x5E-\x7E])#'; + if (is_array($params)) { + foreach ($params as $name => $value) { + if ($name == 'boundary') { + $this->_build_params['boundary'] = $value; + } + if (!preg_match($token_regexp, $value)) { + $header .= ";$eol $name=$value"; + } else { + $value = addcslashes($value, '\\"'); + $header .= ";$eol $name=\"$value\""; + } + } + } + + // add required boundary parameter if not defined + if (preg_match('/^multipart\//i', $type)) { + if (empty($this->_build_params['boundary'])) { + $this->_build_params['boundary'] = '=_' . md5(rand() . microtime()); + } + + $header .= ";$eol boundary=\"".$this->_build_params['boundary']."\""; + } + + $this->_build_params['ctype'] = $header; + } + + /** + * Sets the Subject header + * + * @param string $subject String to set the subject to. + * + * @return void + * @access public + */ + function setSubject($subject) + { + $this->_headers['Subject'] = $subject; + } + + /** + * Set an email to the From (the sender) header + * + * @param string $email The email address to use + * + * @return void + * @access public + */ + function setFrom($email) + { + $this->_headers['From'] = $email; + } + + /** + * Add an email to the To header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * + * @return void + * @access public + */ + function addTo($email) + { + if (isset($this->_headers['To'])) { + $this->_headers['To'] .= ", $email"; + } else { + $this->_headers['To'] = $email; + } + } + + /** + * Add an email to the Cc (carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * + * @return void + * @access public + */ + function addCc($email) + { + if (isset($this->_headers['Cc'])) { + $this->_headers['Cc'] .= ", $email"; + } else { + $this->_headers['Cc'] = $email; + } + } + + /** + * Add an email to the Bcc (blank carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * + * @return void + * @access public + */ + function addBcc($email) + { + if (isset($this->_headers['Bcc'])) { + $this->_headers['Bcc'] .= ", $email"; + } else { + $this->_headers['Bcc'] = $email; + } + } + + /** + * Since the PHP send function requires you to specify + * recipients (To: header) separately from the other + * headers, the To: header is not properly encoded. + * To fix this, you can use this public method to + * encode your recipients before sending to the send + * function + * + * @param string $recipients A comma-delimited list of recipients + * + * @return string Encoded data + * @access public + */ + function encodeRecipients($recipients) + { + $input = array("To" => $recipients); + $retval = $this->_encodeHeaders($input); + return $retval["To"] ; + } + + /** + * Encodes headers as per RFC2047 + * + * @param array $input The header data to encode + * @param array $params Extra build parameters + * + * @return array Encoded data + * @access private + */ + function _encodeHeaders($input, $params = array()) + { + $build_params = $this->_build_params; + while (list($key, $value) = each($params)) { + $build_params[$key] = $value; + } + + foreach ($input as $hdr_name => $hdr_value) { + if (is_array($hdr_value)) { + foreach ($hdr_value as $idx => $value) { + $input[$hdr_name][$idx] = $this->encodeHeader( + $hdr_name, $value, + $build_params['head_charset'], $build_params['head_encoding'] + ); + } + } else { + $input[$hdr_name] = $this->encodeHeader( + $hdr_name, $hdr_value, + $build_params['head_charset'], $build_params['head_encoding'] + ); + } + } + + return $input; + } + + /** + * Encodes a header as per RFC2047 + * + * @param string $name The header name + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * + * @return string Encoded header data (without a name) + * @access public + * @since 1.5.3 + */ + function encodeHeader($name, $value, $charset, $encoding) + { + $mime_part = new Mail_mimePart; + return $mime_part->encodeHeader( + $name, $value, $charset, $encoding, $this->_build_params['eol'] + ); + } + + /** + * Get file's basename (locale independent) + * + * @param string $filename Filename + * + * @return string Basename + * @access private + */ + function _basename($filename) + { + // basename() is not unicode safe and locale dependent + if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) { + return preg_replace('/^.*[\\\\\\/]/', '', $filename); + } else { + return preg_replace('/^.*[\/]/', '', $filename); + } + } + + /** + * Get Content-Type and Content-Transfer-Encoding headers of the message + * + * @return array Headers array + * @access private + */ + function _contentHeaders() + { + $attachments = count($this->_parts) ? true : false; + $html_images = count($this->_html_images) ? true : false; + $html = strlen($this->_htmlbody) ? true : false; + $text = (!$html && strlen($this->_txtbody)) ? true : false; + $headers = array(); + + // See get() + switch (true) { + case $text && !$attachments: + $headers['Content-Type'] = 'text/plain'; + break; + + case !$text && !$html && $attachments: + case $text && $attachments: + case $html && $attachments && !$html_images: + case $html && $attachments && $html_images: + $headers['Content-Type'] = 'multipart/mixed'; + break; + + case $html && !$attachments && !$html_images && isset($this->_txtbody): + case $html && !$attachments && $html_images && isset($this->_txtbody): + $headers['Content-Type'] = 'multipart/alternative'; + break; + + case $html && !$attachments && !$html_images && !isset($this->_txtbody): + $headers['Content-Type'] = 'text/html'; + break; + + case $html && !$attachments && $html_images && !isset($this->_txtbody): + $headers['Content-Type'] = 'multipart/related'; + break; + + default: + return $headers; + } + + $this->_checkParams(); + + $eol = !empty($this->_build_params['eol']) + ? $this->_build_params['eol'] : "\r\n"; + + if ($headers['Content-Type'] == 'text/plain') { + // single-part message: add charset and encoding + $charset = 'charset=' . $this->_build_params['text_charset']; + // place charset parameter in the same line, if possible + // 26 = strlen("Content-Type: text/plain; ") + $headers['Content-Type'] + .= (strlen($charset) + 26 <= 76) ? "; $charset" : ";$eol $charset"; + $headers['Content-Transfer-Encoding'] + = $this->_build_params['text_encoding']; + } else if ($headers['Content-Type'] == 'text/html') { + // single-part message: add charset and encoding + $charset = 'charset=' . $this->_build_params['html_charset']; + // place charset parameter in the same line, if possible + $headers['Content-Type'] + .= (strlen($charset) + 25 <= 76) ? "; $charset" : ";$eol $charset"; + $headers['Content-Transfer-Encoding'] + = $this->_build_params['html_encoding']; + } else { + // multipart message: and boundary + if (!empty($this->_build_params['boundary'])) { + $boundary = $this->_build_params['boundary']; + } else if (!empty($this->_headers['Content-Type']) + && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m) + ) { + $boundary = $m[1]; + } else { + $boundary = '=_' . md5(rand() . microtime()); + } + + $this->_build_params['boundary'] = $boundary; + $headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + } + + return $headers; + } + + /** + * Validate and set build parameters + * + * @return void + * @access private + */ + function _checkParams() + { + $encodings = array('7bit', '8bit', 'base64', 'quoted-printable'); + + $this->_build_params['text_encoding'] + = strtolower($this->_build_params['text_encoding']); + $this->_build_params['html_encoding'] + = strtolower($this->_build_params['html_encoding']); + + if (!in_array($this->_build_params['text_encoding'], $encodings)) { + $this->_build_params['text_encoding'] = '7bit'; + } + if (!in_array($this->_build_params['html_encoding'], $encodings)) { + $this->_build_params['html_encoding'] = '7bit'; + } + + // text body + if ($this->_build_params['text_encoding'] == '7bit' + && !preg_match('/ascii/i', $this->_build_params['text_charset']) + && preg_match('/[^\x00-\x7F]/', $this->_txtbody) + ) { + $this->_build_params['text_encoding'] = 'quoted-printable'; + } + // html body + if ($this->_build_params['html_encoding'] == '7bit' + && !preg_match('/ascii/i', $this->_build_params['html_charset']) + && preg_match('/[^\x00-\x7F]/', $this->_htmlbody) + ) { + $this->_build_params['html_encoding'] = 'quoted-printable'; + } + } + + /** + * PEAR::isError implementation + * + * @param mixed $data Object + * + * @return bool True if object is an instance of PEAR_Error + * @access private + */ + function _isError($data) + { + // PEAR::isError() is not PHP 5.4 compatible (see Bug #19473) + if (is_object($data) && is_a($data, 'PEAR_Error')) { + return true; + } + + return false; + } + + /** + * PEAR::raiseError implementation + * + * @param $message A text error message + * + * @return PEAR_Error Instance of PEAR_Error + * @access private + */ + function _raiseError($message) + { + // PEAR::raiseError() is not PHP 5.4 compatible + return new PEAR_Error($message); + } + +} // End of class diff --git a/vas/rest/class/PEAR/Mail/mimePart.php b/vas/rest/class/PEAR/Mail/mimePart.php new file mode 100755 index 0000000000000000000000000000000000000000..0cbc18adbfb64499d4b3280ed5e33cb18215dc27 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/mimePart.php @@ -0,0 +1,1261 @@ +<?php +/** + * The Mail_mimePart class is used to create MIME E-mail messages + * + * This class enables you to manipulate and build a mime email + * from the ground up. The Mail_Mime class is a userfriendly api + * to this class for people who aren't interested in the internals + * of mime mail. + * This class however allows full control over the email. + * + * Compatible with PHP versions 4 and 5 + * + * LICENSE: This LICENSE is in the BSD license style. + * Copyright (c) 2002-2003, Richard Heyes <richard@phpguru.org> + * Copyright (c) 2003-2006, PEAR <pear-group@php.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the authors, nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes <richard@phpguru.org> + * @author Cipriano Groenendal <cipri@php.net> + * @author Sean Coates <sean@php.net> + * @author Aleksander Machniak <alec@php.net> + * @copyright 2003-2006 PEAR <pear-group@php.net> + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id$ + * @link http://pear.php.net/package/Mail_mime + */ + + +/** + * The Mail_mimePart class is used to create MIME E-mail messages + * + * This class enables you to manipulate and build a mime email + * from the ground up. The Mail_Mime class is a userfriendly api + * to this class for people who aren't interested in the internals + * of mime mail. + * This class however allows full control over the email. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes <richard@phpguru.org> + * @author Cipriano Groenendal <cipri@php.net> + * @author Sean Coates <sean@php.net> + * @author Aleksander Machniak <alec@php.net> + * @copyright 2003-2006 PEAR <pear-group@php.net> + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/Mail_mime + */ +class Mail_mimePart +{ + /** + * The encoding type of this part + * + * @var string + * @access private + */ + var $_encoding; + + /** + * An array of subparts + * + * @var array + * @access private + */ + var $_subparts; + + /** + * The output of this part after being built + * + * @var string + * @access private + */ + var $_encoded; + + /** + * Headers for this part + * + * @var array + * @access private + */ + var $_headers; + + /** + * The body of this part (not encoded) + * + * @var string + * @access private + */ + var $_body; + + /** + * The location of file with body of this part (not encoded) + * + * @var string + * @access private + */ + var $_body_file; + + /** + * The end-of-line sequence + * + * @var string + * @access private + */ + var $_eol = "\r\n"; + + + /** + * Constructor. + * + * Sets up the object. + * + * @param string $body The body of the mime part if any. + * @param array $params An associative array of optional parameters: + * content_type - The content type for this part eg multipart/mixed + * encoding - The encoding to use, 7bit, 8bit, + * base64, or quoted-printable + * charset - Content character set + * cid - Content ID to apply + * disposition - Content disposition, inline or attachment + * filename - Filename parameter for content disposition + * description - Content description + * name_encoding - Encoding of the attachment name (Content-Type) + * By default filenames are encoded using RFC2231 + * Here you can set RFC2047 encoding (quoted-printable + * or base64) instead + * filename_encoding - Encoding of the attachment filename (Content-Disposition) + * See 'name_encoding' + * headers_charset - Charset of the headers e.g. filename, description. + * If not set, 'charset' will be used + * eol - End of line sequence. Default: "\r\n" + * headers - Hash array with additional part headers. Array keys can be + * in form of <header_name>:<parameter_name> + * body_file - Location of file with part's body (instead of $body) + * + * @access public + */ + function __construct($body = '', $params = array()) + { + if (!empty($params['eol'])) { + $this->_eol = $params['eol']; + } else if (defined('MAIL_MIMEPART_CRLF')) { // backward-copat. + $this->_eol = MAIL_MIMEPART_CRLF; + } + + // Additional part headers + if (!empty($params['headers']) && is_array($params['headers'])) { + $headers = $params['headers']; + } + + foreach ($params as $key => $value) { + switch ($key) { + case 'encoding': + $this->_encoding = $value; + $headers['Content-Transfer-Encoding'] = $value; + break; + + case 'cid': + $headers['Content-ID'] = '<' . $value . '>'; + break; + + case 'location': + $headers['Content-Location'] = $value; + break; + + case 'body_file': + $this->_body_file = $value; + break; + + // for backward compatibility + case 'dfilename': + $params['filename'] = $value; + break; + } + } + + // Default content-type + if (empty($params['content_type'])) { + $params['content_type'] = 'text/plain'; + } + + // Content-Type + $headers['Content-Type'] = $params['content_type']; + if (!empty($params['charset'])) { + $charset = "charset={$params['charset']}"; + // place charset parameter in the same line, if possible + if ((strlen($headers['Content-Type']) + strlen($charset) + 16) <= 76) { + $headers['Content-Type'] .= '; '; + } else { + $headers['Content-Type'] .= ';' . $this->_eol . ' '; + } + $headers['Content-Type'] .= $charset; + + // Default headers charset + if (!isset($params['headers_charset'])) { + $params['headers_charset'] = $params['charset']; + } + } + + // header values encoding parameters + $h_charset = !empty($params['headers_charset']) ? $params['headers_charset'] : 'US-ASCII'; + $h_language = !empty($params['language']) ? $params['language'] : null; + $h_encoding = !empty($params['name_encoding']) ? $params['name_encoding'] : null; + + + if (!empty($params['filename'])) { + $headers['Content-Type'] .= ';' . $this->_eol; + $headers['Content-Type'] .= $this->_buildHeaderParam( + 'name', $params['filename'], $h_charset, $h_language, $h_encoding + ); + } + + // Content-Disposition + if (!empty($params['disposition'])) { + $headers['Content-Disposition'] = $params['disposition']; + if (!empty($params['filename'])) { + $headers['Content-Disposition'] .= ';' . $this->_eol; + $headers['Content-Disposition'] .= $this->_buildHeaderParam( + 'filename', $params['filename'], $h_charset, $h_language, + !empty($params['filename_encoding']) ? $params['filename_encoding'] : null + ); + } + + // add attachment size + $size = $this->_body_file ? filesize($this->_body_file) : strlen($body); + if ($size) { + $headers['Content-Disposition'] .= ';' . $this->_eol . ' size=' . $size; + } + } + + if (!empty($params['description'])) { + $headers['Content-Description'] = $this->encodeHeader( + 'Content-Description', $params['description'], $h_charset, $h_encoding, + $this->_eol + ); + } + + // Search and add existing headers' parameters + foreach ($headers as $key => $value) { + $items = explode(':', $key); + if (count($items) == 2) { + $header = $items[0]; + $param = $items[1]; + if (isset($headers[$header])) { + $headers[$header] .= ';' . $this->_eol; + } + $headers[$header] .= $this->_buildHeaderParam( + $param, $value, $h_charset, $h_language, $h_encoding + ); + unset($headers[$key]); + } + } + + // Default encoding + if (!isset($this->_encoding)) { + $this->_encoding = '7bit'; + } + + // Assign stuff to member variables + $this->_encoded = array(); + $this->_headers = $headers; + $this->_body = $body; + } + + /** + * Encodes and returns the email. Also stores + * it in the encoded member variable + * + * @param string $boundary Pre-defined boundary string + * + * @return An associative array containing two elements, + * body and headers. The headers element is itself + * an indexed array. On error returns PEAR error object. + * @access public + */ + function encode($boundary=null) + { + $encoded =& $this->_encoded; + + if (count($this->_subparts)) { + $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); + $eol = $this->_eol; + + $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + + $encoded['body'] = ''; + + for ($i = 0; $i < count($this->_subparts); $i++) { + $encoded['body'] .= '--' . $boundary . $eol; + $tmp = $this->_subparts[$i]->encode(); + if ($this->_isError($tmp)) { + return $tmp; + } + foreach ($tmp['headers'] as $key => $value) { + $encoded['body'] .= $key . ': ' . $value . $eol; + } + $encoded['body'] .= $eol . $tmp['body'] . $eol; + } + + $encoded['body'] .= '--' . $boundary . '--' . $eol; + + } else if ($this->_body) { + $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding); + } else if ($this->_body_file) { + // Temporarily reset magic_quotes_runtime for file reads and writes + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + $body = $this->_getEncodedDataFromFile($this->_body_file, $this->_encoding); + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + if ($this->_isError($body)) { + return $body; + } + $encoded['body'] = $body; + } else { + $encoded['body'] = ''; + } + + // Add headers to $encoded + $encoded['headers'] =& $this->_headers; + + return $encoded; + } + + /** + * Encodes and saves the email into file. File must exist. + * Data will be appended to the file. + * + * @param string $filename Output file location + * @param string $boundary Pre-defined boundary string + * @param boolean $skip_head True if you don't want to save headers + * + * @return array An associative array containing message headers + * or PEAR error object + * @access public + * @since 1.6.0 + */ + function encodeToFile($filename, $boundary=null, $skip_head=false) + { + if (file_exists($filename) && !is_writable($filename)) { + $err = $this->_raiseError('File is not writeable: ' . $filename); + return $err; + } + + if (!($fh = fopen($filename, 'ab'))) { + $err = $this->_raiseError('Unable to open file: ' . $filename); + return $err; + } + + // Temporarily reset magic_quotes_runtime for file reads and writes + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + $res = $this->_encodePartToFile($fh, $boundary, $skip_head); + + fclose($fh); + + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + return $this->_isError($res) ? $res : $this->_headers; + } + + /** + * Encodes given email part into file + * + * @param string $fh Output file handle + * @param string $boundary Pre-defined boundary string + * @param boolean $skip_head True if you don't want to save headers + * + * @return array True on sucess or PEAR error object + * @access private + */ + function _encodePartToFile($fh, $boundary=null, $skip_head=false) + { + $eol = $this->_eol; + + if (count($this->_subparts)) { + $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); + $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + } + + if (!$skip_head) { + foreach ($this->_headers as $key => $value) { + fwrite($fh, $key . ': ' . $value . $eol); + } + $f_eol = $eol; + } else { + $f_eol = ''; + } + + if (count($this->_subparts)) { + for ($i = 0; $i < count($this->_subparts); $i++) { + fwrite($fh, $f_eol . '--' . $boundary . $eol); + $res = $this->_subparts[$i]->_encodePartToFile($fh); + if ($this->_isError($res)) { + return $res; + } + $f_eol = $eol; + } + + fwrite($fh, $eol . '--' . $boundary . '--' . $eol); + + } else if ($this->_body) { + fwrite($fh, $f_eol . $this->_getEncodedData($this->_body, $this->_encoding)); + } else if ($this->_body_file) { + fwrite($fh, $f_eol); + $res = $this->_getEncodedDataFromFile( + $this->_body_file, $this->_encoding, $fh + ); + if ($this->_isError($res)) { + return $res; + } + } + + return true; + } + + /** + * Adds a subpart to current mime part and returns + * a reference to it + * + * @param string $body The body of the subpart, if any. + * @param array $params The parameters for the subpart, same + * as the $params argument for constructor. + * + * @return Mail_mimePart A reference to the part you just added. In PHP4, it is + * crucial if using multipart/* in your subparts that + * you use =& in your script when calling this function, + * otherwise you will not be able to add further subparts. + * @access public + */ + function &addSubpart($body, $params) + { + $this->_subparts[] = $part = new Mail_mimePart($body, $params); + return $part; + } + + /** + * Returns encoded data based upon encoding passed to it + * + * @param string $data The data to encode. + * @param string $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * + * @return string + * @access private + */ + function _getEncodedData($data, $encoding) + { + switch ($encoding) { + case 'quoted-printable': + return $this->_quotedPrintableEncode($data); + break; + + case 'base64': + return rtrim(chunk_split(base64_encode($data), 76, $this->_eol)); + break; + + case '8bit': + case '7bit': + default: + return $data; + } + } + + /** + * Returns encoded data based upon encoding passed to it + * + * @param string $filename Data file location + * @param string $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * @param resource $fh Output file handle. If set, data will be + * stored into it instead of returning it + * + * @return string Encoded data or PEAR error object + * @access private + */ + function _getEncodedDataFromFile($filename, $encoding, $fh=null) + { + if (!is_readable($filename)) { + $err = $this->_raiseError('Unable to read file: ' . $filename); + return $err; + } + + if (!($fd = fopen($filename, 'rb'))) { + $err = $this->_raiseError('Could not open file: ' . $filename); + return $err; + } + + $data = ''; + + switch ($encoding) { + case 'quoted-printable': + while (!feof($fd)) { + $buffer = $this->_quotedPrintableEncode(fgets($fd)); + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + break; + + case 'base64': + while (!feof($fd)) { + // Should read in a multiple of 57 bytes so that + // the output is 76 bytes per line. Don't use big chunks + // because base64 encoding is memory expensive + $buffer = fread($fd, 57 * 9198); // ca. 0.5 MB + $buffer = base64_encode($buffer); + $buffer = chunk_split($buffer, 76, $this->_eol); + if (feof($fd)) { + $buffer = rtrim($buffer); + } + + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + break; + + case '8bit': + case '7bit': + default: + while (!feof($fd)) { + $buffer = fread($fd, 1048576); // 1 MB + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + } + + fclose($fd); + + if (!$fh) { + return $data; + } + } + + /** + * Encodes data to quoted-printable standard. + * + * @param string $input The data to encode + * @param int $line_max Optional max line length. Should + * not be more than 76 chars + * + * @return string Encoded data + * + * @access private + */ + function _quotedPrintableEncode($input , $line_max = 76) + { + $eol = $this->_eol; + /* + // imap_8bit() is extremely fast, but doesn't handle properly some characters + if (function_exists('imap_8bit') && $line_max == 76) { + $input = preg_replace('/\r?\n/', "\r\n", $input); + $input = imap_8bit($input); + if ($eol != "\r\n") { + $input = str_replace("\r\n", $eol, $input); + } + return $input; + } + */ + $lines = preg_split("/\r?\n/", $input); + $escape = '='; + $output = ''; + + while (list($idx, $line) = each($lines)) { + $newline = ''; + $i = 0; + + while (isset($line[$i])) { + $char = $line[$i]; + $dec = ord($char); + $i++; + + if (($dec == 32) && (!isset($line[$i]))) { + // convert space at eol only + $char = '=20'; + } elseif ($dec == 9 && isset($line[$i])) { + ; // Do nothing if a TAB is not on eol + } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) { + $char = $escape . sprintf('%02X', $dec); + } elseif (($dec == 46) && (($newline == '') + || ((strlen($newline) + strlen("=2E")) >= $line_max)) + ) { + // Bug #9722: convert full-stop at bol, + // some Windows servers need this, won't break anything (cipri) + // Bug #11731: full-stop at bol also needs to be encoded + // if this line would push us over the line_max limit. + $char = '=2E'; + } + + // Note, when changing this line, also change the ($dec == 46) + // check line, as it mimics this line due to Bug #11731 + // EOL is not counted + if ((strlen($newline) + strlen($char)) >= $line_max) { + // soft line break; " =\r\n" is okay + $output .= $newline . $escape . $eol; + $newline = ''; + } + $newline .= $char; + } // end of for + $output .= $newline . $eol; + unset($lines[$idx]); + } + // Don't want last crlf + $output = substr($output, 0, -1 * strlen($eol)); + return $output; + } + + /** + * Encodes the parameter of a header. + * + * @param string $name The name of the header-parameter + * @param string $value The value of the paramter + * @param string $charset The characterset of $value + * @param string $language The language used in $value + * @param string $encoding Parameter encoding. If not set, parameter value + * is encoded according to RFC2231 + * @param int $maxLength The maximum length of a line. Defauls to 75 + * + * @return string + * + * @access private + */ + function _buildHeaderParam($name, $value, $charset=null, $language=null, + $encoding=null, $maxLength=75 + ) { + // RFC 2045: + // value needs encoding if contains non-ASCII chars or is longer than 78 chars + if (!preg_match('#[^\x20-\x7E]#', $value)) { + $token_regexp = '#([^\x21\x23-\x27\x2A\x2B\x2D' + . '\x2E\x30-\x39\x41-\x5A\x5E-\x7E])#'; + if (!preg_match($token_regexp, $value)) { + // token + if (strlen($name) + strlen($value) + 3 <= $maxLength) { + return " {$name}={$value}"; + } + } else { + // quoted-string + $quoted = addcslashes($value, '\\"'); + if (strlen($name) + strlen($quoted) + 5 <= $maxLength) { + return " {$name}=\"{$quoted}\""; + } + } + } + + // RFC2047: use quoted-printable/base64 encoding + if ($encoding == 'quoted-printable' || $encoding == 'base64') { + return $this->_buildRFC2047Param($name, $value, $charset, $encoding); + } + + // RFC2231: + $encValue = preg_replace_callback( + '/([^\x21\x23\x24\x26\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E])/', + array($this, '_encodeReplaceCallback'), $value + ); + $value = "$charset'$language'$encValue"; + + $header = " {$name}*={$value}"; + if (strlen($header) <= $maxLength) { + return $header; + } + + $preLength = strlen(" {$name}*0*="); + $maxLength = max(16, $maxLength - $preLength - 3); + $maxLengthReg = "|(.{0,$maxLength}[^\%][^\%])|"; + + $headers = array(); + $headCount = 0; + while ($value) { + $matches = array(); + $found = preg_match($maxLengthReg, $value, $matches); + if ($found) { + $headers[] = " {$name}*{$headCount}*={$matches[0]}"; + $value = substr($value, strlen($matches[0])); + } else { + $headers[] = " {$name}*{$headCount}*={$value}"; + $value = ''; + } + $headCount++; + } + + $headers = implode(';' . $this->_eol, $headers); + return $headers; + } + + /** + * Encodes header parameter as per RFC2047 if needed + * + * @param string $name The parameter name + * @param string $value The parameter value + * @param string $charset The parameter charset + * @param string $encoding Encoding type (quoted-printable or base64) + * @param int $maxLength Encoded parameter max length. Default: 76 + * + * @return string Parameter line + * @access private + */ + function _buildRFC2047Param($name, $value, $charset, + $encoding='quoted-printable', $maxLength=76 + ) { + // WARNING: RFC 2047 says: "An 'encoded-word' MUST NOT be used in + // parameter of a MIME Content-Type or Content-Disposition field", + // but... it's supported by many clients/servers + $quoted = ''; + + if ($encoding == 'base64') { + $value = base64_encode($value); + $prefix = '=?' . $charset . '?B?'; + $suffix = '?='; + + // 2 x SPACE, 2 x '"', '=', ';' + $add_len = strlen($prefix . $suffix) + strlen($name) + 6; + $len = $add_len + strlen($value); + + while ($len > $maxLength) { + // We can cut base64-encoded string every 4 characters + $real_len = floor(($maxLength - $add_len) / 4) * 4; + $_quote = substr($value, 0, $real_len); + $value = substr($value, $real_len); + + $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; + $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' + $len = strlen($value) + $add_len; + } + $quoted .= $prefix . $value . $suffix; + + } else { + // quoted-printable + $value = $this->encodeQP($value); + $prefix = '=?' . $charset . '?Q?'; + $suffix = '?='; + + // 2 x SPACE, 2 x '"', '=', ';' + $add_len = strlen($prefix . $suffix) + strlen($name) + 6; + $len = $add_len + strlen($value); + + while ($len > $maxLength) { + $length = $maxLength - $add_len; + // don't break any encoded letters + if (preg_match("/^(.{0,$length}[^\=][^\=])/", $value, $matches)) { + $_quote = $matches[1]; + } + + $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; + $value = substr($value, strlen($_quote)); + $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' + $len = strlen($value) + $add_len; + } + + $quoted .= $prefix . $value . $suffix; + } + + return " {$name}=\"{$quoted}\""; + } + + /** + * Encodes a header as per RFC2047 + * + * @param string $name The header name + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded header data (without a name) + * @access public + * @since 1.6.1 + */ + function encodeHeader($name, $value, $charset='ISO-8859-1', + $encoding='quoted-printable', $eol="\r\n" + ) { + // Structured headers + $comma_headers = array( + 'from', 'to', 'cc', 'bcc', 'sender', 'reply-to', + 'resent-from', 'resent-to', 'resent-cc', 'resent-bcc', + 'resent-sender', 'resent-reply-to', + 'mail-reply-to', 'mail-followup-to', + 'return-receipt-to', 'disposition-notification-to', + ); + $other_headers = array( + 'references', 'in-reply-to', 'message-id', 'resent-message-id', + ); + + $name = strtolower($name); + + if (in_array($name, $comma_headers)) { + $separator = ','; + } else if (in_array($name, $other_headers)) { + $separator = ' '; + } + + if (!$charset) { + $charset = 'ISO-8859-1'; + } + + // Structured header (make sure addr-spec inside is not encoded) + if (!empty($separator)) { + // Simple e-mail address regexp + $email_regexp = '([^\s<]+|("[^\r\n"]+"))@\S+'; + + $parts = Mail_mimePart::_explodeQuotedString($separator, $value); + $value = ''; + + foreach ($parts as $part) { + $part = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $part); + $part = trim($part); + + if (!$part) { + continue; + } + if ($value) { + $value .= $separator==',' ? $separator.' ' : ' '; + } else { + $value = $name . ': '; + } + + // let's find phrase (name) and/or addr-spec + if (preg_match('/^<' . $email_regexp . '>$/', $part)) { + $value .= $part; + } else if (preg_match('/^' . $email_regexp . '$/', $part)) { + // address without brackets and without name + $value .= $part; + } else if (preg_match('/<*' . $email_regexp . '>*$/', $part, $matches)) { + // address with name (handle name) + $address = $matches[0]; + $word = str_replace($address, '', $part); + $word = trim($word); + // check if phrase requires quoting + if ($word) { + // non-ASCII: require encoding + if (preg_match('#([\x80-\xFF]){1}#', $word)) { + if ($word[0] == '"' && $word[strlen($word)-1] == '"') { + // de-quote quoted-string, encoding changes + // string to atom + $search = array("\\\"", "\\\\"); + $replace = array("\"", "\\"); + $word = str_replace($search, $replace, $word); + $word = substr($word, 1, -1); + } + // find length of last line + if (($pos = strrpos($value, $eol)) !== false) { + $last_len = strlen($value) - $pos; + } else { + $last_len = strlen($value); + } + $word = Mail_mimePart::encodeHeaderValue( + $word, $charset, $encoding, $last_len, $eol + ); + } else if (($word[0] != '"' || $word[strlen($word)-1] != '"') + && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $word) + ) { + // ASCII: quote string if needed + $word = '"'.addcslashes($word, '\\"').'"'; + } + } + $value .= $word.' '.$address; + } else { + // addr-spec not found, don't encode (?) + $value .= $part; + } + + // RFC2822 recommends 78 characters limit, use 76 from RFC2047 + $value = wordwrap($value, 76, $eol . ' '); + } + + // remove header name prefix (there could be EOL too) + $value = preg_replace( + '/^'.$name.':('.preg_quote($eol, '/').')* /', '', $value + ); + + } else { + // Unstructured header + // non-ASCII: require encoding + if (preg_match('#([\x80-\xFF]){1}#', $value)) { + if ($value[0] == '"' && $value[strlen($value)-1] == '"') { + // de-quote quoted-string, encoding changes + // string to atom + $search = array("\\\"", "\\\\"); + $replace = array("\"", "\\"); + $value = str_replace($search, $replace, $value); + $value = substr($value, 1, -1); + } + $value = Mail_mimePart::encodeHeaderValue( + $value, $charset, $encoding, strlen($name) + 2, $eol + ); + } else if (strlen($name.': '.$value) > 78) { + // ASCII: check if header line isn't too long and use folding + $value = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $value); + $tmp = wordwrap($name.': '.$value, 78, $eol . ' '); + $value = preg_replace('/^'.$name.':\s*/', '', $tmp); + // hard limit 998 (RFC2822) + $value = wordwrap($value, 998, $eol . ' ', true); + } + } + + return $value; + } + + /** + * Explode quoted string + * + * @param string $delimiter Delimiter expression string for preg_match() + * @param string $string Input string + * + * @return array String tokens array + * @access private + */ + function _explodeQuotedString($delimiter, $string) + { + $result = array(); + $strlen = strlen($string); + + for ($q=$p=$i=0; $i < $strlen; $i++) { + if ($string[$i] == "\"" + && (empty($string[$i-1]) || $string[$i-1] != "\\") + ) { + $q = $q ? false : true; + } else if (!$q && preg_match("/$delimiter/", $string[$i])) { + $result[] = substr($string, $p, $i - $p); + $p = $i + 1; + } + } + + $result[] = substr($string, $p); + return $result; + } + + /** + * Encodes a header value as per RFC2047 + * + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param int $prefix_len Prefix length. Default: 0 + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded header data + * @access public + * @since 1.6.1 + */ + function encodeHeaderValue($value, $charset, $encoding, $prefix_len=0, $eol="\r\n") + { + // #17311: Use multibyte aware method (requires mbstring extension) + if ($result = Mail_mimePart::encodeMB($value, $charset, $encoding, $prefix_len, $eol)) { + return $result; + } + + // Generate the header using the specified params and dynamicly + // determine the maximum length of such strings. + // 75 is the value specified in the RFC. + $encoding = $encoding == 'base64' ? 'B' : 'Q'; + $prefix = '=?' . $charset . '?' . $encoding .'?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix); + $maxLength1stLine = $maxLength - $prefix_len; + + if ($encoding == 'B') { + // Base64 encode the entire string + $value = base64_encode($value); + + // We can cut base64 every 4 characters, so the real max + // we can get must be rounded down. + $maxLength = $maxLength - ($maxLength % 4); + $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4); + + $cutpoint = $maxLength1stLine; + $output = ''; + + while ($value) { + // Split translated string at every $maxLength + $part = substr($value, 0, $cutpoint); + $value = substr($value, $cutpoint); + $cutpoint = $maxLength; + // RFC 2047 specifies that any split header should + // be separated by a CRLF SPACE. + if ($output) { + $output .= $eol . ' '; + } + $output .= $prefix . $part . $suffix; + } + $value = $output; + } else { + // quoted-printable encoding has been selected + $value = Mail_mimePart::encodeQP($value); + + // This regexp will break QP-encoded text at every $maxLength + // but will not break any encoded letters. + $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|"; + $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; + + if (strlen($value) > $maxLength1stLine) { + // Begin with the regexp for the first line. + $reg = $reg1st; + $output = ''; + while ($value) { + // Split translated string at every $maxLength + // But make sure not to break any translated chars. + $found = preg_match($reg, $value, $matches); + + // After this first line, we need to use a different + // regexp for the first line. + $reg = $reg2nd; + + // Save the found part and encapsulate it in the + // prefix & suffix. Then remove the part from the + // $value_out variable. + if ($found) { + $part = $matches[0]; + $len = strlen($matches[0]); + $value = substr($value, $len); + } else { + $part = $value; + $value = ''; + } + + // RFC 2047 specifies that any split header should + // be separated by a CRLF SPACE + if ($output) { + $output .= $eol . ' '; + } + $output .= $prefix . $part . $suffix; + } + $value = $output; + } else { + $value = $prefix . $value . $suffix; + } + } + + return $value; + } + + /** + * Encodes the given string using quoted-printable + * + * @param string $str String to encode + * + * @return string Encoded string + * @access public + * @since 1.6.0 + */ + function encodeQP($str) + { + // Bug #17226 RFC 2047 restricts some characters + // if the word is inside a phrase, permitted chars are only: + // ASCII letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" + + // "=", "_", "?" must be encoded + $regexp = '/([\x22-\x29\x2C\x2E\x3A-\x40\x5B-\x60\x7B-\x7E\x80-\xFF])/'; + $str = preg_replace_callback( + $regexp, array('Mail_mimePart', '_qpReplaceCallback'), $str + ); + + return str_replace(' ', '_', $str); + } + + /** + * Encodes the given string using base64 or quoted-printable. + * This method makes sure that encoded-word represents an integral + * number of characters as per RFC2047. + * + * @param string $str String to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param int $prefix_len Prefix length. Default: 0 + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded string + * @access public + * @since 1.8.0 + */ + function encodeMB($str, $charset, $encoding, $prefix_len=0, $eol="\r\n") + { + if (!function_exists('mb_substr') || !function_exists('mb_strlen')) { + return; + } + + $encoding = $encoding == 'base64' ? 'B' : 'Q'; + // 75 is the value specified in the RFC + $prefix = '=?' . $charset . '?'.$encoding.'?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix); + + // A multi-octet character may not be split across adjacent encoded-words + // So, we'll loop over each character + // mb_stlen() with wrong charset will generate a warning here and return null + $length = mb_strlen($str, $charset); + $result = ''; + $line_length = $prefix_len; + + if ($encoding == 'B') { + // base64 + $start = 0; + $prev = ''; + + for ($i=1; $i<=$length; $i++) { + // See #17311 + $chunk = mb_substr($str, $start, $i-$start, $charset); + $chunk = base64_encode($chunk); + $chunk_len = strlen($chunk); + + if ($line_length + $chunk_len == $maxLength || $i == $length) { + if ($result) { + $result .= "\n"; + } + $result .= $chunk; + $line_length = 0; + $start = $i; + } else if ($line_length + $chunk_len > $maxLength) { + if ($result) { + $result .= "\n"; + } + if ($prev) { + $result .= $prev; + } + $line_length = 0; + $start = $i - 1; + } else { + $prev = $chunk; + } + } + } else { + // quoted-printable + // see encodeQP() + $regexp = '/([\x22-\x29\x2C\x2E\x3A-\x40\x5B-\x60\x7B-\x7E\x80-\xFF])/'; + + for ($i=0; $i<=$length; $i++) { + $char = mb_substr($str, $i, 1, $charset); + // RFC recommends underline (instead of =20) in place of the space + // that's one of the reasons why we're not using iconv_mime_encode() + if ($char == ' ') { + $char = '_'; + $char_len = 1; + } else { + $char = preg_replace_callback( + $regexp, array('Mail_mimePart', '_qpReplaceCallback'), $char + ); + $char_len = strlen($char); + } + + if ($line_length + $char_len > $maxLength) { + if ($result) { + $result .= "\n"; + } + $line_length = 0; + } + + $result .= $char; + $line_length += $char_len; + } + } + + if ($result) { + $result = $prefix + .str_replace("\n", $suffix.$eol.' '.$prefix, $result).$suffix; + } + + return $result; + } + + /** + * Callback function to replace extended characters (\x80-xFF) with their + * ASCII values (RFC2047: quoted-printable) + * + * @param array $matches Preg_replace's matches array + * + * @return string Encoded character string + * @access private + */ + function _qpReplaceCallback($matches) + { + return sprintf('=%02X', ord($matches[1])); + } + + /** + * Callback function to replace extended characters (\x80-xFF) with their + * ASCII values (RFC2231) + * + * @param array $matches Preg_replace's matches array + * + * @return string Encoded character string + * @access private + */ + function _encodeReplaceCallback($matches) + { + return sprintf('%%%02X', ord($matches[1])); + } + + /** + * PEAR::isError implementation + * + * @param mixed $data Object + * + * @return bool True if object is an instance of PEAR_Error + * @access private + */ + function _isError($data) + { + // PEAR::isError() is not PHP 5.4 compatible (see Bug #19473) + if (is_object($data) && is_a($data, 'PEAR_Error')) { + return true; + } + + return false; + } + + /** + * PEAR::raiseError implementation + * + * @param $message A text error message + * + * @return PEAR_Error Instance of PEAR_Error + * @access private + */ + function _raiseError($message) + { + // PEAR::raiseError() is not PHP 5.4 compatible + return new PEAR_Error($message); + } + +} // End of class diff --git a/vas/rest/class/PEAR/Mail/mock.php b/vas/rest/class/PEAR/Mail/mock.php new file mode 100755 index 0000000000000000000000000000000000000000..971dae6a0e0da47a839c3318cf34dc1b18142755 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/mock.php @@ -0,0 +1,119 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ +// +// $Id: mock.php,v 1.1 2007/12/08 17:57:54 chagenbu Exp $ +// + +/** + * Mock implementation of the PEAR Mail:: interface for testing. + * @access public + * @package Mail + * @version $Revision: 1.1 $ + */ +class Mail_mock extends Mail { + + /** + * Array of messages that have been sent with the mock. + * + * @var array + * @access public + */ + var $sentMessages = array(); + + /** + * Callback before sending mail. + * + * @var callback + */ + var $_preSendCallback; + + /** + * Callback after sending mai. + * + * @var callback + */ + var $_postSendCallback; + + /** + * Constructor. + * + * Instantiates a new Mail_mock:: object based on the parameters + * passed in. It looks for the following parameters, both optional: + * preSendCallback Called before an email would be sent. + * postSendCallback Called after an email would have been sent. + * + * @param array Hash containing any parameters. + * @access public + */ + function Mail_mock($params) + { + if (isset($params['preSendCallback']) && + is_callable($params['preSendCallback'])) { + $this->_preSendCallback = $params['preSendCallback']; + } + + if (isset($params['postSendCallback']) && + is_callable($params['postSendCallback'])) { + $this->_postSendCallback = $params['postSendCallback']; + } + } + + /** + * Implements Mail_mock::send() function. Silently discards all + * mail. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + if ($this->_preSendCallback) { + call_user_func_array($this->_preSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + $entry = array('recipients' => $recipients, 'headers' => $headers, 'body' => $body); + $this->sentMessages[] = $entry; + + if ($this->_postSendCallback) { + call_user_func_array($this->_postSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + return true; + } + +} diff --git a/vas/rest/class/PEAR/Mail/net/SMTP.php b/vas/rest/class/PEAR/Mail/net/SMTP.php new file mode 100755 index 0000000000000000000000000000000000000000..a768745929009a5041e45d67a96bf169548dacce --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/SMTP.php @@ -0,0 +1,1082 @@ +<?php +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Chuck Hagenbuch <chuck@horde.org> | +// | Jon Parise <jon@php.net> | +// | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> | +// +----------------------------------------------------------------------+ +// +// $Id: SMTP.php,v 1.63 2008/06/10 05:39:12 jon Exp $ + +require_once 'PEAR/PEAR.php'; +require_once 'Socket.php'; + +/** + * Provides an implementation of the SMTP protocol using PEAR's + * Net_Socket:: class. + * + * @package Net_SMTP + * @author Chuck Hagenbuch <chuck@horde.org> + * @author Jon Parise <jon@php.net> + * @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> + * + * @example basic.php A basic implementation of the Net_SMTP package. + */ +class Net_SMTP +{ + /** + * The server to connect to. + * @var string + * @access public + */ + var $host = 'localhost'; + + /** + * The port to connect to. + * @var int + * @access public + */ + var $port = 25; + + /** + * The value to give when sending EHLO or HELO. + * @var string + * @access public + */ + var $localhost = 'localhost'; + + /** + * List of supported authentication methods, in preferential order. + * @var array + * @access public + */ + var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN'); + + /** + * Use SMTP command pipelining (specified in RFC 2920) if the SMTP + * server supports it. + * + * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(), + * somlFrom() and samlFrom() do not wait for a response from the + * SMTP server but return immediately. + * + * @var bool + * @access public + */ + var $pipelining = false; + + /** + * Number of pipelined commands. + * @var int + * @access private + */ + var $_pipelined_commands = 0; + + /** + * Should debugging output be enabled? + * @var boolean + * @access private + */ + var $_debug = false; + + /** + * The socket resource being used to connect to the SMTP server. + * @var resource + * @access private + */ + var $_socket = null; + + /** + * The most recent server response code. + * @var int + * @access private + */ + var $_code = -1; + + /** + * The most recent server response arguments. + * @var array + * @access private + */ + var $_arguments = array(); + + /** + * Stores detected features of the SMTP server. + * @var array + * @access private + */ + var $_esmtp = array(); + + /** + * Instantiates a new Net_SMTP object, overriding any defaults + * with parameters that are passed in. + * + * If you have SSL support in PHP, you can connect to a server + * over SSL using an 'ssl://' prefix: + * + * // 465 is a common smtps port. + * $smtp = new Net_SMTP('ssl://mail.host.com', 465); + * $smtp->connect(); + * + * @param string $host The server to connect to. + * @param integer $port The port to connect to. + * @param string $localhost The value to give when sending EHLO or HELO. + * @param boolean $pipeling Use SMTP command pipelining + * + * @access public + * @since 1.0 + */ + function Net_SMTP($host = null, $port = null, $localhost = null, $pipelining = false) + { + if (isset($host)) { + $this->host = $host; + } + if (isset($port)) { + $this->port = $port; + } + if (isset($localhost)) { + $this->localhost = $localhost; + } + $this->pipelining = $pipelining; + + $this->_socket = new Net_Socket(); + + /* Include the Auth_SASL package. If the package is not + * available, we disable the authentication methods that + * depend upon it. */ + if ((@include_once 'Auth/SASL.php') === false) { + $pos = array_search('DIGEST-MD5', $this->auth_methods); + unset($this->auth_methods[$pos]); + $pos = array_search('CRAM-MD5', $this->auth_methods); + unset($this->auth_methods[$pos]); + } + } + + /** + * Set the value of the debugging flag. + * + * @param boolean $debug New value for the debugging flag. + * + * @access public + * @since 1.1.0 + */ + function setDebug($debug) + { + $this->_debug = $debug; + } + + /** + * Send the given string of data to the server. + * + * @param string $data The string of data to send. + * + * @return mixed True on success or a PEAR_Error object on failure. + * + * @access private + * @since 1.1.0 + */ + function _send($data) + { + if ($this->_debug) { + echo "DEBUG: Send: $data\n"; + } + + if (PEAR::isError($error = $this->_socket->write($data))) { + return PEAR::raiseError('Failed to write to socket: ' . + $error->getMessage()); + } + + return true; + } + + /** + * Send a command to the server with an optional string of + * arguments. A carriage return / linefeed (CRLF) sequence will + * be appended to each command string before it is sent to the + * SMTP server - an error will be thrown if the command string + * already contains any newline characters. Use _send() for + * commands that must contain newlines. + * + * @param string $command The SMTP command to send to the server. + * @param string $args A string of optional arguments to append + * to the command. + * + * @return mixed The result of the _send() call. + * + * @access private + * @since 1.1.0 + */ + function _put($command, $args = '') + { + if (!empty($args)) { + $command .= ' ' . $args; + } + + if (strcspn($command, "\r\n") !== strlen($command)) { + return PEAR::raiseError('Commands cannot contain newlines'); + } + + return $this->_send($command . "\r\n"); + } + + /** + * Read a reply from the SMTP server. The reply consists of a response + * code and a response message. + * + * @param mixed $valid The set of valid response codes. These + * may be specified as an array of integer + * values or as a single integer value. + * @param bool $later Do not parse the response now, but wait + * until the last command in the pipelined + * command group + * + * @return mixed True if the server returned a valid response code or + * a PEAR_Error object is an error condition is reached. + * + * @access private + * @since 1.1.0 + * + * @see getResponse + */ + function _parseResponse($valid, $later = false) + { + $this->_code = -1; + $this->_arguments = array(); + + if ($later) { + $this->_pipelined_commands++; + return true; + } + + for ($i = 0; $i <= $this->_pipelined_commands; $i++) { + while ($line = $this->_socket->readLine()) { + if ($this->_debug) { + echo "DEBUG: Recv: $line\n"; + } + + /* If we receive an empty line, the connection has been closed. */ + if (empty($line)) { + $this->disconnect(); + return PEAR::raiseError('Connection was unexpectedly closed'); + } + + /* Read the code and store the rest in the arguments array. */ + $code = substr($line, 0, 3); + $this->_arguments[] = trim(substr($line, 4)); + + /* Check the syntax of the response code. */ + if (is_numeric($code)) { + $this->_code = (int)$code; + } else { + $this->_code = -1; + break; + } + + /* If this is not a multiline response, we're done. */ + if (substr($line, 3, 1) != '-') { + break; + } + } + } + + $this->_pipelined_commands = 0; + + /* Compare the server's response code with the valid code/codes. */ + if (is_int($valid) && ($this->_code === $valid)) { + return true; + } elseif (is_array($valid) && in_array($this->_code, $valid, true)) { + return true; + } + + return PEAR::raiseError('Invalid response code received from server', + $this->_code); + } + + /** + * Return a 2-tuple containing the last response from the SMTP server. + * + * @return array A two-element array: the first element contains the + * response code as an integer and the second element + * contains the response's arguments as a string. + * + * @access public + * @since 1.1.0 + */ + function getResponse() + { + return array($this->_code, join("\n", $this->_arguments)); + } + + /** + * Attempt to connect to the SMTP server. + * + * @param int $timeout The timeout value (in seconds) for the + * socket connection. + * @param bool $persistent Should a persistent socket connection + * be used? + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function connect($timeout = null, $persistent = false) + { + $result = $this->_socket->connect($this->host, $this->port, + $persistent, $timeout); + if (PEAR::isError($result)) { + return PEAR::raiseError('Failed to connect socket: ' . + $result->getMessage()); + } + + if (PEAR::isError($error = $this->_parseResponse(220))) { + return $error; + } + if (PEAR::isError($error = $this->_negotiate())) { + return $error; + } + + return true; + } + + /** + * Attempt to disconnect from the SMTP server. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function disconnect() + { + if (PEAR::isError($error = $this->_put('QUIT'))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(221))) { + return $error; + } + if (PEAR::isError($error = $this->_socket->disconnect())) { + return PEAR::raiseError('Failed to disconnect socket: ' . + $error->getMessage()); + } + + return true; + } + + /** + * Attempt to send the EHLO command and obtain a list of ESMTP + * extensions available, and failing that just send HELO. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * + * @access private + * @since 1.1.0 + */ + function _negotiate() + { + if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) { + return $error; + } + + if (PEAR::isError($this->_parseResponse(250))) { + /* If we receive a 503 response, we're already authenticated. */ + if ($this->_code === 503) { + return true; + } + + /* If the EHLO failed, try the simpler HELO command. */ + if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) { + return $error; + } + if (PEAR::isError($this->_parseResponse(250))) { + return PEAR::raiseError('HELO was not accepted: ', $this->_code); + } + + return true; + } + + foreach ($this->_arguments as $argument) { + $verb = strtok($argument, ' '); + $arguments = substr($argument, strlen($verb) + 1, + strlen($argument) - strlen($verb) - 1); + $this->_esmtp[$verb] = $arguments; + } + + if (!isset($this->_esmtp['PIPELINING'])) { + $this->pipelining = false; + } + + return true; + } + + /** + * Returns the name of the best authentication method that the server + * has advertised. + * + * @return mixed Returns a string containing the name of the best + * supported authentication method or a PEAR_Error object + * if a failure condition is encountered. + * @access private + * @since 1.1.0 + */ + function _getBestAuthMethod() + { + $available_methods = explode(' ', $this->_esmtp['AUTH']); + + foreach ($this->auth_methods as $method) { + if (in_array($method, $available_methods)) { + return $method; + } + } + + return PEAR::raiseError('No supported authentication methods'); + } + + /** + * Attempt to do SMTP authentication. + * + * @param string The userid to authenticate as. + * @param string The password to authenticate with. + * @param string The requested authentication method. If none is + * specified, the best supported method will be used. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function auth($uid, $pwd , $method = '') + { + if (empty($this->_esmtp['AUTH'])) { + if (version_compare(PHP_VERSION, '5.1.0', '>=')) { + if (!isset($this->_esmtp['STARTTLS'])) { + return PEAR::raiseError('SMTP server does not support authentication'); + } + if (PEAR::isError($result = $this->_put('STARTTLS'))) { + return $result; + } + if (PEAR::isError($result = $this->_parseResponse(220))) { + return $result; + } + if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) { + return $result; + } elseif ($result !== true) { + return PEAR::raiseError('STARTTLS failed'); + } + + /* Send EHLO again to recieve the AUTH string from the + * SMTP server. */ + $this->_negotiate(); + if (empty($this->_esmtp['AUTH'])) { + return PEAR::raiseError('SMTP server does not support authentication'); + } + } else { + return PEAR::raiseError('SMTP server does not support authentication'); + } + } + + /* If no method has been specified, get the name of the best + * supported method advertised by the SMTP server. */ + if (empty($method)) { + if (PEAR::isError($method = $this->_getBestAuthMethod())) { + /* Return the PEAR_Error object from _getBestAuthMethod(). */ + return $method; + } + } else { + $method = strtoupper($method); + if (!in_array($method, $this->auth_methods)) { + return PEAR::raiseError("$method is not a supported authentication method"); + } + } + + switch ($method) { + case 'DIGEST-MD5': + $result = $this->_authDigest_MD5($uid, $pwd); + break; + + case 'CRAM-MD5': + $result = $this->_authCRAM_MD5($uid, $pwd); + break; + + case 'LOGIN': + $result = $this->_authLogin($uid, $pwd); + break; + + case 'PLAIN': + $result = $this->_authPlain($uid, $pwd); + break; + + default: + $result = PEAR::raiseError("$method is not a supported authentication method"); + break; + } + + /* If an error was encountered, return the PEAR_Error object. */ + if (PEAR::isError($result)) { + return $result; + } + + return true; + } + + /** + * Authenticates the user using the DIGEST-MD5 method. + * + * @param string The userid to authenticate as. + * @param string The password to authenticate with. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access private + * @since 1.1.0 + */ + function _authDigest_MD5($uid, $pwd) + { + if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + /* 503: Error: already authenticated */ + if ($this->_code === 503) { + return true; + } + return $error; + } + + $challenge = base64_decode($this->_arguments[0]); + $digest = &Auth_SASL::factory('digestmd5'); + $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge, + $this->host, "smtp")); + + if (PEAR::isError($error = $this->_put($auth_str))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + return $error; + } + + /* We don't use the protocol's third step because SMTP doesn't + * allow subsequent authentication, so we just silently ignore + * it. */ + if (PEAR::isError($error = $this->_put(''))) { + return $error; + } + /* 235: Authentication successful */ + if (PEAR::isError($error = $this->_parseResponse(235))) { + return $error; + } + } + + /** + * Authenticates the user using the CRAM-MD5 method. + * + * @param string The userid to authenticate as. + * @param string The password to authenticate with. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access private + * @since 1.1.0 + */ + function _authCRAM_MD5($uid, $pwd) + { + if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + /* 503: Error: already authenticated */ + if ($this->_code === 503) { + return true; + } + return $error; + } + + $challenge = base64_decode($this->_arguments[0]); + $cram = &Auth_SASL::factory('crammd5'); + $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge)); + + if (PEAR::isError($error = $this->_put($auth_str))) { + return $error; + } + + /* 235: Authentication successful */ + if (PEAR::isError($error = $this->_parseResponse(235))) { + return $error; + } + } + + /** + * Authenticates the user using the LOGIN method. + * + * @param string The userid to authenticate as. + * @param string The password to authenticate with. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access private + * @since 1.1.0 + */ + function _authLogin($uid, $pwd) + { + if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + /* 503: Error: already authenticated */ + if ($this->_code === 503) { + return true; + } + return $error; + } + + if (PEAR::isError($error = $this->_put(base64_encode($uid)))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + return $error; + } + + if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) { + return $error; + } + + /* 235: Authentication successful */ + if (PEAR::isError($error = $this->_parseResponse(235))) { + return $error; + } + + return true; + } + + /** + * Authenticates the user using the PLAIN method. + * + * @param string The userid to authenticate as. + * @param string The password to authenticate with. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access private + * @since 1.1.0 + */ + function _authPlain($uid, $pwd) + { + if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) { + return $error; + } + /* 334: Continue authentication request */ + if (PEAR::isError($error = $this->_parseResponse(334))) { + /* 503: Error: already authenticated */ + if ($this->_code === 503) { + return true; + } + return $error; + } + + $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd); + + if (PEAR::isError($error = $this->_put($auth_str))) { + return $error; + } + + /* 235: Authentication successful */ + if (PEAR::isError($error = $this->_parseResponse(235))) { + return $error; + } + + return true; + } + + /** + * Send the HELO command. + * + * @param string The domain name to say we are. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function helo($domain) + { + if (PEAR::isError($error = $this->_put('HELO', $domain))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250))) { + return $error; + } + + return true; + } + + /** + * Return the list of SMTP service extensions advertised by the server. + * + * @return array The list of SMTP service extensions. + * @access public + * @since 1.3 + */ + function getServiceExtensions() + { + return $this->_esmtp; + } + + /** + * Send the MAIL FROM: command. + * + * @param string $sender The sender (reverse path) to set. + * @param string $params String containing additional MAIL parameters, + * such as the NOTIFY flags defined by RFC 1891 + * or the VERP protocol. + * + * If $params is an array, only the 'verp' option + * is supported. If 'verp' is true, the XVERP + * parameter is appended to the MAIL command. If + * the 'verp' value is a string, the full + * XVERP=value parameter is appended. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function mailFrom($sender, $params = null) + { + $args = "FROM:<$sender>"; + + /* Support the deprecated array form of $params. */ + if (is_array($params) && isset($params['verp'])) { + /* XVERP */ + if ($params['verp'] === true) { + $args .= ' XVERP'; + + /* XVERP=something */ + } elseif (trim($params['verp'])) { + $args .= ' XVERP=' . $params['verp']; + } + } elseif (is_string($params)) { + $args .= ' ' . $params; + } + + if (PEAR::isError($error = $this->_put('MAIL', $args))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Send the RCPT TO: command. + * + * @param string $recipient The recipient (forward path) to add. + * @param string $params String containing additional RCPT parameters, + * such as the NOTIFY flags defined by RFC 1891. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * + * @access public + * @since 1.0 + */ + function rcptTo($recipient, $params = null) + { + $args = "TO:<$recipient>"; + if (is_string($params)) { + $args .= ' ' . $params; + } + + if (PEAR::isError($error = $this->_put('RCPT', $args))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(array(250, 251), $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Quote the data so that it meets SMTP standards. + * + * This is provided as a separate public function to facilitate + * easier overloading for the cases where it is desirable to + * customize the quoting behavior. + * + * @param string $data The message text to quote. The string must be passed + * by reference, and the text will be modified in place. + * + * @access public + * @since 1.2 + */ + function quotedata(&$data) + { + /* Change Unix (\n) and Mac (\r) linefeeds into + * Internet-standard CRLF (\r\n) linefeeds. */ + $data = preg_replace(array('/(?<!\r)\n/','/\r(?!\n)/'), "\r\n", $data); + + /* Because a single leading period (.) signifies an end to the + * data, legitimate leading periods need to be "doubled" + * (e.g. '..'). */ + $data = str_replace("\n.", "\n..", $data); + } + + /** + * Send the DATA command. + * + * @param string $data The message body to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function data($data) + { + /* RFC 1870, section 3, subsection 3 states "a value of zero + * indicates that no fixed maximum message size is in force". + * Furthermore, it says that if "the parameter is omitted no + * information is conveyed about the server's fixed maximum + * message size". */ + if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) { + if (strlen($data) >= $this->_esmtp['SIZE']) { + $this->disconnect(); + return PEAR::raiseError('Message size excedes the server limit'); + } + } + + /* Quote the data based on the SMTP standards. */ + $this->quotedata($data); + + if (PEAR::isError($error = $this->_put('DATA'))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(354))) { + return $error; + } + + if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) { + return $result; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Send the SEND FROM: command. + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.2.6 + */ + function sendFrom($path) + { + if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Backwards-compatibility wrapper for sendFrom(). + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * + * @access public + * @since 1.0 + * @deprecated 1.2.6 + */ + function send_from($path) + { + return sendFrom($path); + } + + /** + * Send the SOML FROM: command. + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.2.6 + */ + function somlFrom($path) + { + if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Backwards-compatibility wrapper for somlFrom(). + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * + * @access public + * @since 1.0 + * @deprecated 1.2.6 + */ + function soml_from($path) + { + return somlFrom($path); + } + + /** + * Send the SAML FROM: command. + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.2.6 + */ + function samlFrom($path) + { + if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Backwards-compatibility wrapper for samlFrom(). + * + * @param string The reverse path to send. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * + * @access public + * @since 1.0 + * @deprecated 1.2.6 + */ + function saml_from($path) + { + return samlFrom($path); + } + + /** + * Send the RSET command. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function rset() + { + if (PEAR::isError($error = $this->_put('RSET'))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { + return $error; + } + + return true; + } + + /** + * Send the VRFY command. + * + * @param string The string to verify + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function vrfy($string) + { + /* Note: 251 is also a valid response code */ + if (PEAR::isError($error = $this->_put('VRFY', $string))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(array(250, 252)))) { + return $error; + } + + return true; + } + + /** + * Send the NOOP command. + * + * @return mixed Returns a PEAR_Error with an error message on any + * kind of failure, or true on success. + * @access public + * @since 1.0 + */ + function noop() + { + if (PEAR::isError($error = $this->_put('NOOP'))) { + return $error; + } + if (PEAR::isError($error = $this->_parseResponse(250))) { + return $error; + } + + return true; + } + + /** + * Backwards-compatibility method. identifySender()'s functionality is + * now handled internally. + * + * @return boolean This method always return true. + * + * @access public + * @since 1.0 + */ + function identifySender() + { + return true; + } + +} diff --git a/vas/rest/class/PEAR/Mail/net/Socket.php b/vas/rest/class/PEAR/Mail/net/Socket.php new file mode 100755 index 0000000000000000000000000000000000000000..845ce5e9fe0cfd10c358c28e05537fa302d2e9c2 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/Socket.php @@ -0,0 +1,592 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Stig Bakken <ssb@php.net> | +// | Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ +// +// $Id: Socket.php,v 1.38 2008/02/15 18:24:17 chagenbu Exp $ + +require_once 'PEAR/PEAR.php'; + +define('NET_SOCKET_READ', 1); +define('NET_SOCKET_WRITE', 2); +define('NET_SOCKET_ERROR', 4); + +/** + * Generalized Socket class. + * + * @version 1.1 + * @author Stig Bakken <ssb@php.net> + * @author Chuck Hagenbuch <chuck@horde.org> + */ +class Net_Socket extends PEAR { + + /** + * Socket file pointer. + * @var resource $fp + */ + var $fp = null; + + /** + * Whether the socket is blocking. Defaults to true. + * @var boolean $blocking + */ + var $blocking = true; + + /** + * Whether the socket is persistent. Defaults to false. + * @var boolean $persistent + */ + var $persistent = false; + + /** + * The IP address to connect to. + * @var string $addr + */ + var $addr = ''; + + /** + * The port number to connect to. + * @var integer $port + */ + var $port = 0; + + /** + * Number of seconds to wait on socket connections before assuming + * there's no more data. Defaults to no timeout. + * @var integer $timeout + */ + var $timeout = false; + + /** + * Number of bytes to read at a time in readLine() and + * readAll(). Defaults to 2048. + * @var integer $lineLength + */ + var $lineLength = 2048; + + /** + * Connect to the specified port. If called when the socket is + * already connected, it disconnects and connects again. + * + * @param string $addr IP address or host name. + * @param integer $port TCP port number. + * @param boolean $persistent (optional) Whether the connection is + * persistent (kept open between requests + * by the web server). + * @param integer $timeout (optional) How long to wait for data. + * @param array $options See options for stream_context_create. + * + * @access public + * + * @return boolean | PEAR_Error True on success or a PEAR_Error on failure. + */ + function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null) + { + if (is_resource($this->fp)) { + @fclose($this->fp); + $this->fp = null; + } + + if (!$addr) { + return $this->raiseError('$addr cannot be empty'); + } elseif (strspn($addr, '.0123456789') == strlen($addr) || + strstr($addr, '/') !== false) { + $this->addr = $addr; + } else { + $this->addr = @gethostbyname($addr); + } + + $this->port = $port % 65536; + + if ($persistent !== null) { + $this->persistent = $persistent; + } + + if ($timeout !== null) { + $this->timeout = $timeout; + } + + $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen'; + $errno = 0; + $errstr = ''; + $old_track_errors = @ini_set('track_errors', 1); + if ($options && function_exists('stream_context_create')) { + if ($this->timeout) { + $timeout = $this->timeout; + } else { + $timeout = 0; + } + $context = stream_context_create($options); + + // Since PHP 5 fsockopen doesn't allow context specification + if (function_exists('stream_socket_client')) { + $flags = $this->persistent ? STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT; + $addr = $this->addr . ':' . $this->port; + $fp = stream_socket_client($addr, $errno, $errstr, $timeout, $flags, $context); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + } + } else { + if ($this->timeout) { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr); + } + } + + if (!$fp) { + if ($errno == 0 && isset($php_errormsg)) { + $errstr = $php_errormsg; + } + @ini_set('track_errors', $old_track_errors); + return $this->raiseError($errstr, $errno); + } + + @ini_set('track_errors', $old_track_errors); + $this->fp = $fp; + + return $this->setBlocking($this->blocking); + } + + /** + * Disconnects from the peer, closes the socket. + * + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function disconnect() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + @fclose($this->fp); + $this->fp = null; + return true; + } + + /** + * Find out if the socket is in blocking mode. + * + * @access public + * @return boolean The current blocking mode. + */ + function isBlocking() + { + return $this->blocking; + } + + /** + * Sets whether the socket connection should be blocking or + * not. A read call to a non-blocking socket will return immediately + * if there is no data available, whereas it will block until there + * is data for blocking sockets. + * + * @param boolean $mode True for blocking sockets, false for nonblocking. + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function setBlocking($mode) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $this->blocking = $mode; + socket_set_blocking($this->fp, $this->blocking); + return true; + } + + /** + * Sets the timeout value on socket descriptor, + * expressed in the sum of seconds and microseconds + * + * @param integer $seconds Seconds. + * @param integer $microseconds Microseconds. + * @access public + * @return mixed true on success or a PEAR_Error instance otherwise + */ + function setTimeout($seconds, $microseconds) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_set_timeout($this->fp, $seconds, $microseconds); + } + + /** + * Sets the file buffering size on the stream. + * See php's stream_set_write_buffer for more information. + * + * @param integer $size Write buffer size. + * @access public + * @return mixed on success or an PEAR_Error object otherwise + */ + function setWriteBuffer($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $returned = stream_set_write_buffer($this->fp, $size); + if ($returned == 0) { + return true; + } + return $this->raiseError('Cannot set write buffer.'); + } + + /** + * Returns information about an existing socket resource. + * Currently returns four entries in the result array: + * + * <p> + * timed_out (bool) - The socket timed out waiting for data<br> + * blocked (bool) - The socket was blocked<br> + * eof (bool) - Indicates EOF event<br> + * unread_bytes (int) - Number of bytes left in the socket buffer<br> + * </p> + * + * @access public + * @return mixed Array containing information about existing socket resource or a PEAR_Error instance otherwise + */ + function getStatus() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_get_status($this->fp); + } + + /** + * Get a specified line of data + * + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function gets($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fgets($this->fp, $size); + } + + /** + * Read a specified amount of data. This is guaranteed to return, + * and has the added benefit of getting everything in one fread() + * chunk; if you know the size of the data you're getting + * beforehand, this is definitely the way to go. + * + * @param integer $size The number of bytes to read from the socket. + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function read($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fread($this->fp, $size); + } + + /** + * Write a specified amount of data. + * + * @param string $data Data to write. + * @param integer $blocksize Amount of data to write at once. + * NULL means all at once. + * + * @access public + * @return mixed If the socket is not connected, returns an instance of PEAR_Error + * If the write succeeds, returns the number of bytes written + * If the write fails, returns false. + */ + function write($data, $blocksize = null) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + if (is_null($blocksize) && !OS_WINDOWS) { + return @fwrite($this->fp, $data); + } else { + if (is_null($blocksize)) { + $blocksize = 1024; + } + + $pos = 0; + $size = strlen($data); + while ($pos < $size) { + $written = @fwrite($this->fp, substr($data, $pos, $blocksize)); + if ($written === false) { + return false; + } + $pos += $written; + } + + return $pos; + } + } + + /** + * Write a line of data to the socket, followed by a trailing "\r\n". + * + * @access public + * @return mixed fputs result, or an error + */ + function writeLine($data) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return fwrite($this->fp, $data . "\r\n"); + } + + /** + * Tests for end-of-file on a socket descriptor. + * + * Also returns true if the socket is disconnected. + * + * @access public + * @return bool + */ + function eof() + { + return (!is_resource($this->fp) || feof($this->fp)); + } + + /** + * Reads a byte of data + * + * @access public + * @return 1 byte of data from the socket, or a PEAR_Error if + * not connected. + */ + function readByte() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return ord(@fread($this->fp, 1)); + } + + /** + * Reads a word of data + * + * @access public + * @return 1 word of data from the socket, or a PEAR_Error if + * not connected. + */ + function readWord() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 2); + return (ord($buf[0]) + (ord($buf[1]) << 8)); + } + + /** + * Reads an int of data + * + * @access public + * @return integer 1 int of data from the socket, or a PEAR_Error if + * not connected. + */ + function readInt() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return (ord($buf[0]) + (ord($buf[1]) << 8) + + (ord($buf[2]) << 16) + (ord($buf[3]) << 24)); + } + + /** + * Reads a zero-terminated string of data + * + * @access public + * @return string, or a PEAR_Error if + * not connected. + */ + function readString() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $string = ''; + while (($char = @fread($this->fp, 1)) != "\x00") { + $string .= $char; + } + return $string; + } + + /** + * Reads an IP Address and returns it in a dot formatted string + * + * @access public + * @return Dot formatted string, or a PEAR_Error if + * not connected. + */ + function readIPAddress() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]), + ord($buf[2]), ord($buf[3])); + } + + /** + * Read until either the end of the socket or a newline, whichever + * comes first. Strips the trailing newline from the returned data. + * + * @access public + * @return All available data up to a newline, without that + * newline, or until the end of the socket, or a PEAR_Error if + * not connected. + */ + function readLine() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $line = ''; + $timeout = time() + $this->timeout; + while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) { + $line .= @fgets($this->fp, $this->lineLength); + if (substr($line, -1) == "\n") { + return rtrim($line, "\r\n"); + } + } + return $line; + } + + /** + * Read until the socket closes, or until there is no more data in + * the inner PHP buffer. If the inner buffer is empty, in blocking + * mode we wait for at least 1 byte of data. Therefore, in + * blocking mode, if there is no data at all to be read, this + * function will never exit (unless the socket is closed on the + * remote end). + * + * @access public + * + * @return string All data until the socket closes, or a PEAR_Error if + * not connected. + */ + function readAll() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $data = ''; + while (!feof($this->fp)) { + $data .= @fread($this->fp, $this->lineLength); + } + return $data; + } + + /** + * Runs the equivalent of the select() system call on the socket + * with a timeout specified by tv_sec and tv_usec. + * + * @param integer $state Which of read/write/error to check for. + * @param integer $tv_sec Number of seconds for timeout. + * @param integer $tv_usec Number of microseconds for timeout. + * + * @access public + * @return False if select fails, integer describing which of read/write/error + * are ready, or PEAR_Error if not connected. + */ + function select($state, $tv_sec, $tv_usec = 0) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $read = null; + $write = null; + $except = null; + if ($state & NET_SOCKET_READ) { + $read[] = $this->fp; + } + if ($state & NET_SOCKET_WRITE) { + $write[] = $this->fp; + } + if ($state & NET_SOCKET_ERROR) { + $except[] = $this->fp; + } + if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) { + return false; + } + + $result = 0; + if (count($read)) { + $result |= NET_SOCKET_READ; + } + if (count($write)) { + $result |= NET_SOCKET_WRITE; + } + if (count($except)) { + $result |= NET_SOCKET_ERROR; + } + return $result; + } + + /** + * Turns encryption on/off on a connected socket. + * + * @param bool $enabled Set this parameter to true to enable encryption + * and false to disable encryption. + * @param integer $type Type of encryption. See + * http://se.php.net/manual/en/function.stream-socket-enable-crypto.php for values. + * + * @access public + * @return false on error, true on success and 0 if there isn't enough data and the + * user should try again (non-blocking sockets only). A PEAR_Error object + * is returned if the socket is not connected + */ + function enableCrypto($enabled, $type) + { + if (version_compare(phpversion(), "5.1.0", ">=")) { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + return @stream_socket_enable_crypto($this->fp, $enabled, $type); + } else { + return $this->raiseError('Net_Socket::enableCrypto() requires php version >= 5.1.0'); + } + } + +} diff --git a/vas/rest/class/PEAR/Mail/net/docs/guide.txt b/vas/rest/class/PEAR/Mail/net/docs/guide.txt new file mode 100755 index 0000000000000000000000000000000000000000..04b401c19ebb03754c433e10ca0df2af1af010e6 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/docs/guide.txt @@ -0,0 +1,211 @@ +====================== + The Net_SMTP Package +====================== + +-------------------- + User Documentation +-------------------- + +:Author: Jon Parise +:Contact: jon@php.net +:Date: $Date: 2005/03/04 03:35:45 $ +:Revision: $Revision: 1.5 $ + +.. contents:: Table of Contents +.. section-numbering:: + +Dependencies +============ + +The `PEAR_Error` Class +---------------------- + +The Net_SMTP package uses the `PEAR_Error`_ class for all of its `error +handling`_. + +The `Net_Socket` Package +------------------------ + +The Net_Socket_ package is used as the basis for all network communications. + +The `Auth_SASL` Package +----------------------- + +The `Auth_SASL`_ package is an optional dependency. If it is available, the +Net_SMTP package will be able to support the DIGEST-MD5_ and CRAM-MD5_ SMTP +authentication methods. Otherwise, only the LOGIN_ and PLAIN_ methods will +be available. + +Error Handling +============== + +All of the Net_SMTP class's public methods return a PEAR_Error_ object if an +error occurs. The standard way to check for a PEAR_Error object is by using +`PEAR::isError()`_:: + + if (PEAR::isError($error = $smtp->connect())) { + die($error->getMessage()); + } + +.. _PEAR::isError(): http://pear.php.net/manual/en/core.pear.pear.iserror.php + +SMTP Authentication +=================== + +The Net_SMTP package supports the SMTP authentication standard (as defined +by RFC-2554_). The Net_SMTP package supports the following authentication +methods, in order of preference: + +.. _RFC-2554: http://www.ietf.org/rfc/rfc2554.txt + +DIGEST-MD5 +---------- + +The DIGEST-MD5 authentication method uses `RSA Data Security Inc.`_'s MD5 +Message Digest algorithm. It is considered the most secure method of SMTP +authentication. + +**Note:** The DIGEST-MD5 authentication method is only supported if the +AUTH_SASL_ package is available. + +.. _RSA Data Security Inc.: http://www.rsasecurity.com/ + +CRAM-MD5 +-------- + +The CRAM-MD5 authentication method has been superseded by the DIGEST-MD5_ +method in terms of security. It is provided here for compatibility with +older SMTP servers that may not support the newer DIGEST-MD5 algorithm. + +**Note:** The CRAM-MD5 authentication method is only supported if the +AUTH_SASL_ package is available. + +LOGIN +----- + +The LOGIN authentication method encrypts the user's password using the +Base64_ encoding scheme. Because decrypting a Base64-encoded string is +trivial, LOGIN is not considered a secure authentication method and should +be avoided. + +.. _Base64: http://www.php.net/manual/en/function.base64-encode.php + +PLAIN +----- + +The PLAIN authentication method sends the user's password in plain text. +This method of authentication is not secure and should be avoided. + +Secure Connections +================== + +If `secure socket transports`_ have been enabled in PHP, it is possible to +establish a secure connection to the remote SMTP server:: + + $smtp = new Net_SMTP('ssl://mail.example.com', 465); + +This example connects to `mail.example.com` on port 465 (a common SMTPS +port) using the `ssl://` transport. + +.. _secure socket transports: http://www.php.net/transports + +Data Quoting +============ + +By default, all outbound string data is quoted in accordance with SMTP +standards. This means that all native Unix (`\\n`) and Mac (`\\r`) line +endings are converted to Internet-standard CRLF (`\\r\\n`) line endings. +Also, because the SMTP protocol uses a single leading period (`.`) to signal +an end to the message data, single leading periods in the original data +string are "doubled" (e.g. "`..`"). + +These string transformation can be expensive when large blocks of data are +involved. For example, the Net_SMTP package is not aware of MIME parts (it +just sees the MIME message as one big string of characters), so it is not +able to skip non-text attachments when searching for characters that may +need to be quoted. + +Because of this, it is possible to extend the Net_SMTP class in order to +implement your own custom quoting routine. Just create a new class based on +the Net_SMTP class and reimplement the `quotedata()` method:: + + require 'Net_SMTP.php'; + + class Net_SMTP_custom extends Net_SMTP + { + function quotedata($data) + { + /* Perform custom data quoting */ + } + } + +Note that the `$data` parameter will be passed to the `quotedata()` function +`by reference`_. This means that you can operate directly on `$data`. It +also the overhead of copying a large `$data` string to and from the +`quotedata()` method. + +.. _by reference: http://www.php.net/manual/en/language.references.pass.php + +Debugging +========= + +The Net_SMTP package contains built-in debugging output routines (disabled +by default). Debugging output must be explicitly enabled via the setDebug() +method:: + + $smtp->setDebug(true); + +The debugging messages will be sent to the standard output stream. + +Examples +======== + +Basic Use +--------- + +The following script demonstrates how a simple email message can be sent +using the Net_SMTP package:: + + require 'Net/SMTP.php'; + + $host = 'mail.example.com'; + $from = 'user@example.com'; + $rcpt = array('recipient1@example.com', 'recipient2@example.com'); + $subj = "Subject: Test Message\n"; + $body = "Body Line 1\nBody Line 2"; + + /* Create a new Net_SMTP object. */ + if (! ($smtp = new Net_SMTP($host))) { + die("Unable to instantiate Net_SMTP object\n"); + } + + /* Connect to the SMTP server. */ + if (PEAR::isError($e = $smtp->connect())) { + die($e->getMessage() . "\n"); + } + + /* Send the 'MAIL FROM:' SMTP command. */ + if (PEAR::isError($smtp->mailFrom($from))) { + die("Unable to set sender to <$from>\n"); + } + + /* Address the message to each of the recipients. */ + foreach ($rcpt as $to) { + if (PEAR::isError($res = $smtp->rcptTo($to))) { + die("Unable to add recipient <$to>: " . $res->getMessage() . "\n"); + } + } + + /* Set the body of the message. */ + if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) { + die("Unable to send data\n"); + } + + /* Disconnect from the SMTP server. */ + $smtp->disconnect(); + +.. _PEAR_Error: http://pear.php.net/manual/en/core.pear.pear-error.php +.. _Net_Socket: http://pear.php.net/package/Net_Socket +.. _Auth_SASL: http://pear.php.net/package/Auth_SASL + +.. vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=76: diff --git a/vas/rest/class/PEAR/Mail/net/examples/basic.php b/vas/rest/class/PEAR/Mail/net/examples/basic.php new file mode 100755 index 0000000000000000000000000000000000000000..07a105878213e4fc7975e9d0b17e54b918d3dc8f --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/examples/basic.php @@ -0,0 +1,39 @@ +<?php + +require 'Net/SMTP.php'; + +$host = 'mail.example.com'; +$from = 'user@example.com'; +$rcpt = array('recipient1@example.com', 'recipient2@example.com'); +$subj = "Subject: Test Message\n"; +$body = "Body Line 1\nBody Line 2"; + +/* Create a new Net_SMTP object. */ +if (! ($smtp = new Net_SMTP($host))) { + die("Unable to instantiate Net_SMTP object\n"); +} + +/* Connect to the SMTP server. */ +if (PEAR::isError($e = $smtp->connect())) { + die($e->getMessage() . "\n"); +} + +/* Send the 'MAIL FROM:' SMTP command. */ +if (PEAR::isError($smtp->mailFrom($from))) { + die("Unable to set sender to <$from>\n"); +} + +/* Address the message to each of the recipients. */ +foreach ($rcpt as $to) { + if (PEAR::isError($res = $smtp->rcptTo($to))) { + die("Unable to add recipient <$to>: " . $res->getMessage() . "\n"); + } +} + +/* Set the body of the message. */ +if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) { + die("Unable to send data\n"); +} + +/* Disconnect from the SMTP server. */ +$smtp->disconnect(); diff --git a/vas/rest/class/PEAR/Mail/net/tests/auth.phpt b/vas/rest/class/PEAR/Mail/net/tests/auth.phpt new file mode 100755 index 0000000000000000000000000000000000000000..3b80bf813c02b3957f6b68fb95298eb63bb1adf6 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/tests/auth.phpt @@ -0,0 +1,40 @@ +--TEST-- +Net_SMTP: SMTP Authentication +--SKIPIF-- +<?php if (!@include('config.php')) die("skip\n"); +--FILE-- +<?php + +require_once 'Net/SMTP.php'; +require_once 'config.php'; + +if (! ($smtp = new Net_SMTP(TEST_HOSTNAME, TEST_PORT, TEST_LOCALHOST))) { + die("Unable to instantiate Net_SMTP object\n"); +} + +if (PEAR::isError($e = $smtp->connect())) { + die($e->getMessage() . "\n"); +} + +if (PEAR::isError($e = $smtp->auth(TEST_AUTH_USER, TEST_AUTH_PASS))) { +} + +if (PEAR::isError($smtp->mailFrom(TEST_FROM))) { + die('Unable to set sender to <' . TEST_FROM . ">\n"); +} + +if (PEAR::isError($res = $smtp->rcptTo(TEST_TO))) { + die('Unable to add recipient <' . TEST_TO . '>: ' . + $res->getMessage() . "\n"); +} + +if (PEAR::isError($smtp->data(TEST_SUBJECT . "\r\n" . TEST_BODY))) { + die("Unable to send data\n"); +} + +$smtp->disconnect(); + +echo 'Success!'; + +--EXPECT-- +Success! diff --git a/vas/rest/class/PEAR/Mail/net/tests/basic.phpt b/vas/rest/class/PEAR/Mail/net/tests/basic.phpt new file mode 100755 index 0000000000000000000000000000000000000000..94734d86656ab0bfdd754148de3c59d111f18fa4 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/tests/basic.phpt @@ -0,0 +1,37 @@ +--TEST-- +Net_SMTP: Basic Functionality +--SKIPIF-- +<?php if (!@include('config.php')) die("skip\n"); +--FILE-- +<?php + +require_once 'Net/SMTP.php'; +require_once 'config.php'; + +if (! ($smtp = new Net_SMTP(TEST_HOSTNAME, TEST_PORT, TEST_LOCALHOST))) { + die("Unable to instantiate Net_SMTP object\n"); +} + +if (PEAR::isError($e = $smtp->connect())) { + die($e->getMessage() . "\n"); +} + +if (PEAR::isError($smtp->mailFrom(TEST_FROM))) { + die('Unable to set sender to <' . TEST_FROM . ">\n"); +} + +if (PEAR::isError($res = $smtp->rcptTo(TEST_TO))) { + die('Unable to add recipient <' . TEST_TO . '>: ' . + $res->getMessage() . "\n"); +} + +if (PEAR::isError($smtp->data(TEST_SUBJECT . "\r\n" . TEST_BODY))) { + die("Unable to send data\n"); +} + +$smtp->disconnect(); + +echo 'Success!'; + +--EXPECT-- +Success! diff --git a/vas/rest/class/PEAR/Mail/net/tests/config.php.dist b/vas/rest/class/PEAR/Mail/net/tests/config.php.dist new file mode 100755 index 0000000000000000000000000000000000000000..fe4a0c97510f34e9c0c912282f3acf4da513ff3e --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/tests/config.php.dist @@ -0,0 +1,15 @@ +<?php +/** + * Copy this file to config.php and customize the following values to + * suit your configuration. + */ + +define('TEST_HOSTNAME', 'localhost'); +define('TEST_PORT', 25); +define('TEST_LOCALHOST', 'localhost'); +define('TEST_AUTH_USER', 'jon'); +define('TEST_AUTH_PASS', 'secret'); +define('TEST_FROM', 'from@example.com'); +define('TEST_TO', 'to@example.com'); +define('TEST_SUBJECT', 'Test Subject'); +define('TEST_BODY', 'Test Body'); diff --git a/vas/rest/class/PEAR/Mail/net/tests/quotedata.phpt b/vas/rest/class/PEAR/Mail/net/tests/quotedata.phpt new file mode 100755 index 0000000000000000000000000000000000000000..518d4f69e451e4e870a461ec8fda7c17244d633b --- /dev/null +++ b/vas/rest/class/PEAR/Mail/net/tests/quotedata.phpt @@ -0,0 +1,62 @@ +--TEST-- +Net_SMTP: quotedata() \n | \r => \r\n replacement +--FILE-- +<?php + +error_reporting(E_ALL); +require_once 'Net/SMTP.php'; + +$tests = array( + "\n" => "\r\n", + "\r\n" => "\r\n", + "\nxx" => "\r\nxx", + "xx\n" => "xx\r\n", + "xx\nxx" => "xx\r\nxx", + "\n\nxx" => "\r\n\r\nxx", + "xx\n\nxx" => "xx\r\n\r\nxx", + "xx\n\n" => "xx\r\n\r\n", + "\r\nxx" => "\r\nxx", + "xx\r\n" => "xx\r\n", + "xx\r\nxx" => "xx\r\nxx", + "\r\n\r\nxx" => "\r\n\r\nxx", + "xx\r\n\r\nxx" => "xx\r\n\r\nxx", + "xx\r\n\r\n" => "xx\r\n\r\n", + "\r\n\nxx" => "\r\n\r\nxx", + "\n\r\nxx" => "\r\n\r\nxx", + "xx\r\n\nxx" => "xx\r\n\r\nxx", + "xx\n\r\nxx" => "xx\r\n\r\nxx", + "xx\r\n\n" => "xx\r\n\r\n", + "xx\n\r\n" => "xx\r\n\r\n", + "\r" => "\r\n", + "\rxx" => "\r\nxx", + "xx\rxx" => "xx\r\nxx", + "xx\r" => "xx\r\n", + "\r\r" => "\r\n\r\n", + "\r\rxx" => "\r\n\r\nxx", + "xx\r\rxx" => "xx\r\n\r\nxx", + "xx\r\r" => "xx\r\n\r\n", + "xx\rxx\nxx\r\nxx" => "xx\r\nxx\r\nxx\r\nxx", + "\r\r\n\n" => "\r\n\r\n\r\n", +); + +$hadError = false; +foreach ($tests as $input => $expect) { + $output = $input; + Net_SMTP::quotedata($output); + if ($output != $expect) { + echo "Error: input " . prettyprint($input) . ", output " . prettyprint($output) . ", expected " . prettyprint($expect) . "\n"; + $hadError = true; + } +} + +if (!$hadError) { + echo "success\n"; +} + +function prettyprint($x) +{ + return str_replace(array("\r", "\n"), array('\r', '\n'), $x); +} + +--EXPECT-- +success diff --git a/vas/rest/class/PEAR/Mail/null.php b/vas/rest/class/PEAR/Mail/null.php new file mode 100755 index 0000000000000000000000000000000000000000..982bfa45b6d652132a5219fb273d4327e505e856 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/null.php @@ -0,0 +1,60 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Phil Kernick <philk@rotfl.com.au> | +// +----------------------------------------------------------------------+ +// +// $Id: null.php,v 1.2 2004/04/06 05:19:03 jon Exp $ +// + +/** + * Null implementation of the PEAR Mail:: interface. + * @access public + * @package Mail + * @version $Revision: 1.2 $ + */ +class Mail_null extends Mail { + + /** + * Implements Mail_null::send() function. Silently discards all + * mail. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + return true; + } + +} diff --git a/vas/rest/class/PEAR/Mail/sendmail.php b/vas/rest/class/PEAR/Mail/sendmail.php new file mode 100755 index 0000000000000000000000000000000000000000..cd248e61d267e4c70b6078833e171ac62605eb6a --- /dev/null +++ b/vas/rest/class/PEAR/Mail/sendmail.php @@ -0,0 +1,170 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ + +/** + * Sendmail implementation of the PEAR Mail:: interface. + * @access public + * @package Mail + * @version $Revision: 1.19 $ + */ +class Mail_sendmail extends Mail { + + /** + * The location of the sendmail or sendmail wrapper binary on the + * filesystem. + * @var string + */ + var $sendmail_path = '/usr/sbin/sendmail'; + + /** + * Any extra command-line parameters to pass to the sendmail or + * sendmail wrapper binary. + * @var string + */ + var $sendmail_args = '-i'; + + /** + * Constructor. + * + * Instantiates a new Mail_sendmail:: object based on the parameters + * passed in. It looks for the following parameters: + * sendmail_path The location of the sendmail binary on the + * filesystem. Defaults to '/usr/sbin/sendmail'. + * + * sendmail_args Any extra parameters to pass to the sendmail + * or sendmail wrapper binary. + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @param array $params Hash containing any parameters different from the + * defaults. + * @access public + */ + function Mail_sendmail($params) + { + if (isset($params['sendmail_path'])) { + $this->sendmail_path = $params['sendmail_path']; + } + if (isset($params['sendmail_args'])) { + $this->sendmail_args = $params['sendmail_args']; + } + + /* + * Because we need to pass message headers to the sendmail program on + * the commandline, we can't guarantee the use of the standard "\r\n" + * separator. Instead, we use the system's native line separator. + */ + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } + } + + /** + * Implements Mail::send() function using the sendmail + * command-line binary. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + return $recipients; + } + $recipients = escapeShellCmd(implode(' ', $recipients)); + + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list($from, $text_headers) = $headerElements; + + /* Since few MTAs are going to allow this header to be forged + * unless it's in the MAIL FROM: exchange, we'll use + * Return-Path instead of From: if it's set. */ + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + + if (!isset($from)) { + return PEAR::raiseError('No from address given.'); + } elseif (strpos($from, ' ') !== false || + strpos($from, ';') !== false || + strpos($from, '&') !== false || + strpos($from, '`') !== false) { + return PEAR::raiseError('From address specified with dangerous characters.'); + } + + $from = escapeShellCmd($from); + $mail = @popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w'); + if (!$mail) { + return PEAR::raiseError('Failed to open sendmail [' . $this->sendmail_path . '] for execution.'); + } + + // Write the headers following by two newlines: one to end the headers + // section and a second to separate the headers block from the body. + fputs($mail, $text_headers . $this->sep . $this->sep); + + fputs($mail, $body); + $result = pclose($mail); + if (version_compare(phpversion(), '4.2.3') == -1) { + // With older php versions, we need to shift the pclose + // result to get the exit code. + $result = $result >> 8 & 0xFF; + } + + if ($result != 0) { + return PEAR::raiseError('sendmail returned error code ' . $result, + $result); + } + + return true; + } + +} diff --git a/vas/rest/class/PEAR/Mail/smtp.php b/vas/rest/class/PEAR/Mail/smtp.php new file mode 100755 index 0000000000000000000000000000000000000000..52b95735415a768ad406421302408840c851fd55 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/smtp.php @@ -0,0 +1,407 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.02 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Chuck Hagenbuch <chuck@horde.org> | +// | Jon Parise <jon@php.net> | +// +----------------------------------------------------------------------+ + +/** Error: Failed to create a Net_SMTP object */ +define('PEAR_MAIL_SMTP_ERROR_CREATE', 10000); + +/** Error: Failed to connect to SMTP server */ +define('PEAR_MAIL_SMTP_ERROR_CONNECT', 10001); + +/** Error: SMTP authentication failure */ +define('PEAR_MAIL_SMTP_ERROR_AUTH', 10002); + +/** Error: No From: address has been provided */ +define('PEAR_MAIL_SMTP_ERROR_FROM', 10003); + +/** Error: Failed to set sender */ +define('PEAR_MAIL_SMTP_ERROR_SENDER', 10004); + +/** Error: Failed to add recipient */ +define('PEAR_MAIL_SMTP_ERROR_RECIPIENT', 10005); + +/** Error: Failed to send data */ +define('PEAR_MAIL_SMTP_ERROR_DATA', 10006); + +/** + * SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * @access public + * @package Mail + * @version $Revision: 1.33 $ + */ +class Mail_smtp extends Mail { + + /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The list of service extension parameters to pass to the Net_SMTP + * mailFrom() command. + * @var array + */ + var $_extparams = array(); + + /** + * The SMTP host to connect to. + * @var string + */ + var $host = 'localhost'; + + /** + * The port the SMTP server is on. + * @var integer + */ + var $port = 25; + + /** + * Should SMTP authentication be used? + * + * This value may be set to true, false or the name of a specific + * authentication method. + * + * If the value is set to true, the Net_SMTP package will attempt to use + * the best authentication method advertised by the remote SMTP server. + * + * @var mixed + */ + var $auth = false; + + /** + * The username to use if the SMTP server requires authentication. + * @var string + */ + var $username = ''; + + /** + * The password to use if the SMTP server requires authentication. + * @var string + */ + var $password = ''; + + /** + * Hostname or domain that will be sent to the remote SMTP server in the + * HELO / EHLO message. + * + * @var string + */ + var $localhost = 'localhost'; + + /** + * SMTP connection timeout value. NULL indicates no timeout. + * + * @var integer + */ + var $timeout = null; + + /** + * Turn on Net_SMTP debugging? + * + * @var boolean $debug + */ + var $debug = false; + + /** + * Indicates whether or not the SMTP connection should persist over + * multiple calls to the send() method. + * + * @var boolean + */ + var $persist = false; + + /** + * Use SMTP command pipelining (specified in RFC 2920) if the SMTP server + * supports it. This speeds up delivery over high-latency connections. By + * default, use the default value supplied by Net_SMTP. + * @var bool + */ + var $pipelining; + + /** + * Constructor. + * + * Instantiates a new Mail_smtp:: object based on the parameters + * passed in. It looks for the following parameters: + * host The server to connect to. Defaults to localhost. + * port The port to connect to. Defaults to 25. + * auth SMTP authentication. Defaults to none. + * username The username to use for SMTP auth. No default. + * password The password to use for SMTP auth. No default. + * localhost The local hostname / domain. Defaults to localhost. + * timeout The SMTP connection timeout. Defaults to none. + * verp Whether to use VERP or not. Defaults to false. + * DEPRECATED as of 1.2.0 (use setMailParams()). + * debug Activate SMTP debug mode? Defaults to false. + * persist Should the SMTP connection persist? + * pipelining Use SMTP command pipelining + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @param array Hash containing any parameters different from the + * defaults. + * @access public + */ + function Mail_smtp($params) + { + if (isset($params['host'])) $this->host = $params['host']; + if (isset($params['port'])) $this->port = $params['port']; + if (isset($params['auth'])) $this->auth = $params['auth']; + if (isset($params['username'])) $this->username = $params['username']; + if (isset($params['password'])) $this->password = $params['password']; + if (isset($params['localhost'])) $this->localhost = $params['localhost']; + if (isset($params['timeout'])) $this->timeout = $params['timeout']; + if (isset($params['debug'])) $this->debug = (bool)$params['debug']; + if (isset($params['persist'])) $this->persist = (bool)$params['persist']; + if (isset($params['pipelining'])) $this->pipelining = (bool)$params['pipelining']; + + // Deprecated options + if (isset($params['verp'])) { + $this->addServiceExtensionParameter('XVERP', is_bool($params['verp']) ? null : $params['verp']); + } + + register_shutdown_function(array(&$this, '_Mail_smtp')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function _Mail_smtp() + { + $this->disconnect(); + } + + /** + * Implements Mail::send() function using SMTP. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (e.g., 'Subject'), and the array value + * is the header value (e.g., 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * MIME parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + /* If we don't already have an SMTP object, create one. */ + $result = &$this->getSMTPObject(); + if (PEAR::isError($result)) { + return $result; + } + + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $this->_sanitizeHeaders($headers); + + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + $this->_smtp->rset(); + return $headerElements; + } + list($from, $textHeaders) = $headerElements; + + /* Since few MTAs are going to allow this header to be forged + * unless it's in the MAIL FROM: exchange, we'll use + * Return-Path instead of From: if it's set. */ + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + + if (!isset($from)) { + $this->_smtp->rset(); + return PEAR::raiseError('No From: address has been provided', + PEAR_MAIL_SMTP_ERROR_FROM); + } + + $params = null; + if (!empty($this->_extparams)) { + foreach ($this->_extparams as $key => $val) { + $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val); + } + } + if (PEAR::isError($res = $this->_smtp->mailFrom($from, ltrim($params)))) { + $error = $this->_error("Failed to set sender: $from", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_SENDER); + } + + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + $this->_smtp->rset(); + return $recipients; + } + + foreach ($recipients as $recipient) { + $res = $this->_smtp->rcptTo($recipient); + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error("Failed to add recipient: $recipient", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_RECIPIENT); + } + } + + /* Send the message's headers and the body as SMTP data. */ + $res = $this->_smtp->data($textHeaders . "\r\n\r\n" . $body); + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error('Failed to send data', $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_DATA); + } + + /* If persistent connections are disabled, destroy our SMTP object. */ + if ($this->persist === false) { + $this->disconnect(); + } + + return true; + } + + /** + * Connect to the SMTP server by instantiating a Net_SMTP object. + * + * @return mixed Returns a reference to the Net_SMTP object on success, or + * a PEAR_Error containing a descriptive error message on + * failure. + * + * @since 1.2.0 + * @access public + */ + function &getSMTPObject() + { + if (is_object($this->_smtp) !== false) { + return $this->_smtp; + } + + include_once 'net/SMTP.php'; + $this->_smtp = &new Net_SMTP($this->host, + $this->port, + $this->localhost); + + /* If we still don't have an SMTP object at this point, fail. */ + if (is_object($this->_smtp) === false) { + return PEAR::raiseError('Failed to create a Net_SMTP object', + PEAR_MAIL_SMTP_ERROR_CREATE); + } + + /* Configure the SMTP connection. */ + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + /* Attempt to connect to the configured SMTP server. */ + if (PEAR::isError($res = $this->_smtp->connect($this->timeout))) { + $error = $this->_error('Failed to connect to ' . + $this->host . ':' . $this->port, + $res); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_CONNECT); + } + + /* Attempt to authenticate if authentication has been enabled. */ + if ($this->auth) { + $method = is_string($this->auth) ? $this->auth : ''; + + if (PEAR::isError($res = $this->_smtp->auth($this->username, + $this->password, + $method))) { + $error = $this->_error("$method authentication failure", + $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_AUTH); + } + } + + return $this->_smtp; + } + + /** + * Add parameter associated with a SMTP service extension. + * + * @param string Extension keyword. + * @param string Any value the keyword needs. + * + * @since 1.2.0 + * @access public + */ + function addServiceExtensionParameter($keyword, $value = null) + { + $this->_extparams[$keyword] = $value; + } + + /** + * Disconnect and destroy the current SMTP connection. + * + * @return boolean True if the SMTP connection no longer exists. + * + * @since 1.1.9 + * @access public + */ + function disconnect() + { + /* If we have an SMTP object, disconnect and destroy it. */ + if (is_object($this->_smtp) && $this->_smtp->disconnect()) { + $this->_smtp = null; + } + + /* We are disconnected if we no longer have an SMTP object. */ + return ($this->_smtp === null); + } + + /** + * Build a standardized string describing the current SMTP error. + * + * @param string $text Custom string describing the error context. + * @param object $error Reference to the current PEAR_Error object. + * + * @return string A string describing the current SMTP error. + * + * @since 1.1.7 + * @access private + */ + function _error($text, &$error) + { + /* Split the SMTP response into a code and a response string. */ + list($code, $response) = $this->_smtp->getResponse(); + + /* Build our standardized error string. */ + return $text + . ' [SMTP: ' . $error->getMessage() + . " (code: $code, response: $response)]"; + } + +} diff --git a/vas/rest/class/PEAR/Mail/smtpmx.php b/vas/rest/class/PEAR/Mail/smtpmx.php new file mode 100755 index 0000000000000000000000000000000000000000..9d2dccfb13bc2676843a952ac5cb1788ac778f24 --- /dev/null +++ b/vas/rest/class/PEAR/Mail/smtpmx.php @@ -0,0 +1,478 @@ +<?PHP +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * SMTP MX + * + * SMTP MX implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Mail + * @package Mail_smtpmx + * @author gERD Schaufelberger <gerd@php-tools.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: smtpmx.php,v 1.2 2007/10/06 17:00:00 chagenbu Exp $ + * @see Mail + */ + +require_once 'Net/SMTP.php'; + +/** + * SMTP MX implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * + * + * @access public + * @author gERD Schaufelberger <gerd@php-tools.net> + * @package Mail + * @version $Revision: 1.2 $ + */ +class Mail_smtpmx extends Mail { + + /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The port the SMTP server is on. + * @var integer + * @see getservicebyname() + */ + var $port = 25; + + /** + * Hostname or domain that will be sent to the remote SMTP server in the + * HELO / EHLO message. + * + * @var string + * @see posix_uname() + */ + var $mailname = 'localhost'; + + /** + * SMTP connection timeout value. NULL indicates no timeout. + * + * @var integer + */ + var $timeout = 10; + + /** + * use either PEAR:Net_DNS or getmxrr + * + * @var boolean + */ + var $withNetDns = true; + + /** + * PEAR:Net_DNS_Resolver + * + * @var object + */ + var $resolver; + + /** + * Whether to use VERP or not. If not a boolean, the string value + * will be used as the VERP separators. + * + * @var mixed boolean or string + */ + var $verp = false; + + /** + * Whether to use VRFY or not. + * + * @var boolean $vrfy + */ + var $vrfy = false; + + /** + * Switch to test mode - don't send emails for real + * + * @var boolean $debug + */ + var $test = false; + + /** + * Turn on Net_SMTP debugging? + * + * @var boolean $peardebug + */ + var $debug = false; + + /** + * internal error codes + * + * translate internal error identifier to PEAR-Error codes and human + * readable messages. + * + * @var boolean $debug + * @todo as I need unique error-codes to identify what exactly went wrond + * I did not use intergers as it should be. Instead I added a "namespace" + * for each code. This avoids conflicts with error codes from different + * classes. How can I use unique error codes and stay conform with PEAR? + */ + var $errorCode = array( + 'not_connected' => array( + 'code' => 1, + 'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.' + ), + 'failed_vrfy_rcpt' => array( + 'code' => 2, + 'msg' => 'Recipient "{RCPT}" could not be veryfied.' + ), + 'failed_set_from' => array( + 'code' => 3, + 'msg' => 'Failed to set sender: {FROM}.' + ), + 'failed_set_rcpt' => array( + 'code' => 4, + 'msg' => 'Failed to set recipient: {RCPT}.' + ), + 'failed_send_data' => array( + 'code' => 5, + 'msg' => 'Failed to send mail to: {RCPT}.' + ), + 'no_from' => array( + 'code' => 5, + 'msg' => 'No from address has be provided.' + ), + 'send_data' => array( + 'code' => 7, + 'msg' => 'Failed to create Net_SMTP object.' + ), + 'no_mx' => array( + 'code' => 8, + 'msg' => 'No MX-record for {RCPT} found.' + ), + 'no_resolver' => array( + 'code' => 9, + 'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"' + ), + 'failed_rset' => array( + 'code' => 10, + 'msg' => 'RSET command failed, SMTP-connection corrupt.' + ), + ); + + /** + * Constructor. + * + * Instantiates a new Mail_smtp:: object based on the parameters + * passed in. It looks for the following parameters: + * mailname The name of the local mail system (a valid hostname which matches the reverse lookup) + * port smtp-port - the default comes from getservicebyname() and should work fine + * timeout The SMTP connection timeout. Defaults to 30 seconds. + * vrfy Whether to use VRFY or not. Defaults to false. + * verp Whether to use VERP or not. Defaults to false. + * test Activate test mode? Defaults to false. + * debug Activate SMTP and Net_DNS debug mode? Defaults to false. + * netdns whether to use PEAR:Net_DNS or the PHP build in function getmxrr, default is true + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @access public + * @param array Hash containing any parameters different from the + * defaults. + * @see _Mail_smtpmx() + */ + function __construct($params) + { + if (isset($params['mailname'])) { + $this->mailname = $params['mailname']; + } else { + // try to find a valid mailname + if (function_exists('posix_uname')) { + $uname = posix_uname(); + $this->mailname = $uname['nodename']; + } + } + + // port number + if (isset($params['port'])) { + $this->_port = $params['port']; + } else { + $this->_port = getservbyname('smtp', 'tcp'); + } + + if (isset($params['timeout'])) $this->timeout = $params['timeout']; + if (isset($params['verp'])) $this->verp = $params['verp']; + if (isset($params['test'])) $this->test = $params['test']; + if (isset($params['peardebug'])) $this->test = $params['peardebug']; + if (isset($params['netdns'])) $this->withNetDns = $params['netdns']; + } + + /** + * Constructor wrapper for PHP4 + * + * @access public + * @param array Hash containing any parameters different from the defaults + * @see __construct() + */ + function Mail_smtpmx($params) + { + $this->__construct($params); + register_shutdown_function(array(&$this, '__destruct')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function __destruct() + { + if (is_object($this->_smtp)) { + $this->_smtp->disconnect(); + $this->_smtp = null; + } + } + + /** + * Implements Mail::send() function using SMTP direct delivery + * + * @access public + * @param mixed $recipients in RFC822 style or array + * @param array $headers The array of headers to send with the mail. + * @param string $body The full text of the message body, + * @return mixed Returns true on success, or a PEAR_Error + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // Prepare headers + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list($from, $textHeaders) = $headerElements; + + // use 'Return-Path' if possible + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + if (!isset($from)) { + return $this->_raiseError('no_from'); + } + + // Prepare recipients + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + return $recipients; + } + + foreach ($recipients as $rcpt) { + list($user, $host) = explode('@', $rcpt); + + $mx = $this->_getMx($host); + if (is_a($mx, 'PEAR_Error')) { + return $mx; + } + + if (empty($mx)) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('no_mx', $info); + } + + $connected = false; + foreach ($mx as $mserver => $mpriority) { + $this->_smtp = new Net_SMTP($mserver, $this->port, $this->mailname); + + // configure the SMTP connection. + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + // attempt to connect to the configured SMTP server. + $res = $this->_smtp->connect($this->timeout); + if (is_a($res, 'PEAR_Error')) { + $this->_smtp = null; + continue; + } + + // connection established + if ($res) { + $connected = true; + break; + } + } + + if (!$connected) { + $info = array( + 'host' => implode(', ', array_keys($mx)), + 'port' => $this->port, + 'rcpt' => $rcpt, + ); + return $this->_raiseError('not_connected', $info); + } + + // Verify recipient + if ($this->vrfy) { + $res = $this->_smtp->vrfy($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_vrfy_rcpt', $info); + } + } + + // mail from: + $args['verp'] = $this->verp; + $res = $this->_smtp->mailFrom($from, $args); + if (is_a($res, 'PEAR_Error')) { + $info = array('from' => $from); + return $this->_raiseError('failed_set_from', $info); + } + + // rcpt to: + $res = $this->_smtp->rcptTo($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_set_rcpt', $info); + } + + // Don't send anything in test mode + if ($this->test) { + $result = $this->_smtp->rset(); + $res = $this->_smtp->rset(); + if (is_a($res, 'PEAR_Error')) { + return $this->_raiseError('failed_rset'); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + return true; + } + + // Send data + $res = $this->_smtp->data("$textHeaders\r\n$body"); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_send_data', $info); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + } + + return true; + } + + /** + * Recieve mx rexords for a spciefied host + * + * The MX records + * + * @access private + * @param string $host mail host + * @return mixed sorted + */ + function _getMx($host) + { + $mx = array(); + + if ($this->withNetDns) { + $res = $this->_loadNetDns(); + if (is_a($res, 'PEAR_Error')) { + return $res; + } + + $response = $this->resolver->query($host, 'MX'); + if (!$response) { + return false; + } + + foreach ($response->answer as $rr) { + if ($rr->type == 'MX') { + $mx[$rr->exchange] = $rr->preference; + } + } + } else { + $mxHost = array(); + $mxWeight = array(); + + if (!getmxrr($host, $mxHost, $mxWeight)) { + return false; + } + for ($i = 0; $i < count($mxHost); ++$i) { + $mx[$mxHost[$i]] = $mxWeight[$i]; + } + } + + asort($mx); + return $mx; + } + + /** + * initialize PEAR:Net_DNS_Resolver + * + * @access private + * @return boolean true on success + */ + function _loadNetDns() + { + if (is_object($this->resolver)) { + return true; + } + + if (!include_once 'Net/DNS.php') { + return $this->_raiseError('no_resolver'); + } + + $this->resolver = new Net_DNS_Resolver(); + if ($this->debug) { + $this->resolver->test = 1; + } + + return true; + } + + /** + * raise standardized error + * + * include additional information in error message + * + * @access private + * @param string $id maps error ids to codes and message + * @param array $info optional information in associative array + * @see _errorCode + */ + function _raiseError($id, $info = array()) + { + $code = $this->errorCode[$id]['code']; + $msg = $this->errorCode[$id]['msg']; + + // include info to messages + if (!empty($info)) { + $search = array(); + $replace = array(); + + foreach ($info as $key => $value) { + array_push($search, '{' . strtoupper($key) . '}'); + array_push($replace, $value); + } + + $msg = str_replace($search, $replace, $msg); + } + + return PEAR::raiseError($msg, $code); + } + +} diff --git a/vas/rest/class/PEAR/PEAR.php b/vas/rest/class/PEAR/PEAR.php new file mode 100755 index 0000000000000000000000000000000000000000..77d16cd10dc49782fd9fb04f3cad26ec0dc002c4 --- /dev/null +++ b/vas/rest/class/PEAR/PEAR.php @@ -0,0 +1,1118 @@ +<?php +/** + * PEAR, the PHP Extension and Application Repository + * + * PEAR class and PEAR_Error class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Sterling Hughes <sterling@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function __construct($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function __destruct() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } + } + return false; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if (intval(PHP_VERSION) < 5) { + // little non-eval hack to fix bug #12147 + include 'PEAR/FixPHP5PEARWarnings.php'; + return $a; + } + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + return $a; + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } else { + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Gregory Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function __construct($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + function __toString() + { + return $this->getMessage(); + } + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/vas/rest/class/PEAR/PackageFile.php b/vas/rest/class/PEAR/PackageFile.php new file mode 100755 index 0000000000000000000000000000000000000000..0dc42e9739c74475aa28f4620cf08ab19d0b7b30 --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile.php @@ -0,0 +1,474 @@ +<?php +/** + * PEAR_PackageFile, package.xml parsing utility class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PackageFile.php,v 1.41 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; +/** + * Error code if the package.xml <package> tag does not contain a valid version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); +/** + * Error code if the package.xml <package> tag version is not supported (version 1.0 and 1.1 are the only supported versions, + * currently + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); +/** + * Abstraction for the package.xml package description file + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile +{ + /** + * @var PEAR_Config + */ + var $_config; + var $_debug; + /** + * Temp directory for uncompressing tgz files. + * @var string|false + */ + var $_tmpdir; + var $_logger = false; + /** + * @var boolean + */ + var $_rawReturn = false; + + /** + * + * @param PEAR_Config $config + * @param ? $debug + * @param string @tmpdir Optional temporary directory for uncompressing + * files + */ + function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) + { + $this->_config = $config; + $this->_debug = $debug; + $this->_tmpdir = $tmpdir; + } + + /** + * Turn off validation - return a parsed package.xml without checking it + * + * This is used by the package-validate command + */ + function rawReturn() + { + $this->_rawReturn = true; + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + /** + * Create a PEAR_PackageFile_Parser_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 + */ + function &parserFactory($version) + { + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; + } + include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; + $version = $version{0}; + $class = "PEAR_PackageFile_Parser_v$version"; + $a = new $class; + return $a; + } + + /** + * For simpler unit-testing + * @return string + */ + function getClassPrefix() + { + return 'PEAR_PackageFile_v'; + } + + /** + * Create a PEAR_PackageFile_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 + */ + function &factory($version) + { + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; + } + include_once 'PEAR/PackageFile/v' . $version{0} . '.php'; + $version = $version{0}; + $class = $this->getClassPrefix() . $version; + $a = new $class; + return $a; + } + + /** + * Create a PEAR_PackageFile_v* from its toArray() method + * + * WARNING: no validation is performed, the array is assumed to be valid, + * always parse from xml if you want validation. + * @param array $arr + * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 + * @uses factory() to construct the returned object. + */ + function &fromArray($arr) + { + if (isset($arr['xsdversion'])) { + $obj = &$this->factory($arr['xsdversion']); + if ($this->_logger) { + $obj->setLogger($this->_logger); + } + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; + } else { + if (isset($arr['package']['attribs']['version'])) { + $obj = &$this->factory($arr['package']['attribs']['version']); + } else { + $obj = &$this->factory('1.0'); + } + if ($this->_logger) { + $obj->setLogger($this->_logger); + } + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; + } + } + + /** + * Create a PEAR_PackageFile_v* from an XML string. + * @access public + * @param string $data contents of package.xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string $file full path to the package.xml file (and the files + * it references) + * @param string $archive optional name of the archive that the XML was + * extracted from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses parserFactory() to construct a parser to load the package. + */ + function &fromXmlString($data, $state, $file, $archive = false) + { + if (preg_match('/<package[^>]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { + if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { + return PEAR::raiseError('package.xml version "' . $packageversion[1] . + '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); + } + $object = &$this->parserFactory($packageversion[1]); + if ($this->_logger) { + $object->setLogger($this->_logger); + } + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } + if ($this->_rawReturn) { + return $pf; + } + if ($pf->validate($state)) { + if ($this->_logger) { + if ($pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); + } + } + } + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + return $pf; + } else { + if ($this->_config->get('verbose') > 0) { + if ($this->_logger) { + if ($pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings(false) as $warning) { + $this->_logger->log(0, 'ERROR: ' . $warning['message']); + } + } + } + } + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; + } + } elseif (preg_match('/<package[^>]+version="([^"]+)"/', $data, $packageversion)) { + $a = PEAR::raiseError('package.xml file "' . $file . + '" has unsupported package.xml <package> version "' . $packageversion[1] . '"'); + return $a; + } else { + if (!class_exists('PEAR_ErrorStack')) { + require_once 'PEAR/ErrorStack.php'; + } + PEAR_ErrorStack::staticPush('PEAR_PackageFile', + PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, + 'warning', array('xml' => $data), 'package.xml "' . $file . + '" has no package.xml <package> version'); + $object = &$this->parserFactory('1.0'); + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } + if ($this->_rawReturn) { + return $pf; + } + if ($pf->validate($state)) { + if ($this->_logger) { + if ($pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); + } + } + } + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + return $pf; + } else { + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; + } + } + } + + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * @return void + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + /** + * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. + * @access public + * @param string contents of package.xml file + * @param int package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @using Archive_Tar to extract the files + * @using fromPackageFile() to load the package after the package.xml + * file is extracted. + */ + function &fromTgzFile($file, $state) + { + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; + } + $tar = new Archive_Tar($file); + if ($this->_debug <= 1) { + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + } + $content = $tar->listContent(); + if ($this->_debug <= 1) { + $tar->popErrorHandling(); + } + if (!is_array($content)) { + if (is_string($file) && strlen($file < 255) && + (!file_exists($file) || !@is_file($file))) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + $file = realpath($file); + $ret = PEAR::raiseError("Could not get contents of package \"$file\"". + '. Invalid tgz file.'); + return $ret; + } else { + if (!count($content) && !@is_file($file)) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + } + $xml = null; + $origfile = $file; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package2.xml') { // allow a .tgz to distribute both versions + $xml = $name; + break; + } + if ($name == 'package.xml') { + $xml = $name; + break; + } elseif (ereg('package.xml$', $name, $match)) { + $xml = $name; + break; + } + } + if ($this->_tmpdir) { + $tmpdir = $this->_tmpdir; + } else { + $tmpdir = System::mkTemp(array('-d', 'pear')); + PEAR_PackageFile::addTempFile($tmpdir); + } + $this->_extractErrors(); + PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + $extra = implode("\n", $this->_extractErrors()); + if ($extra) { + $extra = ' ' . $extra; + } + PEAR::staticPopErrorHandling(); + $ret = PEAR::raiseError('could not extract the package.xml file from "' . + $origfile . '"' . $extra); + return $ret; + } + PEAR::staticPopErrorHandling(); + $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); + return $ret; + } + + /** + * helper for extracting Archive_Tar errors + * @var array + * @access private + */ + var $_extractErrors = array(); + + /** + * helper callback for extracting Archive_Tar errors + * + * @param PEAR_Error|null $err + * @return array + * @access private + */ + function _extractErrors($err = null) + { + static $errors = array(); + if ($err === null) { + $e = $errors; + $errors = array(); + return $e; + } + $errors[] = $err->getMessage(); + } + + /** + * Create a PEAR_PackageFile_v* from a package.xml file. + * + * @access public + * @param string $descfile name of package xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string|false $archive name of the archive this package.xml came + * from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses PEAR_PackageFile::fromXmlString to create the oject after the + * XML is loaded from the package.xml file. + */ + function &fromPackageFile($descfile, $state, $archive = false) + { + if (is_string($descfile) && strlen($descfile) < 255 && + (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || + (!$fp = @fopen($descfile, 'r')))) { + $a = PEAR::raiseError("Unable to open $descfile"); + return $a; + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); + return $ret; + } + + + /** + * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. + * + * This method is able to extract information about a package from a .tgz + * archive or from a XML package definition file. + * + * @access public + * @param string $info file name + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses fromPackageFile() if the file appears to be XML + * @uses fromTgzFile() to load all non-XML files + */ + function &fromAnyFile($info, $state) + { + if (is_dir($info)) { + $dir_name = realpath($info); + if (file_exists($dir_name . '/package.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); + } elseif (file_exists($dir_name . '/package2.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); + } else { + $info = PEAR::raiseError("No package definition found in '$info' directory"); + } + return $info; + } + + $fp = false; + if (is_string($info) && strlen($info) < 255 && + (file_exists($info) || ($fp = @fopen($info, 'r')))) { + if ($fp) { + fclose($fp); + } + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = &PEAR_PackageFile::fromPackageFile($info, $state); + } elseif ($tmp == '.tar' || $tmp == '.tgz') { + $info = &PEAR_PackageFile::fromTgzFile($info, $state); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "<?xml") { + $info = &PEAR_PackageFile::fromPackageFile($info, $state); + } else { + $info = &PEAR_PackageFile::fromTgzFile($info, $state); + } + } + } else { + $info = PEAR::raiseError("Cannot open '$info' for parsing"); + return $info; + } + return $info; + } +} + +?> diff --git a/vas/rest/class/PEAR/PackageFile/Generator/v1.php b/vas/rest/class/PEAR/PackageFile/Generator/v1.php new file mode 100755 index 0000000000000000000000000000000000000000..e6c5c94c1261a2d58cd508689ad317d034d45c2f --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/Generator/v1.php @@ -0,0 +1,1272 @@ +<?php +/** + * package.xml generation class, package.xml version 1.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v1.php,v 1.74 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; +require_once 'System.php'; +require_once 'PEAR/PackageFile/v2.php'; +/** + * This class converts a PEAR_PackageFile_v1 object into any output format. + * + * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 + * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Generator_v1 +{ + /** + * @var PEAR_PackageFile_v1 + */ + var $_packagefile; + function PEAR_PackageFile_Generator_v1(&$packagefile) + { + $this->_packagefile = &$packagefile; + } + + function getPackagerVersion() + { + return '1.7.2'; + } + + /** + * @param PEAR_Packager + * @param bool if true, a .tgz is written, otherwise a .tar is written + * @param string|null directory in which to save the .tgz + * @return string|PEAR_Error location of package or error object + */ + function toTgz(&$packager, $compress = true, $where = null) + { + require_once 'Archive/Tar.php'; + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . + ' not be created'); + } + if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && + !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . + ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + } + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + } + $pkginfo = $this->_packagefile->getArray(); + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && + !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . + getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); + } + if ($pkgfile = $this->_packagefile->getPackageFile()) { + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + } else { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . + 'be created from a real file'); + } + // {{{ Create the package file list + $filelist = array(); + $i = 0; + + foreach ($this->_packagefile->getFilelist() as $fname => $atts) { + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return PEAR::raiseError("File does not exist: $fname"); + } else { + $filelist[$i++] = $file; + if (!isset($atts['md5sum'])) { + $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); + } + $packager->log(2, "Adding file $fname"); + } + } + // }}} + $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); + if ($packagexml) { + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($packagexml), '', $where); + if (PEAR::isError($ok)) { + return $ok; + } elseif (!$ok) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + return $dest_package; + } + } + + /** + * @param string|null directory to place the package.xml in, or null for a temporary dir + * @param int one of the PEAR_VALIDATE_* constants + * @param string name of the generated file + * @param bool if true, then no analysis will be performed on role="php" files + * @return string|PEAR_Error path to the created file on success + */ + function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', + $nofilechecking = false) + { + if (!$this->_packagefile->validate($state, $nofilechecking)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', + null, null, null, $this->_packagefile->getValidationWarnings()); + } + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . + ' not be created'); + } + $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . + "$name as $newpkgfile"); + } + fwrite($np, $this->toXml($state, true)); + fclose($np); + return $newpkgfile; + } + + /** + * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' + * + * @param string $string + * @return string + * @access private + */ + function _fixXmlEncoding($string) + { + if (version_compare(phpversion(), '5.0.0', 'lt')) { + $string = utf8_encode($string); + } + return strtr($string, array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @return string XML data + */ + function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) + { + $this->_packagefile->setDate(date('Y-m-d')); + if (!$this->_packagefile->validate($state, $nofilevalidation)) { + return false; + } + $pkginfo = $this->_packagefile->getArray(); + static $maint_map = array( + "handle" => "user", + "name" => "name", + "email" => "email", + "role" => "role", + ); + $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; + $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n"; + $ret .= "<package version=\"1.0\" packagerversion=\"1.7.2\">\n" . +" <name>$pkginfo[package]</name>"; + if (isset($pkginfo['extends'])) { + $ret .= "\n<extends>$pkginfo[extends]</extends>"; + } + $ret .= + "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" . +" <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" . +" <maintainers>\n"; + foreach ($pkginfo['maintainers'] as $maint) { + $ret .= " <maintainer>\n"; + foreach ($maint_map as $idx => $elm) { + $ret .= " <$elm>"; + $ret .= $this->_fixXmlEncoding($maint[$idx]); + $ret .= "</$elm>\n"; + } + $ret .= " </maintainer>\n"; + } + $ret .= " </maintainers>\n"; + $ret .= $this->_makeReleaseXml($pkginfo, false, $state); + if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { + $ret .= " <changelog>\n"; + foreach ($pkginfo['changelog'] as $oldrelease) { + $ret .= $this->_makeReleaseXml($oldrelease, true); + } + $ret .= " </changelog>\n"; + } + $ret .= "</package>\n"; + return $ret; + } + + // }}} + // {{{ _makeReleaseXml() + + /** + * Generate part of an XML description with release information. + * + * @param array $pkginfo array with release information + * @param bool $changelog whether the result will be in a changelog element + * + * @return string XML data + * + * @access private + */ + function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) + { + // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! + $indent = $changelog ? " " : ""; + $ret = "$indent <release>\n"; + if (!empty($pkginfo['version'])) { + $ret .= "$indent <version>$pkginfo[version]</version>\n"; + } + if (!empty($pkginfo['release_date'])) { + $ret .= "$indent <date>$pkginfo[release_date]</date>\n"; + } + if (!empty($pkginfo['release_license'])) { + $ret .= "$indent <license>$pkginfo[release_license]</license>\n"; + } + if (!empty($pkginfo['release_state'])) { + $ret .= "$indent <state>$pkginfo[release_state]</state>\n"; + } + if (!empty($pkginfo['release_notes'])) { + $ret .= "$indent <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) + ."\n$indent </notes>\n"; + } + if (!empty($pkginfo['release_warnings'])) { + $ret .= "$indent <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n"; + } + if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { + $ret .= "$indent <deps>\n"; + foreach ($pkginfo['release_deps'] as $dep) { + $ret .= "$indent <dep type=\"$dep[type]\" rel=\"$dep[rel]\""; + if (isset($dep['version'])) { + $ret .= " version=\"$dep[version]\""; + } + if (isset($dep['optional'])) { + $ret .= " optional=\"$dep[optional]\""; + } + if (isset($dep['name'])) { + $ret .= ">$dep[name]</dep>\n"; + } else { + $ret .= "/>\n"; + } + } + $ret .= "$indent </deps>\n"; + } + if (isset($pkginfo['configure_options'])) { + $ret .= "$indent <configureoptions>\n"; + foreach ($pkginfo['configure_options'] as $c) { + $ret .= "$indent <configureoption name=\"". + $this->_fixXmlEncoding($c['name']) . "\""; + if (isset($c['default'])) { + $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; + } + $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; + $ret .= "/>\n"; + } + $ret .= "$indent </configureoptions>\n"; + } + if (isset($pkginfo['provides'])) { + foreach ($pkginfo['provides'] as $key => $what) { + $ret .= "$indent <provides type=\"$what[type]\" "; + $ret .= "name=\"$what[name]\" "; + if (isset($what['extends'])) { + $ret .= "extends=\"$what[extends]\" "; + } + $ret .= "/>\n"; + } + } + if (isset($pkginfo['filelist'])) { + $ret .= "$indent <filelist>\n"; + if ($state ^ PEAR_VALIDATE_PACKAGING) { + $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']); + } else { + foreach ($pkginfo['filelist'] as $file => $fa) { + if (!isset($fa['role'])) { + $fa['role'] = ''; + } + $ret .= "$indent <file role=\"$fa[role]\""; + if (isset($fa['baseinstalldir'])) { + $ret .= ' baseinstalldir="' . + $this->_fixXmlEncoding($fa['baseinstalldir']) . '"'; + } + if (isset($fa['md5sum'])) { + $ret .= " md5sum=\"$fa[md5sum]\""; + } + if (isset($fa['platform'])) { + $ret .= " platform=\"$fa[platform]\""; + } + if (!empty($fa['install-as'])) { + $ret .= ' install-as="' . + $this->_fixXmlEncoding($fa['install-as']) . '"'; + } + $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; + if (empty($fa['replacements'])) { + $ret .= "/>\n"; + } else { + $ret .= ">\n"; + foreach ($fa['replacements'] as $r) { + $ret .= "$indent <replace"; + foreach ($r as $k => $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; + } + $ret .= "/>\n"; + } + $ret .= "$indent </file>\n"; + } + } + } + $ret .= "$indent </filelist>\n"; + } + $ret .= "$indent </release>\n"; + return $ret; + } + + /** + * @param array + * @access protected + */ + function recursiveXmlFilelist($list) + { + $this->_dirs = array(); + foreach ($list as $file => $attributes) { + $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); + } + return $this->_formatDir($this->_dirs); + } + + /** + * @param array + * @param array + * @param string|null + * @param array|null + * @access private + */ + function _addDir(&$dirs, $dir, $file = null, $attributes = null) + { + if ($dir == array() || $dir == array('.')) { + $dirs['files'][basename($file)] = $attributes; + return; + } + $curdir = array_shift($dir); + if (!isset($dirs['dirs'][$curdir])) { + $dirs['dirs'][$curdir] = array(); + } + $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); + } + + /** + * @param array + * @param string + * @param string + * @access private + */ + function _formatDir($dirs, $indent = '', $curdir = '') + { + $ret = ''; + if (!count($dirs)) { + return ''; + } + if (isset($dirs['dirs'])) { + uksort($dirs['dirs'], 'strnatcasecmp'); + foreach ($dirs['dirs'] as $dir => $contents) { + $usedir = "$curdir/$dir"; + $ret .= "$indent <dir name=\"$dir\">\n"; + $ret .= $this->_formatDir($contents, "$indent ", $usedir); + $ret .= "$indent </dir> <!-- $usedir -->\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 <file role=\"$attributes[role]\""; + if (isset($attributes['baseinstalldir'])) { + $ret .= ' baseinstalldir="' . + $this->_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 <replace"; + foreach ($r as $k => $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; + } + $ret .= "/>\n"; + } + $ret .= "$indent </file>\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: + * + * <pre> + * - if any install-as/platform exist, create a generic release and fill it with + * o <install as=..> tags for <file name=... install-as=...> + * o <install as=..> tags for <file name=... platform=!... install-as=..> + * o <ignore> tags for <file name=... platform=...> + * o <ignore> tags for <file name=... platform=... install-as=..> + * - create a release for each platform encountered and fill with + * o <install as..> tags for <file name=... install-as=...> + * o <install as..> tags for <file name=... platform=this platform install-as=..> + * o <install as..> tags for <file name=... platform=!other platform install-as=..> + * o <ignore> tags for <file name=... platform=!this platform> + * o <ignore> tags for <file name=... platform=other platform> + * o <ignore> tags for <file name=... platform=other platform install-as=..> + * o <ignore> tags for <file name=... platform=!this platform install-as=..> + * </pre> + * + * 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 <install as=..> tags for <file name=... install-as=...> + if (!isset($package['platform'][$file])) { + $generic[] = $file; + continue; + } + //o <install as=..> tags for <file name=... platform=!... install-as=..> + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} == '!') { + $generic[] = $file; + continue; + } + //o <ignore> tags for <file name=... platform=... install-as=..> + 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 <ignore> tags for <file name=... platform=...> + $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 <install as=..> tags for <file name=... install-as=...> + if (!isset($package['platform'][$file])) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o <install as..> tags for + // <file name=... platform=this platform install-as=..> + if (isset($package['platform'][$file]) && + $package['platform'][$file] == $os) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o <install as..> tags for + // <file name=... platform=!other platform install-as=..> + 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 <ignore> tags for + // <file name=... platform=!this platform install-as=..> + if (isset($package['platform'][$file]) && + $package['platform'][$file] == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o <ignore> tags for + // <file name=... platform=other platform install-as=..> + 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 <ignore> tags for <file name=... platform=!this platform> + if ($platform == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o <ignore> tags for <file name=... platform=other platform> + 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 + $min = array_pop($a = array_flip($min)); + } else { + $min = false; + } + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); + } else { + $max = false; + } + if ($min) { + $php['min'] = $min; + } + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; + } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + return $php; + } + + /** + * process multiple dependencies that have a name, like package deps + * @param array + * @return array + * @access private + */ + function _processMultipleDepsName($deps) + { + $tests = array(); + foreach ($deps as $name => $dep) { + foreach ($dep as $d) { + $tests[$name][] = $this->_processDep($d); + } + } + foreach ($tests as $name => $test) { + $php = array(); + $min = array(); + $max = array(); + $php['name'] = $name; + foreach ($test as $dep) { + if (!$dep) { + continue; + } + if (isset($dep['channel'])) { + $php['channel'] = 'pear.php.net'; + } + if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { + $php['conflicts'] = 'yes'; + } + if (isset($dep['min'])) { + $min[$dep['min']] = count($min); + } + if (isset($dep['max'])) { + $max[$dep['max']] = count($max); + } + } + if (count($min) > 0) { + uksort($min, 'version_compare'); + } + if (count($max) > 0) { + uksort($max, 'version_compare'); + } + if (count($min)) { + // get the highest minimum + $min = array_pop($a = array_flip($min)); + } else { + $min = false; + } + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); + } else { + $max = false; + } + if ($min) { + $php['min'] = $min; + } + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; + } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + $ret[] = $php; + } + return $ret; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/PackageFile/Generator/v2.php b/vas/rest/class/PEAR/PackageFile/Generator/v2.php new file mode 100755 index 0000000000000000000000000000000000000000..fb8d2f9774f1058a0d783a4ffe760d9cff668616 --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/Generator/v2.php @@ -0,0 +1,1531 @@ +<?php +/** + * package.xml generation class, package.xml version 2.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Stephan Schmidt (original XML_Serializer code) + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v2.php,v 1.39 2008/05/13 05:29:24 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * file/dir manipulation routines + */ +require_once 'System.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 <cellog@php.net> + * @author Stephan Schmidt (original XML_Serializer code) + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 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 PEAR_PackageFile_Generator_v2_PEAR_PackageFile_Generator_v2_XML_Util::getDoctypeDeclaration()} + 'rootName' => 'package', // name of the root tag + 'rootAttributes' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd', + ), // attributes of the root tag + 'attributesArray' => 'attribs', // all values in this key will be treated as attributes + 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray + 'beautifyFilelist' => false, + 'encoding' => 'UTF-8', + ); + + /** + * options for the serialization + * @access private + * @var array $options + */ + var $options = array(); + + /** + * 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 PEAR_PackageFile_Generator_v2(&$packagefile) + { + $this->_packagefile = &$packagefile; + } + + /** + * @return string + */ + function getPackagerVersion() + { + return '1.7.2'; + } + + /** + * @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'); + } + if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && + !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . + ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + } + 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(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && + !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . + getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); + } + if ($pkgfile = $this->_packagefile->getPackageFile()) { + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + } else { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . + 'be created from a real file'); + } + // {{{ 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"); + } else { + $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"); + } + } + } + // }}} + if ($pf1 !== null) { + $name = 'package2.xml'; + } else { + $name = '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']); + } + 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.7.2'; + 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)) { + if (isset($this->options['rootName'])) { + $tagName = $this->options['rootName']; + } else { + $tagName = 'array'; + } + + $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); + } + + // add doctype declaration + if ($this->options['addDoctype'] === true) { + $this->_serializedData = PEAR_PackageFile_Generator_v2_XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) + . $this->options['linebreak'] + . $this->_serializedData; + } + + // build xml declaration + if ($this->options['addDecl']) { + $atts = array(); + if (isset($this->options['encoding']) ) { + $encoding = $this->options['encoding']; + } else { + $encoding = null; + } + $this->_serializedData = PEAR_PackageFile_Generator_v2_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 PEAR_PackageFile_Generator_v2_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 .= ' <!-- ' . $this->_curdir . ' -->'; + 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) && (PEAR_PackageFile_Generator_v2_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 = PEAR_PackageFile_Generator_v2_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 .= ' <!-- ' . $this->_curdir . ' -->'; + 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 { + $multiline = false; + $indent = 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 ($this->options['encoding'] == 'UTF-8' && + version_compare(phpversion(), '5.0.0', 'lt')) { + $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML; + } else { + $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML; + } + $tag = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak'], $encoding); + } 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 = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities); + } + return $tag; + } +} + +// well, it's one way to do things without extra deps ... +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2002 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Stephan Schmidt <schst@php-tools.net> | +// +----------------------------------------------------------------------+ +// +// $Id: v2.php,v 1.39 2008/05/13 05:29:24 cellog Exp $ + +/** + * error code for invalid chars in XML name + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_CHARS", 51); + +/** + * error code for invalid chars in XML name + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_START", 52); + +/** + * error code for non-scalar tag content + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NON_SCALAR_CONTENT", 60); + +/** + * error code for missing tag name + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NO_TAG_NAME", 61); + +/** + * replace XML entities + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES", 1); + +/** + * embedd content in a CData Section + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_CDATA_SECTION", 2); + +/** + * do not replace entitites + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE", 0); + +/** + * replace all XML entitites + * This setting will replace <, >, ", ' and & + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML", 1); + +/** + * replace only required XML entitites + * This setting will replace <, " and & + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED", 2); + +/** + * replace HTML entitites + * @link http://www.php.net/htmlentities + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML", 3); + +/** + * replace all XML entitites, and encode from ISO-8859-1 to UTF-8 + * This setting will replace <, >, ", ' and & + */ +define("PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML", 4); + +/** + * utility class for working with XML documents + * + * customized version of XML_Util 0.6.0 + * + * @category XML + * @package PEAR + * @version 0.6.0 + * @author Stephan Schmidt <schst@php.net> + * @author Gregory Beaver <cellog@php.net> + */ +class PEAR_PackageFile_Generator_v2_XML_Util { + + /** + * return API version + * + * @access public + * @static + * @return string $version API version + */ + function apiVersion() + { + return "0.6"; + } + + /** + * replace XML entities + * + * With the optional second parameter, you may select, which + * entities should be replaced. + * + * <code> + * require_once 'XML/Util.php'; + * + * // replace XML entites: + * $string = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities("This string contains < & >."); + * </code> + * + * @access public + * @static + * @param string string where XML special chars should be replaced + * @param integer setting for entities in attribute values (one of PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML) + * @return string string with replaced chars + */ + function replaceEntities($string, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML) + { + switch ($replaceEntities) { + case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_UTF8_XML: + return strtr(utf8_encode($string),array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + break; + case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML: + return strtr($string,array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + break; + case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED: + return strtr($string,array( + '&' => '&', + '<' => '<', + '"' => '"' )); + break; + case PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML: + return htmlspecialchars($string); + break; + } + return $string; + } + + /** + * build an xml declaration + * + * <code> + * require_once 'XML/Util.php'; + * + * // get an XML declaration: + * $xmlDecl = PEAR_PackageFile_Generator_v2_XML_Util::getXMLDeclaration("1.0", "UTF-8", true); + * </code> + * + * @access public + * @static + * @param string $version xml version + * @param string $encoding character encoding + * @param boolean $standAlone document is standalone (or not) + * @return string $decl xml declaration + * @uses PEAR_PackageFile_Generator_v2_XML_Util::attributesToString() to serialize the attributes of the XML declaration + */ + function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null) + { + $attributes = array( + "version" => $version, + ); + // add encoding + if ($encoding !== null) { + $attributes["encoding"] = $encoding; + } + // add standalone, if specified + if ($standalone !== null) { + $attributes["standalone"] = $standalone ? "yes" : "no"; + } + + return sprintf("<?xml%s?>", PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($attributes, false)); + } + + /** + * build a document type declaration + * + * <code> + * require_once 'XML/Util.php'; + * + * // get a doctype declaration: + * $xmlDecl = PEAR_PackageFile_Generator_v2_XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd"); + * </code> + * + * @access public + * @static + * @param string $root name of the root tag + * @param string $uri uri of the doctype definition (or array with uri and public id) + * @param string $internalDtd internal dtd entries + * @return string $decl doctype declaration + * @since 0.2 + */ + function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) + { + if (is_array($uri)) { + $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] ); + } elseif (!empty($uri)) { + $ref = sprintf( ' SYSTEM "%s"', $uri ); + } else { + $ref = ""; + } + + if (empty($internalDtd)) { + return sprintf("<!DOCTYPE %s%s>", $root, $ref); + } else { + return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd); + } + } + + /** + * create string representation of an attribute list + * + * <code> + * require_once 'XML/Util.php'; + * + * // build an attribute string + * $att = array( + * "foo" => "bar", + * "argh" => "tomato" + * ); + * + * $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($att); + * </code> + * + * @access public + * @static + * @param array $attributes attribute array + * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities' + * @param boolean $multiline use linebreaks, if more than one attribute is given + * @param string $indent string used for indentation of multiline attributes + * @param string $linebreak string used for linebreaks of multiline attributes + * @param integer $entities setting for entities in attribute values (one of PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML_REQUIRED, PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_HTML) + * @return string string representation of the attributes + * @uses PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities() to replace XML entities in attribute values + * @todo allow sort also to be an options array + */ + function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML) + { + /** + * second parameter may be an array + */ + if (is_array($sort)) { + if (isset($sort['multiline'])) { + $multiline = $sort['multiline']; + } + if (isset($sort['indent'])) { + $indent = $sort['indent']; + } + if (isset($sort['linebreak'])) { + $multiline = $sort['linebreak']; + } + if (isset($sort['entities'])) { + $entities = $sort['entities']; + } + if (isset($sort['sort'])) { + $sort = $sort['sort']; + } else { + $sort = true; + } + } + $string = ''; + if (is_array($attributes) && !empty($attributes)) { + if ($sort) { + ksort($attributes); + } + if( !$multiline || count($attributes) == 1) { + foreach ($attributes as $key => $value) { + if ($entities != PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE) { + $value = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($value, $entities); + } + $string .= ' '.$key.'="'.$value.'"'; + } + } else { + $first = true; + foreach ($attributes as $key => $value) { + if ($entities != PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_NONE) { + $value = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($value, $entities); + } + if ($first) { + $string .= " ".$key.'="'.$value.'"'; + $first = false; + } else { + $string .= $linebreak.$indent.$key.'="'.$value.'"'; + } + } + } + } + return $string; + } + + /** + * create a tag + * + * This method will call PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray(), which + * is more flexible. + * + * <code> + * require_once 'XML/Util.php'; + * + * // create an XML tag: + * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#"); + * </code> + * + * @access public + * @static + * @param string $qname qualified tagname (including namespace) + * @param array $attributes array containg attributes + * @param mixed $content + * @param string $namespaceUri URI of the namespace + * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both + * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line + * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) + * @param string $linebreak string used for linebreaks + * @param string $encoding encoding that should be used to translate content + * @return string $string XML tag + * @see PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray() + * @uses PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray() to create the tag + */ + function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML) + { + $tag = array( + "qname" => $qname, + "attributes" => $attributes + ); + + // add tag content + if ($content !== null) { + $tag["content"] = $content; + } + + // add namespace Uri + if ($namespaceUri !== null) { + $tag["namespaceUri"] = $namespaceUri; + } + + return PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak, $encoding); + } + + /** + * create a tag from an array + * this method awaits an array in the following format + * <pre> + * array( + * "qname" => $qname // qualified name of the tag + * "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace) + * "localpart" => $localpart, // local part of the tagname (optional, if qname is specified) + * "attributes" => array(), // array containing all attributes (optional) + * "content" => $content, // tag content (optional) + * "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional) + * ) + * </pre> + * + * <code> + * require_once 'XML/Util.php'; + * + * $tag = array( + * "qname" => "foo:bar", + * "namespaceUri" => "http://foo.com", + * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), + * "content" => "I'm inside the tag", + * ); + * // creating a tag with qualified name and namespaceUri + * $string = PEAR_PackageFile_Generator_v2_XML_Util::createTagFromArray($tag); + * </code> + * + * @access public + * @static + * @param array $tag tag definition + * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both + * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line + * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) + * @param string $linebreak string used for linebreaks + * @return string $string XML tag + * @see PEAR_PackageFile_Generator_v2_XML_Util::createTag() + * @uses PEAR_PackageFile_Generator_v2_XML_Util::attributesToString() to serialize the attributes of the tag + * @uses PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName() to get local part and namespace of a qualified name + */ + function createTagFromArray($tag, $replaceEntities = PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = PEAR_PackageFile_Generator_v2_XML_Util_ENTITIES_XML) + { + if (isset($tag["content"]) && !is_scalar($tag["content"])) { + return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( "Supplied non-scalar value as tag content", PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NON_SCALAR_CONTENT ); + } + + if (!isset($tag['qname']) && !isset($tag['localPart'])) { + return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', PEAR_PackageFile_Generator_v2_XML_Util_ERROR_NO_TAG_NAME ); + } + + // if no attributes hav been set, use empty attributes + if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) { + $tag["attributes"] = array(); + } + + // qualified name is not given + if (!isset($tag["qname"])) { + // check for namespace + if (isset($tag["namespace"]) && !empty($tag["namespace"])) { + $tag["qname"] = $tag["namespace"].":".$tag["localPart"]; + } else { + $tag["qname"] = $tag["localPart"]; + } + // namespace URI is set, but no namespace + } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) { + $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName($tag["qname"]); + $tag["localPart"] = $parts["localPart"]; + if (isset($parts["namespace"])) { + $tag["namespace"] = $parts["namespace"]; + } + } + + if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) { + // is a namespace given + if (isset($tag["namespace"]) && !empty($tag["namespace"])) { + $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"]; + } else { + // define this Uri as the default namespace + $tag["attributes"]["xmlns"] = $tag["namespaceUri"]; + } + } + + // check for multiline attributes + if ($multiline === true) { + if ($indent === "_auto") { + $indent = str_repeat(" ", (strlen($tag["qname"])+2)); + } + } + + // create attribute list + $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($tag["attributes"], true, $multiline, $indent, $linebreak ); + if (!isset($tag["content"]) || (string)$tag["content"] == '') { + $tag = sprintf("<%s%s />", $tag["qname"], $attList); + } else { + if ($replaceEntities == PEAR_PackageFile_Generator_v2_XML_Util_REPLACE_ENTITIES) { + $tag["content"] = PEAR_PackageFile_Generator_v2_XML_Util::replaceEntities($tag["content"], $encoding); + } elseif ($replaceEntities == PEAR_PackageFile_Generator_v2_XML_Util_CDATA_SECTION) { + $tag["content"] = PEAR_PackageFile_Generator_v2_XML_Util::createCDataSection($tag["content"]); + } + $tag = sprintf("<%s%s>%s</%s>", $tag["qname"], $attList, $tag["content"], $tag["qname"] ); + } + return $tag; + } + + /** + * create a start element + * + * <code> + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#"); + * </code> + * + * @access public + * @static + * @param string $qname qualified tagname (including namespace) + * @param array $attributes array containg attributes + * @param string $namespaceUri URI of the namespace + * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line + * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) + * @param string $linebreak string used for linebreaks + * @return string $string XML start element + * @see PEAR_PackageFile_Generator_v2_XML_Util::createEndElement(), PEAR_PackageFile_Generator_v2_XML_Util::createTag() + */ + function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n") + { + // if no attributes hav been set, use empty attributes + if (!isset($attributes) || !is_array($attributes)) { + $attributes = array(); + } + + if ($namespaceUri != null) { + $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName($qname); + } + + // check for multiline attributes + if ($multiline === true) { + if ($indent === "_auto") { + $indent = str_repeat(" ", (strlen($qname)+2)); + } + } + + if ($namespaceUri != null) { + // is a namespace given + if (isset($parts["namespace"]) && !empty($parts["namespace"])) { + $attributes["xmlns:".$parts["namespace"]] = $namespaceUri; + } else { + // define this Uri as the default namespace + $attributes["xmlns"] = $namespaceUri; + } + } + + // create attribute list + $attList = PEAR_PackageFile_Generator_v2_XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak); + $element = sprintf("<%s%s>", $qname, $attList); + return $element; + } + + /** + * create an end element + * + * <code> + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createEndElement("myNs:myTag"); + * </code> + * + * @access public + * @static + * @param string $qname qualified tagname (including namespace) + * @return string $string XML end element + * @see PEAR_PackageFile_Generator_v2_XML_Util::createStartElement(), PEAR_PackageFile_Generator_v2_XML_Util::createTag() + */ + function createEndElement($qname) + { + $element = sprintf("</%s>", $qname); + return $element; + } + + /** + * create an XML comment + * + * <code> + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createComment("I am a comment"); + * </code> + * + * @access public + * @static + * @param string $content content of the comment + * @return string $comment XML comment + */ + function createComment($content) + { + $comment = sprintf("<!-- %s -->", $content); + return $comment; + } + + /** + * create a CData section + * + * <code> + * require_once 'XML/Util.php'; + * + * // create a CData section + * $tag = PEAR_PackageFile_Generator_v2_XML_Util::createCDataSection("I am content."); + * </code> + * + * @access public + * @static + * @param string $data data of the CData section + * @return string $string CData section with content + */ + function createCDataSection($data) + { + return sprintf("<![CDATA[%s]]>", $data); + } + + /** + * split qualified name and return namespace and local part + * + * <code> + * require_once 'XML/Util.php'; + * + * // split qualified tag + * $parts = PEAR_PackageFile_Generator_v2_XML_Util::splitQualifiedName("xslt:stylesheet"); + * </code> + * the returned array will contain two elements: + * <pre> + * array( + * "namespace" => "xslt", + * "localPart" => "stylesheet" + * ); + * </pre> + * + * @access public + * @static + * @param string $qname qualified tag name + * @param string $defaultNs default namespace (optional) + * @return array $parts array containing namespace and local part + */ + function splitQualifiedName($qname, $defaultNs = null) + { + if (strstr($qname, ':')) { + $tmp = explode(":", $qname); + return array( + "namespace" => $tmp[0], + "localPart" => $tmp[1] + ); + } + return array( + "namespace" => $defaultNs, + "localPart" => $qname + ); + } + + /** + * check, whether string is valid XML name + * + * <p>XML names are used for tagname, attribute names and various + * other, lesser known entities.</p> + * <p>An XML name may only consist of alphanumeric characters, + * dashes, undescores and periods, and has to start with a letter + * or an underscore. + * </p> + * + * <code> + * require_once 'XML/Util.php'; + * + * // verify tag name + * $result = PEAR_PackageFile_Generator_v2_XML_Util::isValidName("invalidTag?"); + * if (PEAR_PackageFile_Generator_v2_XML_Util::isError($result)) { + * print "Invalid XML name: " . $result->getMessage(); + * } + * </code> + * + * @access public + * @static + * @param string $string string that should be checked + * @return mixed $valid true, if string is a valid XML name, PEAR error otherwise + * @todo support for other charsets + */ + function isValidName($string) + { + // check for invalid chars + if (!preg_match("/^[[:alnum:]_\-.]\\z/", $string{0})) { + return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( "XML names may only start with letter or underscore", PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_START ); + } + + // check for invalid chars + if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?\\z/", $string)) { + return PEAR_PackageFile_Generator_v2_XML_Util::raiseError( "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores", PEAR_PackageFile_Generator_v2_XML_Util_ERROR_INVALID_CHARS ); + } + // XML name is valid + return true; + } + + /** + * replacement for PEAR_PackageFile_Generator_v2_XML_Util::raiseError + * + * Avoids the necessity to always require + * PEAR.php + * + * @access public + * @param string error message + * @param integer error code + * @return object PEAR_Error + */ + function raiseError($msg, $code) + { + require_once 'PEAR.php'; + return PEAR::raiseError($msg, $code); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/PackageFile/Parser/v1.php b/vas/rest/class/PEAR/PackageFile/Parser/v1.php new file mode 100755 index 0000000000000000000000000000000000000000..1134dc60357c8d8bc8640c93441ba6f91aecfdde --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/Parser/v1.php @@ -0,0 +1,465 @@ +<?php +/** + * package.xml parsing class, package.xml version 1.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v1.php,v 1.27 2008/01/03 20:55:16 cellog Exp $ + * @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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @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': + //$data = ereg_replace ('[^a-zA-Z0-9._\-]', '_', $data); + 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 ;-) + $data = $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/vas/rest/class/PEAR/PackageFile/Parser/v2.php b/vas/rest/class/PEAR/PackageFile/Parser/v2.php new file mode 100755 index 0000000000000000000000000000000000000000..7cbc5851b23e58f7614e1d0a83d672d760db9114 --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/Parser/v2.php @@ -0,0 +1,117 @@ +<?php +/** + * package.xml parsing class, package.xml version 2.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v2.php,v 1.21 2008/01/03 20:26:37 cellog Exp $ + * @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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @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, $archive = false, $class = 'PEAR_PackageFile_v2') + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; + } + $ret = new $class; + $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/vas/rest/class/PEAR/PackageFile/v1.php b/vas/rest/class/PEAR/PackageFile/v1.php new file mode 100755 index 0000000000000000000000000000000000000000..d289550737799fc15d119ad8eb0037c71513a47b --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/v1.php @@ -0,0 +1,1618 @@ +<?php +/** + * PEAR_PackageFile_v1, package.xml version 1.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v1.php,v 1.74 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'PEAR/ErrorStack.php'; + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); + +/** + * Error code used when there is no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); + +/** + * Error code when a package name is not valid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); + +/** + * Error code used when no summary is parsed + */ +define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); + +/** + * Error code for summaries that are more than 1 line + */ +define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); + +/** + * Error code used when no description is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); + +/** + * Error code used when no license is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); + +/** + * Error code used when a <version> version number is not present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); + +/** + * Error code used when a <version> 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 <dep type="php" rel="not"... is encountered (use rel="ne") + */ +define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48); + +/** + * Error code when a package.xml contains non-ISO-8859-1 characters + */ +define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49); + +/** + * Error code when a dependency is not a 'has' relation, but has no version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50); + +/** + * Error code when a package has no lead developer + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51); + +/** + * Error code when a filename begins with "." + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52); +/** + * package.xml encapsulator + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_v1 +{ + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; + + /** + * A registry object, used to access the package name validation regex for non-standard channels + * @var PEAR_Registry + * @access private + */ + var $_registry; + + /** + * An object that contains a log method that matches PEAR_Common::log's signature + * @var object + * @access private + */ + var $_logger; + + /** + * Parsed package information + * @var array + * @access private + */ + var $_packageInfo; + + /** + * path to package.xml + * @var string + * @access private + */ + var $_packageFile; + + /** + * path to package .tgz or false if this is a local/extracted package.xml + * @var string + * @access private + */ + var $_archiveFile; + + /** + * @var int + * @access private + */ + var $_isValid = 0; + + /** + * Determines whether this packagefile was initialized only with partial package info + * + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private + */ + var $_incomplete = true; + + /** + * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack + * @param string Name of Error Stack class to use. + */ + function PEAR_PackageFile_v1() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = 0; + } + + function installBinary($installer) + { + return false; + } + + function isExtension($name) + { + return false; + } + + function setConfig(&$config) + { + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } + + function setRequestedGroup() + { + // placeholder + } + + /** + * For saving in the registry. + * + * Set the last version that was installed + * @param string + */ + function setLastInstalledVersion($version) + { + $this->_packageInfo['_lastversion'] = $version; + } + + /** + * @return string|false + */ + function getLastInstalledVersion() + { + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; + } + return false; + } + + function getInstalledBinary() + { + return false; + } + + function listPostinstallScripts() + { + return false; + } + + function initPostinstallScripts() + { + return false; + } + + function setLogger(&$logger) + { + if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + } + $this->_logger = &$logger; + } + + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; + } + + function getPackageFile() + { + return isset($this->_packageFile) ? $this->_packageFile : false; + } + + function getPackageType() + { + return 'php'; + } + + function getArchiveFile() + { + return $this->_archiveFile; + } + + function packageInfo($field) + { + if (!is_string($field) || empty($field) || + !isset($this->_packageInfo[$field])) { + return false; + } + return $this->_packageInfo[$field]; + } + + function setDirtree($path) + { + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); + } + $this->_packageInfo['dirtree'][$path] = true; + } + + function getDirtree() + { + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; + } + + function resetDirtree() + { + unset($this->_packageInfo['dirtree']); + } + + function fromArray($pinfo) + { + $this->_incomplete = false; + $this->_packageInfo = $pinfo; + } + + function isIncomplete() + { + return $this->_incomplete; + } + + function getChannel() + { + return 'pear.php.net'; + } + + function getUri() + { + return false; + } + + function getTime() + { + return false; + } + + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; + } + return false; + } + + /** + * @return array + */ + function toArray() + { + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + return $this->getArray(); + } + + function getArray() + { + return $this->_packageInfo; + } + + function getName() + { + return $this->getPackage(); + } + + function getPackage() + { + if (isset($this->_packageInfo['package'])) { + return $this->_packageInfo['package']; + } + return false; + } + + /** + * WARNING - don't use this unless you know what you are doing + */ + function setRawPackage($package) + { + $this->_packageInfo['package'] = $package; + } + + function setPackage($package) + { + $this->_packageInfo['package'] = $package; + $this->_isValid = false; + } + + function getVersion() + { + if (isset($this->_packageInfo['version'])) { + return $this->_packageInfo['version']; + } + return false; + } + + function setVersion($version) + { + $this->_packageInfo['version'] = $version; + $this->_isValid = false; + } + + function clearMaintainers() + { + unset($this->_packageInfo['maintainers']); + } + + function getMaintainers() + { + if (isset($this->_packageInfo['maintainers'])) { + return $this->_packageInfo['maintainers']; + } + return false; + } + + /** + * Adds a new maintainer - no checking of duplicates is performed, use + * updatemaintainer for that purpose. + */ + function addMaintainer($role, $handle, $name, $email) + { + $this->_packageInfo['maintainers'][] = + array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); + $this->_isValid = false; + } + + function updateMaintainer($role, $handle, $name, $email) + { + $found = false; + if (!isset($this->_packageInfo['maintainers']) || + !is_array($this->_packageInfo['maintainers'])) { + return $this->addMaintainer($role, $handle, $name, $email); + } + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; + } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + } + $this->addMaintainer($role, $handle, $name, $email); + } + + function deleteMaintainer($handle) + { + $found = false; + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; + } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + return true; + } + return false; + } + + function getState() + { + if (isset($this->_packageInfo['release_state'])) { + return $this->_packageInfo['release_state']; + } + return false; + } + + function setRawState($state) + { + $this->_packageInfo['release_state'] = $state; + } + + function setState($state) + { + $this->_packageInfo['release_state'] = $state; + $this->_isValid = false; + } + + function getDate() + { + if (isset($this->_packageInfo['release_date'])) { + return $this->_packageInfo['release_date']; + } + return false; + } + + function setDate($date) + { + $this->_packageInfo['release_date'] = $date; + $this->_isValid = false; + } + + function getLicense() + { + if (isset($this->_packageInfo['release_license'])) { + return $this->_packageInfo['release_license']; + } + return false; + } + + function setLicense($date) + { + $this->_packageInfo['release_license'] = $date; + $this->_isValid = false; + } + + function getSummary() + { + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; + } + return false; + } + + function setSummary($summary) + { + $this->_packageInfo['summary'] = $summary; + $this->_isValid = false; + } + + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; + } + + function setDescription($desc) + { + $this->_packageInfo['description'] = $desc; + $this->_isValid = false; + } + + function getNotes() + { + if (isset($this->_packageInfo['release_notes'])) { + return $this->_packageInfo['release_notes']; + } + return false; + } + + function setNotes($notes) + { + $this->_packageInfo['release_notes'] = $notes; + $this->_isValid = false; + } + + function getDeps() + { + if (isset($this->_packageInfo['release_deps'])) { + return $this->_packageInfo['release_deps']; + } + return false; + } + + /** + * Reset dependencies prior to adding new ones + */ + function clearDeps() + { + unset($this->_packageInfo['release_deps']); + } + + function addPhpDep($version, $rel) + { + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'php', + 'rel' => $rel, + 'version' => $version); + } + + function addPackageDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $dep = + array('type' => 'pkg', + 'name' => $name, + 'rel' => $rel, + 'optional' => $optional); + if ($rel != 'has' && $rel != 'not') { + $dep['version'] = $version; + } + $this->_packageInfo['release_deps'][] = $dep; + } + + function addExtensionDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'ext', + 'name' => $name, + 'rel' => $rel, + 'version' => $version, + 'optional' => $optional); + } + + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setDeps($deps) + { + $this->_packageInfo['release_deps'] = $deps; + } + + function hasDeps() + { + return isset($this->_packageInfo['release_deps']) && + count($this->_packageInfo['release_deps']); + } + + function getDependencyGroup($group) + { + return false; + } + + function isCompatible($pf) + { + return false; + } + + function isSubpackageOf($p) + { + return $p->isSubpackage($this); + } + + function isSubpackage($p) + { + return false; + } + + function dependsOn($package, $channel) + { + if (strtolower($channel) != 'pear.php.net') { + return false; + } + if (!($deps = $this->getDeps())) { + return false; + } + foreach ($deps as $dep) { + if ($dep['type'] != 'pkg') { + continue; + } + if (strtolower($dep['name']) == strtolower($package)) { + return true; + } + } + return false; + } + + function getConfigureOptions() + { + if (isset($this->_packageInfo['configure_options'])) { + return $this->_packageInfo['configure_options']; + } + return false; + } + + function hasConfigureOptions() + { + return isset($this->_packageInfo['configure_options']) && + count($this->_packageInfo['configure_options']); + } + + function addConfigureOption($name, $prompt, $default = false) + { + $o = array('name' => $name, 'prompt' => $prompt); + if ($default !== false) { + $o['default'] = $default; + } + if (!isset($this->_packageInfo['configure_options'])) { + $this->_packageInfo['configure_options'] = array(); + } + $this->_packageInfo['configure_options'][] = $o; + } + + function clearConfigureOptions() + { + unset($this->_packageInfo['configure_options']); + } + + function getProvides() + { + if (isset($this->_packageInfo['provides'])) { + return $this->_packageInfo['provides']; + } + return false; + } + + function getProvidesExtension() + { + return false; + } + + function addFile($dir, $file, $attrs) + { + $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); + if ($dir == '/' || $dir == '') { + $dir = ''; + } else { + $dir .= '/'; + } + $file = $dir . $file; + $file = preg_replace('![\\/]+!', '/', $file); + $this->_packageInfo['filelist'][$file] = $attrs; + } + + function getInstallationFilelist() + { + return $this->getFilelist(); + } + + function getFilelist() + { + if (isset($this->_packageInfo['filelist'])) { + return $this->_packageInfo['filelist']; + } + return false; + } + + function setFileAttribute($file, $attr, $value) + { + $this->_packageInfo['filelist'][$file][$attr] = $value; + } + + function resetFilelist() + { + $this->_packageInfo['filelist'] = array(); + } + + function setInstalledAs($file, $path) + { + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } + + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts); + } else { + $this->_packageInfo['filelist'][$file] = $atts; + } + } + + function getChangelog() + { + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; + } + return false; + } + + function getPackagexmlVersion() + { + return '1.0'; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getValidationWarnings($purge = true) + { + return $this->_stack->getErrors($purge); + } + + // }}} + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); + $this->_isValid = false; + } + + /** + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); + } + + /** + * @param integer error code + * @access protected + */ + function _getErrorMessage() + { + return array( + PEAR_PACKAGEFILE_ERROR_NO_NAME => + 'Missing Package Name', + PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => + 'No summary found', + PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => + 'Summary should be on one line', + PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => + 'Missing description', + PEAR_PACKAGEFILE_ERROR_NO_LICENSE => + 'Missing license', + PEAR_PACKAGEFILE_ERROR_NO_VERSION => + 'No release version found', + PEAR_PACKAGEFILE_ERROR_NO_STATE => + 'No release state found', + PEAR_PACKAGEFILE_ERROR_NO_DATE => + 'No release date found', + PEAR_PACKAGEFILE_ERROR_NO_NOTES => + 'No release notes found', + PEAR_PACKAGEFILE_ERROR_NO_LEAD => + 'Package must have at least one lead maintainer', + PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => + 'No maintainers found, at least one must be defined', + PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => + 'Maintainer %index% has no handle (user ID at channel server)', + PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => + 'Maintainer %index% has no role', + PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => + 'Maintainer %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => + 'Maintainer %index% has no email', + PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => + 'Dependency %index% is not a php dependency, and has no name', + PEAR_PACKAGEFILE_ERROR_NO_DEPREL => + 'Dependency %index% has no relation (rel)', + PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => + 'Dependency %index% has no type', + PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => + 'PHP Dependency %index% has a name attribute of "%name%" which will be' . + ' ignored!', + PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => + 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => + 'Dependency %index% is a type="php" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => + 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', + PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => + 'Dependency %index% has invalid optional value "%opt%", should be yes or no', + PEAR_PACKAGEFILE_PHP_NO_NOT => + 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . + ' to exclude specific versions', + PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => + 'Configure Option %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => + 'Configure Option %index% has no prompt', + PEAR_PACKAGEFILE_ERROR_NO_FILES => + 'No files in <filelist> section of package.xml', + PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => + 'File "%file%" has no role, expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => + 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => + 'File "%file%" cannot start with ".", cannot package or install', + PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => + 'Parser error: invalid PHP found in file "%file%"', + PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => + 'in %file%: %type% "%name%" not prefixed with package name "%package%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILE => + 'Parser error: invalid PHP file "%file%"', + PEAR_PACKAGEFILE_ERROR_CHANNELVAL => + 'Channel validator error: field "%field%" - %reason%', + PEAR_PACKAGEFILE_ERROR_PHP5 => + 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', + PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => + 'File "%file%" in package.xml does not exist', + PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => + 'Package.xml contains non-ISO-8859-1 characters, and may not validate', + ); + } + + /** + * Validate XML package definition file. + * + * @access public + * @return boolean + */ + function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) + { + if (($this->_isValid & $state) == $state) { + return true; + } + $this->_isValid = true; + $info = $this->_packageInfo; + if (empty($info['package'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); + $this->_packageName = $pn = 'unknown'; + } else { + $this->_packageName = $pn = $info['package']; + } + + if (empty($info['summary'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); + } + if (empty($info['description'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); + } + if (empty($info['release_license'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); + } + if (empty($info['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); + } + if (empty($info['release_state'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); + } + if (empty($info['release_date'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); + } + if (empty($info['release_notes'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); + } + if (empty($info['maintainers'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); + } else { + $haslead = false; + $i = 1; + foreach ($info['maintainers'] as $m) { + if (empty($m['handle'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, + array('index' => $i)); + } + if (empty($m['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, + array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); + } elseif ($m['role'] == 'lead') { + $haslead = true; + } + if (empty($m['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, + array('index' => $i)); + } + if (empty($m['email'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, + array('index' => $i)); + } + $i++; + } + if (!$haslead) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); + } + } + if (!empty($info['release_deps'])) { + $i = 1; + foreach ($info['release_deps'] as $d) { + if (!isset($d['type']) || empty($d['type'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, + array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); + continue; + } + if (!isset($d['rel']) || empty($d['rel'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, + array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); + continue; + } + if (!empty($d['optional'])) { + if (!in_array($d['optional'], array('yes', 'no'))) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, + array('index' => $i, 'opt' => $d['optional'])); + } + } + if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, + array('index' => $i)); + } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, + array('index' => $i, 'rel' => $d['rel'])); + } + if ($d['type'] == 'php' && !empty($d['name'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, + array('index' => $i, 'name' => $d['name'])); + } elseif ($d['type'] != 'php' && empty($d['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, + array('index' => $i)); + } + if ($d['type'] == 'php' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, + array('index' => $i)); + } + if (($d['rel'] == 'not') && ($d['type'] == 'php')) { + $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, + array('index' => $i)); + } + $i++; + } + } + if (!empty($info['configure_options'])) { + $i = 1; + foreach ($info['configure_options'] as $c) { + if (empty($c['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, + array('index' => $i)); + } + if (empty($c['prompt'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, + array('index' => $i)); + } + $i++; + } + } + if (empty($info['filelist'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); + $errors[] = 'no files'; + } else { + foreach ($info['filelist'] as $file => $fa) { + if (empty($fa['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, + array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); + continue; + } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, + array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { + // file contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file)); + } + if (isset($fa['install-as']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['install-as']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); + } + if (isset($fa['baseinstalldir']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['baseinstalldir']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); + } + } + } + if (isset($this->_registry) && $this->_isValid) { + $chan = $this->_registry->getChannel('pear.php.net'); + if (PEAR::isError($chan)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); + return $this->_isValid = 0; + } + $validator = $chan->getValidationObject(); + $validator->setPackageFile($this); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); + } + foreach ($failures['warnings'] as $warning) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); + } + } + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { + if ($this->_analyzePhpFiles()) { + $this->_isValid = true; + } + } + if ($this->_isValid) { + return $this->_isValid = $state; + } + return $this->_isValid = 0; + } + + function _analyzePhpFiles() + { + if (!$this->_isValid) { + return false; + } + if (!isset($this->_packageFile)) { + return false; + } + $dir_prefix = dirname($this->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_logger) ? array(&$this->_logger, 'log') : + array($common, 'log'); + $info = $this->getFilelist(); + foreach ($info as $file => $fa) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, + array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); + continue; + } + if ($fa['role'] == 'php' && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $this->_buildProvidesArray($srcinfo); + } + } + } + $this->_packageName = $pn = $this->getPackage(); + $pnl = strlen($pn); + if (isset($this->_packageInfo['provides'])) { + foreach ((array) $this->_packageInfo['provides'] as $key => $what) { + if (isset($what['explicit'])) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } + } + } + return $this->_isValid; + } + + /** + * Get the default xml generator object + * + * @return PEAR_PackageFile_Generator_v1 + */ + function &getDefaultGenerator() + { + if (!class_exists('PEAR_PackageFile_Generator_v1')) { + require_once 'PEAR/PackageFile/Generator/v1.php'; + } + $a = &new PEAR_PackageFile_Generator_v1($this); + return $a; + } + + /** + * Get the contents of a file listed within the package.xml + * @param string + * @return string + */ + function getFileContents($file) + { + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); + } + } else { // tgz + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; + } + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); + } + return $file; + } + } + + // {{{ analyzeSourceCode() + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access private + */ + function _analyzeSourceCode($file) + { + if (!function_exists("token_get_all")) { + return false; + } + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); + } + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + if (!$fp = @fopen($file, "r")) { + return false; + } + fclose($fp); + $contents = file_get_contents($file); + $tokens = token_get_all($contents); +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; + continue; + } + } + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; + } + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, + array($file)); + } + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + continue 2; + } + } + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); + } + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private + * + */ + function _buildProvidesArray($srcinfo) + { + if (!$this->_isValid) { + return false; + } + $file = basename($srcinfo['source_file']); + $pn = $this->getPackage(); + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->_packageInfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { + continue; + } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + // }}} +} +?> diff --git a/vas/rest/class/PEAR/PackageFile/v2.php b/vas/rest/class/PEAR/PackageFile/v2.php new file mode 100755 index 0000000000000000000000000000000000000000..4638a77f13a1b04d22d8b6b92def70db0780c8d7 --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/v2.php @@ -0,0 +1,2046 @@ +<?php +/** + * PEAR_PackageFile_v2, package.xml version 2.0 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: v2.php,v 1.143 2008/05/13 05:28:51 cellog Exp $ + * @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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 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 PEAR_PackageFile_v2() + { + $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); + $this->_isValid = false; + } + + /** + * To make unit-testing easier + * @param PEAR_Frontend_* + * @param array options + * @param PEAR_Config + * @return PEAR_Downloader + * @access protected + */ + function &getPEARDownloader(&$i, $o, &$c) + { + $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 <contents>'); + } + + /** + * 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']); + if (!$res) { + continue; // skip this file + } + if (PEAR::isError($res)) { + return $res; + } + $assign = &$task; + $this->_scripts[] = &$assign; + } + } + if (count($this->_scripts)) { + return true; + } + return false; + } + + function runPostinstallScripts() + { + if ($this->initPostinstallScripts()) { + $ui = &PEAR_Frontend::singleton(); + if ($ui) { + $ui->runPostinstallScripts($this->_scripts, $this); + } + } + } + + + /** + * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with + * <file> 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']); + $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 <usesrole> tag contents, if any + * @return array|false + */ + function getUsesrole() + { + if (isset($this->_packageInfo['usesrole'])) { + return $this->_packageInfo['usesrole']; + } + return false; + } + + /** + * Return the <usestask> 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) { + $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 <exclude> 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 <dependencies> 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 <tasks:mycustom-task> + * + * 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: + * <pre> + * array( + * tagname => array(list of tag names that follow this one), + * childtagname => array(list of child tag names that follow this one), + * ) + * </pre> + * + * 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/vas/rest/class/PEAR/PackageFile/v2/Validator.php b/vas/rest/class/PEAR/PackageFile/v2/Validator.php new file mode 100755 index 0000000000000000000000000000000000000000..10efbbb6ab539a22e694e0c70abc01e3181ca7ca --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/v2/Validator.php @@ -0,0 +1,2116 @@ +<?php +/** + * PEAR_PackageFile_v2, package.xml version 2.0, read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Validator.php,v 1.106 2008/03/28 22:23:41 dufuz Exp $ + * @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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 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']) && + version_compare('1.7.2', + $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, '<package>')) { + 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_merge( + array('channel' => $chan->getName(), + 'package' => $this->_pf->getPackage()), + $valpack + ), + 'package "%channel%/%package%" cannot be properly validated without ' . + 'validation package "%channel%/%name%-%version%"'); + return $this->_isValid = 0; + } + $validator->setPackageFile($this->_pf); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_stack->push(__FUNCTION__, 'error', $error, + 'Channel validator error: field "%field%" - %reason%'); + } + foreach ($failures['warnings'] as $warning) { + $this->_stack->push(__FUNCTION__, 'warning', $warning, + 'Channel validator warning: field "%field%" - %reason%'); + } + } + } + $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'], '<version>'); + $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<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 ? '<installcondition><php>' : '<dependencies><required><php>'; + $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 . '<min>', $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 . '<max>', $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>', $exclude); + } + } + } + } + + function _validatePearinstallerDep($dep) + { + $structure = array( + 'min', + '*max', + '*recommended', + '*exclude', + ); + $this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>'); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('<dependencies><required><pearinstaller><min>', + $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('<dependencies><required><pearinstaller><max>', + $dep['max']); + } + } + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>', + $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('<dependencies><required><pearinstaller><exclude>', + $exclude); + } + } + } + } + + function _validatePackageDep($dep, $group, $type = '<package>') + { + 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 .= '<name>' . $dep['name'] . '</name>'; + } + $this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type); + if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || + isset($dep['recommended']) || isset($dep['exclude']))) { + $this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type); + } + if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { + $this->_DepchannelCannotBeUri('<dependencies>' . $group . $type); + } + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']); + } + } + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>', + $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('<dependencies>' . $group . $type . '<exclude>', + $exclude); + } + } + } + } + + function _validateSubpackageDep($dep, $group) + { + $this->_validatePackageDep($dep, $group, '<subpackage>'); + 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 = '<installcondition><extension>'; + } else { + $type = '<dependencies>' . $group . '<extension>'; + } + if (isset($dep['name'])) { + $type .= '<name>' . $dep['name'] . '</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) . '<min', $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']); + } + } + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion(substr($type, 1) . '<recommended', $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(substr($type, 1) . '<exclude', $exclude); + } + } + } + } + + function _validateOsDep($dep, $installcondition = false) + { + $structure = array( + 'name', + '*conflicts', + ); + $type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>'; + 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 ? '<installcondition><arch>' : '<dependencies><required><arch>'; + $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'], '<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], + "<dependencies><$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, '<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, '<group name="' . + $group['attribs']['name'] . '">'); + } + } + } + } + } + } + } + + 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 = '<compatible>'; + if (is_array($package) && array_key_exists('name', $package)) { + $type .= '<name>' . $package['name'] . '</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) . '<min', $package['min']); + } + } + if (is_array($package) && array_key_exists('max', $package)) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $package['max'])) { + $this->_invalidVersion(substr($type, 1) . '<max', $package['max']); + } + } + if (is_array($package) && array_key_exists('exclude', $package)) { + if (!is_array($package['exclude'])) { + $package['exclude'] = array($package['exclude']); + } + foreach ($package['exclude'] as $exclude) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $exclude)) { + $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude); + } + } + } + } + } + + function _validateBundle($list) + { + if (!is_array($list) || !isset($list['bundledpackage'])) { + return $this->_NoBundledPackages(); + } + if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { + return $this->_AtLeast2BundledPackages(); + } + foreach ($list['bundledpackage'] as $package) { + if (!is_string($package)) { + $this->_bundledPackagesMustBeFilename(); + } + } + } + + 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 ? '<filelist>' : '<dir name="*unknown*">'; + $dirname = $iscontents ? '<contents>' : $unknown; + } else { + $dirname = '<dir name="' . $list['attribs']['name'] . '">'; + 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, '<phprelease>'); + } + } + 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, '<bundle>'); + } + } + foreach ($releases as $rel) { + if (is_array($rel) && array_key_exists('installconditions', $rel)) { + $this->_validateInstallConditions($rel['installconditions'], + "<$release><installconditions>"); + } + 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.7.2'); + } + + 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 <contents>, only inside ' . + '<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only'); + } + + function _fileNotAllowed($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '<%type%> is not allowed inside release <filelist>, only inside ' . + '<contents>, use <ignore> and <install> only'); + } + + function _oldStyleFileNotAllowed() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Old-style <file>name</file> is not allowed. Use' . + '<file name="name" role="role"/>'); + } + + 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%" <install as="%as%"/> 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 <dir>, contains <file>. Use ' . + '<dir name="/"> as the first dir element'); + } + + function _filelistMustContainDir($filelist) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), + '<%tag%> must contain <dir>. Use <dir name="/"> 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 <package> tag has no version attribute, or version is not 2.0'); + } + + function _NoBundledPackages() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'No <bundledpackage> tag was found in <contents>, 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 <file name="%file%">'); + } + + function _subpackageCannotProvideExtension($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use <providesextension>, ' . + 'only package dependencies can use this tag'); + } + + function _subpackagesCannotConflict($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use <conflicts/>, ' . + 'only package dependencies can use this tag'); + } + + function _cannotProvideExtension($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages cannot use <providesextension>, 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 <providesextension> 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 <srcpackage> tag'); + } + + function _mustSrcPackage($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>'); + } + + function _mustSrcuri($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>'); + } + + function _uriDepsCannotHaveVersioning($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: dependencies with a <uri> 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 <exclude> 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(), + '<bundledpackage> tags must contain only the filename of a package release ' . + 'in the bundle'); + } + + function _binaryPackageMustBePackagename() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + '<binarypackage> 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 <contents>'); + } + + 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 <uri>, or <channel> and <package>'); + } + + function _usesroletaskMustHavePackage($role, $tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), + '<%tag%> for role "%role%" must contain <package>'); + } + + 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 <dir> tags are not allowed. Enclose them ' . + 'in a <dir name="/">'); + } + + function _multipleInstallAs($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Only one <install> tag is allowed for file "%file%"'); + } + + function _ignoreAndInstallAs($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Cannot have both <ignore> and <install> 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><dir'); + return false; + } + $info = $info['dir']['file']; + if (isset($info['attribs'])) { + $info = array($info); + } + $provides = array(); + foreach ($info as $fa) { + $fa = $fa['attribs']; + $file = $fa['name']; + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { + $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); + $this->_isValid = 0; + continue; + } + if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); + } + } + } + $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)) { + $pn = $this->_pf->getPackage(); + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'package' => $pn), + 'in %file%: Could not process file for unkown reasons,' . + ' possibly a PHP parse error in %file% from %package%'); + + } +/* + 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->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Parser error: invalid PHP found in file "%file%"'); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + $this->_stack->push(__FUNCTION__, 'warning', array( + 'file' => $file), + 'Error, PHP5 token encountered in %file%,' . + ' analysis should be in PHP5'); + } + } + 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->_stack->push(__FUNCTION__, 'warning', array('file' => $file), + 'Parser error: invalid PHP found in 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 array(); + } + $providesret = array(); + $file = basename($srcinfo['source_file']); + $pn = $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; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/PackageFile/v2/rw.php b/vas/rest/class/PEAR/PackageFile/v2/rw.php new file mode 100755 index 0000000000000000000000000000000000000000..383042bd75db0edbcc6d5660a884ccf62eed3f89 --- /dev/null +++ b/vas/rest/class/PEAR/PackageFile/v2/rw.php @@ -0,0 +1,1603 @@ +<?php +/** + * PEAR_PackageFile_v2, package.xml version 2.0, read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: rw.php,v 1.22 2008/01/18 22:47:49 cellog Exp $ + * @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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 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 ($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 <usesrole> 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 <usestask> 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 <contents> 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 <contents> 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/vas/rest/class/PEAR/Packager.php b/vas/rest/class/PEAR/Packager.php new file mode 100755 index 0000000000000000000000000000000000000000..bae9282311b788106b311e788d5ca82109494cc1 --- /dev/null +++ b/vas/rest/class/PEAR/Packager.php @@ -0,0 +1,199 @@ +<?php +/** + * PEAR_Packager for generating releases + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Packager.php,v 1.71 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; +require_once 'System.php'; + +/** + * Administration class used to make a PEAR release tarball. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Packager extends PEAR_Common +{ + /** + * @var PEAR_Registry + */ + var $_registry; + // {{{ package() + + 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"); + } else { + 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"); + } else { + 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"); + } else { + 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"); + } else { + 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)"); + } + } 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)"); + } + } + return $dest_package; + } + + // }}} +} + +// {{{ md5_file() utility function +if (!function_exists('md5_file')) { + function md5_file($file) { + if (!$fd = @fopen($file, 'r')) { + return false; + } + fclose($fd); + $md5 = md5(file_get_contents($file)); + return $md5; + } +} +// }}} + +?> diff --git a/vas/rest/class/PEAR/REST.php b/vas/rest/class/PEAR/REST.php new file mode 100755 index 0000000000000000000000000000000000000000..c32946c60f880065e0239009a991d82cf3d79a8d --- /dev/null +++ b/vas/rest/class/PEAR/REST.php @@ -0,0 +1,397 @@ +<?php +/** + * PEAR_REST + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: REST.php,v 1.31 2008/05/13 18:03:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * For downloading xml files + */ +require_once 'PEAR.php'; +require_once 'PEAR/XMLParser.php'; + +/** + * Intelligently retrieve data, following hyperlinks if necessary, and re-directing + * as well + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_REST +{ + var $config; + var $_options; + function PEAR_REST(&$config, $options = array()) + { + $this->config = &$config; + $this->_options = $options; + } + + /** + * Retrieve REST data, but always retrieve the local cache if it is available. + * + * This is useful for elements that should never change, such as information on a particular + * release + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + if (file_exists($cachefile)) { + return unserialize(implode('', file($cachefile))); + } + return $this->retrieveData($url, $accept, $forcestring, $channel); + } + + /** + * Retrieve a remote REST resource + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveData($url, $accept = false, $forcestring = false, $channel = false) + { + $cacheId = $this->getCacheId($url); + if ($ret = $this->useLocalCache($url, $cacheId)) { + return $ret; + } + if (!isset($this->_options['offline'])) { + $trieddownload = true; + $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); + } else { + $trieddownload = false; + $file = false; + } + if (PEAR::isError($file)) { + if ($file->getCode() == -9276) { + $trieddownload = false; + $file = false; // use local copy if available on socket connect error + } else { + return $file; + } + } + if (!$file) { + $ret = $this->getCache($url); + if (!PEAR::isError($ret) && $trieddownload) { + // reset the age of the cache if the server says it was unmodified + $this->saveCache($url, $ret, null, true, $cacheId); + } + return $ret; + } + if (is_array($file)) { + $headers = $file[2]; + $lastmodified = $file[1]; + $content = $file[0]; + } else { + $content = $file; + $lastmodified = false; + $headers = array(); + } + if ($forcestring) { + $this->saveCache($url, $content, $lastmodified, false, $cacheId); + return $content; + } + if (isset($headers['content-type'])) { + switch ($headers['content-type']) { + case 'text/xml' : + case 'application/xml' : + $parser = new PEAR_XMLParser; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $parser->parse($content); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . + $err->getMessage()); + } + $content = $parser->getData(); + case 'text/html' : + default : + // use it as a string + } + } else { + // assume XML + $parser = new PEAR_XMLParser; + $parser->parse($content); + $content = $parser->getData(); + } + $this->saveCache($url, $content, $lastmodified, false, $cacheId); + return $content; + } + + function useLocalCache($url, $cacheid = null) + { + if ($cacheid === null) { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + if (file_exists($cacheidfile)) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } else { + return false; + } + } + $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)) { + $ret = unserialize(implode('', file($cacheidfile))); + return $ret; + } else { + return false; + } + } + + function getCache($url) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + if (file_exists($cachefile)) { + return unserialize(implode('', file($cachefile))); + } else { + return PEAR::raiseError('No cached content available for "' . $url . '"'); + } + } + + /** + * @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) + { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + if ($cacheid === null && $nochange) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } + + $fp = @fopen($cacheidfile, 'wb'); + if (!$fp) { + $cache_dir = $this->config->get('cache_dir'); + if (!is_dir($cache_dir)) { + System::mkdir(array('-p', $cache_dir)); + $fp = @fopen($cacheidfile, 'wb'); + if (!$fp) { + return false; + } + } else { + return false; + } + } + + if ($nochange) { + fwrite($fp, serialize(array( + 'age' => time(), + 'lastChange' => $cacheid['lastChange'], + ))); + fclose($fp); + return true; + } else { + fwrite($fp, serialize(array( + 'age' => time(), + 'lastChange' => $lastmodified, + ))); + } + fclose($fp); + $fp = @fopen($cachefile, 'wb'); + if (!$fp) { + if (file_exists($cacheidfile)) { + @unlink($cacheidfile); + } + return false; + } + fwrite($fp, serialize($contents)); + fclose($fp); + return true; + } + + /** + * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory + * This is best used for small files + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param string $save_dir directory to save file in + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @return string|array Returns the contents of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public + */ + function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) + { + $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 . '"'); + } else { + $host = $info['host']; + if (!array_key_exists('port', $info)) { + $info['port'] = null; + } + if (!array_key_exists('path', $info)) { + $info['path'] = null; + } + $port = $info['port']; + $path = $info['path']; + } + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($this->config->get('http_proxy')&& + $proxy = parse_url($this->config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'ssl://' . $proxy_host; + } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + } + if (empty($port)) { + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $port = 443; + } else { + $port = 80; + } + } + If (isset($proxy['host'])) { + $request = "GET $url HTTP/1.1\r\n"; + } else { + $request = "GET $path HTTP/1.1\r\n"; + } + $request .= "Host: $host:$port\r\n"; + + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } + } else { + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); + } + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.7.2/PHP/" . PHP_VERSION . "\r\n"; + $username = $this->config->get('username', null, $channel); + $password = $this->config->get('password', null, $channel); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } + $request .= "Accept-Encoding:\r\n"; + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); + if (!$fp) { + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", + -9276); + } + } else { + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $host = 'ssl://' . $host; + } + $fp = @fsockopen($host, $port, $errno, $errstr); + if (!$fp) { + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + } + fwrite($fp, $request); + $headers = array(); + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + if ($matches[1] == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } + if ($matches[1] != 200) { + return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)", (int) $matches[1]); + } + } + } + if (isset($headers['content-length'])) { + $length = $headers['content-length']; + } else { + $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/vas/rest/class/PEAR/REST/10.php b/vas/rest/class/PEAR/REST/10.php new file mode 100755 index 0000000000000000000000000000000000000000..d2f44fe93098da9afc5f8942c311e59456be619a --- /dev/null +++ b/vas/rest/class/PEAR/REST/10.php @@ -0,0 +1,797 @@ +<?php +/** + * PEAR_REST_10 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: 10.php,v 1.53 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a12 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; + +/** + * Implement REST 1.0 + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a12 + */ +class PEAR_REST_10 +{ + /** + * @var PEAR_REST + */ + var $_rest; + function PEAR_REST_10($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: + * <pre> + * array( + * 'package' => 'packagename', + * 'channel' => 'channelname', + * ['state' => 'alpha' (or valid state),] + * -or- + * ['version' => '1.whatever'] + * </pre> + * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} + */ + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + { + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', 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) + { + $channel = $dependency['channel']; + $package = $dependency['name']; + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); + } + 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]; + } + $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . strtolower($package) . '/' . + 'info.xml', false, false, $channel); + if (PEAR::isError($pinfo)) { + return PEAR::raiseError('Package "' . $package . + '" does not have REST info xml available'); + } + $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + $release['v'] . '.xml', false, false, $channel); + if (PEAR::isError($releaseinfo)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST xml available'); + } + $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + 'deps.' . $release['v'] . '.txt', false, true, $channel); + if (PEAR::isError($packagexml)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST dependency information available'); + } + $packagexml = unserialize($packagexml); + if (!$packagexml) { + $packagexml = array(); + } + $allinfo = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { + $allinfo['r'] = array($allinfo['r']); + } + $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; + } + 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 ($found) { + return + array('version' => $releaseinfo['v'], + 'info' => $packagexml, + 'package' => $releaseinfo['p']['_content'], + 'stability' => $releaseinfo['st'], + 'url' => $releaseinfo['g'], + 'compatible' => $compatible, + 'deprecated' => $deprecated, + ); + } else { + return + array('version' => $releaseinfo['v'], + 'package' => $releaseinfo['p']['_content'], + 'stability' => $releaseinfo['st'], + 'info' => $packagexml, + 'compatible' => $compatible, + 'deprecated' => $deprecated, + 'php' => $phpversion + ); + } + } + + function listPackages($base, $channel = false) + { + $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%', false); + } + $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; + } + $found = false; + $release = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + // $info['r'] is sorted by version number + 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 . '" (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; + } + 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); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/REST/11.php b/vas/rest/class/PEAR/REST/11.php new file mode 100755 index 0000000000000000000000000000000000000000..effa68904f26e5601ef7b42f0b2db49345237070 --- /dev/null +++ b/vas/rest/class/PEAR/REST/11.php @@ -0,0 +1,317 @@ +<?php +/** + * PEAR_REST_11 - implement faster list-all/remote-list command + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: 11.php,v 1.14 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.3 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; + +/** + * Implement REST 1.1 + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.3 + */ +class PEAR_REST_11 +{ + /** + * @var PEAR_REST + */ + var $_rest; + + function PEAR_REST_11($config, $options = array()) + { + $this->_rest = &new PEAR_REST($config, $options); + } + + function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) + { + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; + } + $ret = array(); + if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) { + $categorylist['c'] = array($categorylist['c']); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + + foreach ($categorylist['c'] as $progress => $category) { + $category = $category['_content']; + $packagesinfo = $this->_rest->retrieveData($base . + 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel); + + if (PEAR::isError($packagesinfo)) { + continue; + } + + if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) { + continue; + } + + if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) { + $packagesinfo['pi'] = array($packagesinfo['pi']); + } + + foreach ($packagesinfo['pi'] as $packageinfo) { + $info = $packageinfo['p']; + $package = $info['n']; + $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false; + unset($latest); + unset($unstable); + unset($stable); + unset($state); + + if ($releases) { + if (!isset($releases['r'][0])) { + $releases['r'] = array($releases['r']); + } + foreach ($releases['r'] as $release) { + if (!isset($latest)) { + if ($dostable && $release['s'] == 'stable') { + $latest = $release['v']; + $state = 'stable'; + } + if (!$dostable) { + $latest = $release['v']; + $state = $release['s']; + } + } + if (!isset($stable) && $release['s'] == 'stable') { + $stable = $release['v']; + if (!isset($unstable)) { + $unstable = $stable; + } + } + if (!isset($unstable) && $release['s'] != 'stable') { + $unstable = $release['v']; + $state = $release['s']; + } + if (isset($latest) && !isset($state)) { + $state = $release['s']; + } + if (isset($latest) && isset($stable) && isset($unstable)) { + break; + } + } + } + + if ($basic) { // remote-list command + if (!isset($latest)) { + $latest = false; + } + if ($dostable) { + // $state is not set if there are no releases + if (isset($state) && $state == 'stable') { + $ret[$package] = array('stable' => $latest); + } else { + $ret[$package] = array('stable' => '-n/a-'); + } + } else { + $ret[$package] = array('stable' => $latest); + } + continue; + } + + // list-all command + $deps = array(); + if (!isset($unstable)) { + $unstable = false; + $state = 'stable'; + if (isset($stable)) { + $latest = $unstable = $stable; + } + } else { + $latest = $unstable; + } + + if (!isset($latest)) { + $latest = false; + } + + if ($latest && isset($packageinfo['deps'])) { + if (!is_array($packageinfo['deps']) || + !isset($packageinfo['deps'][0])) { + $packageinfo['deps'] = array($packageinfo['deps']); + } + $d = false; + foreach ($packageinfo['deps'] as $dep) { + if ($dep['v'] == $latest) { + $d = unserialize($dep['d']); + } + } + if ($d) { + if (isset($d['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + if (!isset($pf)) { + $pf = new PEAR_PackageFile_v2; + } + $pf->setDeps($d); + $tdeps = $pf->getDeps(); + } else { + $tdeps = $d; + } + foreach ($tdeps as $dep) { + if ($dep['type'] !== 'pkg') { + continue; + } + $deps[] = $dep; + } + } + } + + $info = array('stable' => $latest, 'summary' => $info['s'], + 'description' => + $info['d'], 'deps' => $deps, 'category' => $info['ca']['_content'], + 'unstable' => $unstable, 'state' => $state); + $ret[$package] = $info; + } + } + PEAR::popErrorHandling(); + return $ret; + } + + /** + * List all categories of a REST server + * + * @param string $base base URL of the server + * @return array of categorynames + */ + function listCategories($base, $channel = false) + { + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; + } + if (!is_array($categorylist) || !isset($categorylist['c'])) { + return array(); + } + if (isset($categorylist['c']['_content'])) { + // only 1 category + $categorylist['c'] = array($categorylist['c']); + } + return $categorylist['c']; + } + + /** + * List packages in a category of a REST server + * + * @param string $base base URL of the server + * @param string $category name of the category + * @param boolean $info also download full package info + * @return array of packagenames + */ + function listCategory($base, $category, $info = false, $channel = false) + { + if ($info == false) { + $url = '%s'.'c/%s/packages.xml'; + } else { + $url = '%s'.'c/%s/packagesinfo.xml'; + } + $url = sprintf($url, + $base, + urlencode($category)); + + // gives '404 Not Found' error when category doesn't exist + $packagelist = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + if (!is_array($packagelist)) { + return array(); + } + + if ($info == false) { + if (!isset($packagelist['p'])) { + return array(); + } + if (!is_array($packagelist['p']) || + !isset($packagelist['p'][0])) { // only 1 pkg + $packagelist = array($packagelist['p']); + } else { + $packagelist = $packagelist['p']; + } + return $packagelist; + } else { + // info == true + if (!isset($packagelist['pi'])) { + return array(); + } + if (!is_array($packagelist['pi']) || + !isset($packagelist['pi'][0])) { // only 1 pkg + $packagelist_pre = array($packagelist['pi']); + } else { + $packagelist_pre = $packagelist['pi']; + } + + $packagelist = array(); + foreach ($packagelist_pre as $i => $item) { + // compatibility with r/<latest.txt>.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); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/REST/13.php b/vas/rest/class/PEAR/REST/13.php new file mode 100755 index 0000000000000000000000000000000000000000..875fd390715d5203db6a017c6f2b997b433f8051 --- /dev/null +++ b/vas/rest/class/PEAR/REST/13.php @@ -0,0 +1,280 @@ +<?php +/** + * PEAR_REST_13 + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: 13.php,v 1.6 2008/04/11 01:16:40 dufuz Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a12 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; +require_once 'PEAR/REST/10.php'; + +/** + * Implement REST 1.3 + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 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: + * <pre> + * array( + * 'package' => 'packagename', + * 'channel' => 'channelname', + * ['state' => 'alpha' (or valid state),] + * -or- + * ['version' => '1.whatever'] + * </pre> + * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} + */ + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + { + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases2.xml'); + if (PEAR::isError($info)) { + return PEAR::raiseError('No releases available for package "' . + $channel . '/' . $package . '"'); + } + if (!isset($info['r'])) { + return false; + } + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + $skippedphp = false; + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + if (isset($state)) { + // try our preferred state first + if ($release['s'] == $state) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + // see if there is something newer and more stable + // bug #7221 + if (in_array($release['s'], $this->betterStates($state), true)) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } elseif (isset($version)) { + if ($release['v'] == $version) { + if (!isset($this->_rest->_options['force']) && + !isset($version) && + version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } else { + if (in_array($release['s'], $states)) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } + } + if (!$found && $skippedphp) { + $found = null; + } + return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); + } + + function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, + $prefstate = 'stable', $installed = false, $channel = false) + { + $channel = $dependency['channel']; + $package = $dependency['name']; + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases2.xml'); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); + } + if (!is_array($info) || !isset($info['r'])) { + return false; + } + $exclude = array(); + $min = $max = $recommended = false; + if ($xsdversion == '1.0') { + $pinfo['package'] = $dependency['name']; + $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this + switch ($dependency['rel']) { + case 'ge' : + $min = $dependency['version']; + break; + case 'gt' : + $min = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'eq' : + $recommended = $dependency['version']; + break; + case 'lt' : + $max = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'le' : + $max = $dependency['version']; + break; + case 'ne' : + $exclude = array($dependency['version']); + break; + } + } else { + $pinfo['package'] = $dependency['name']; + $min = isset($dependency['min']) ? $dependency['min'] : false; + $max = isset($dependency['max']) ? $dependency['max'] : false; + $recommended = isset($dependency['recommended']) ? + $dependency['recommended'] : false; + if (isset($dependency['exclude'])) { + if (!isset($dependency['exclude'][0])) { + $exclude = array($dependency['exclude']); + } + } + } + $found = false; + $release = false; + $skippedphp = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + if (in_array($release['v'], $exclude)) { // skip excluded versions + continue; + } + // allow newer releases to say "I'm OK with the dependent package" + if ($xsdversion == '2.0' && isset($release['co'])) { + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + foreach ($release['co'] as $entry) { + if (isset($entry['x']) && !is_array($entry['x'])) { + $entry['x'] = array($entry['x']); + } elseif (!isset($entry['x'])) { + $entry['x'] = array(); + } + if ($entry['c'] == $deppackage['channel'] && + strtolower($entry['p']) == strtolower($deppackage['package']) && + version_compare($deppackage['version'], $entry['min'], '>=') && + version_compare($deppackage['version'], $entry['max'], '<=') && + !in_array($release['v'], $entry['x'])) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip dependency releases that require a PHP version + // newer than our PHP version + $skippedphp = $release; + continue; + } + $recommended = $release['v']; + break; + } + } + } + if ($recommended) { + if ($release['v'] != $recommended) { // if we want a specific + // version, then skip all others + continue; + } 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... + 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); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Registry.php b/vas/rest/class/PEAR/Registry.php new file mode 100755 index 0000000000000000000000000000000000000000..556366d307321c1a2d7ef90ba663eb78b64ca11c --- /dev/null +++ b/vas/rest/class/PEAR/Registry.php @@ -0,0 +1,2236 @@ +<?php +/** + * PEAR_Registry + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Registry.php,v 1.171 2008/05/14 04:16:08 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * for PEAR_Error + */ +require_once 'PEAR.php'; +require_once 'PEAR/DependencyDB.php'; + +define('PEAR_REGISTRY_ERROR_LOCK', -2); +define('PEAR_REGISTRY_ERROR_FORMAT', -3); +define('PEAR_REGISTRY_ERROR_FILE', -4); +define('PEAR_REGISTRY_ERROR_CONFLICT', -5); +define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); + +/** + * Administration class used to maintain the installed package database. + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Registry extends PEAR +{ + // {{{ properties + + /** + * 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 PEAR_DependencyDB + */ + var $_dependencyDB; + + /** + * @var PEAR_Config + */ + var $_config; + // }}} + + // {{{ constructor + + /** + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * + * @access public + */ + function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, + $pecl_channel = false) + { + parent::PEAR(); + $this->setInstallDir($pear_install_dir); + $this->_pearChannel = $pear_channel; + $this->_peclChannel = $pecl_channel; + $this->_config = false; + } + + function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) + { + $ds = DIRECTORY_SEPARATOR; + $this->install_dir = $pear_install_dir; + $this->channelsdir = $pear_install_dir.$ds.'.channels'; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + } + + function hasWriteAccess() + { + if (!file_exists($this->install_dir)) { + $dir = $this->install_dir; + while ($dir && $dir != '.') { + $olddir = $dir; + $dir = dirname($dir); // cd .. + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } else { + return false; + } + } + if ($dir == $olddir) { // this can happen in safe mode + return @is_writable($dir); + } + } + return false; + } + return is_writeable($this->install_dir); + } + + function setConfig(&$config, $resetInstallDir = true) + { + $this->_config = &$config; + if ($resetInstallDir) { + $this->setInstallDir($config->get('php_dir')); + } + } + + function _initializeChannelDirs() + { + static $running = false; + if (!$running) { + $running = true; + $ds = DIRECTORY_SEPARATOR; + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $pear_channel = $this->_pearChannel; + if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setName('pear.php.net'); + $pear_channel->setAlias('pear'); + $pear_channel->setServer('pear.php.net'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + } else { + $pear_channel->setName('pear.php.net'); + $pear_channel->setAlias('pear'); + } + $pear_channel->validate(); + $this->_addChannel($pear_channel); + } + if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { + $pecl_channel = $this->_peclChannel; + if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pecl_channel = new PEAR_ChannelFile; + $pecl_channel->setName('pecl.php.net'); + $pecl_channel->setAlias('pecl'); + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setSummary('PHP Extension Community Library'); + $pecl_channel->setDefaultPEARProtocols(); + $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + } else { + $pecl_channel->setName('pecl.php.net'); + $pecl_channel->setAlias('pecl'); + } + $pecl_channel->validate(); + $this->_addChannel($pecl_channel); + } + if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->addFunction('xmlrpc', '1.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? + if (OS_WINDOWS) { + $file = 'pear.ini'; + } else { + $file = '.pearrc'; + } + $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . + $file); + $this->_config->setRegistry($this); + $this->_config->set('php_dir', $this->install_dir); + } + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + // attempt to recover by removing the dep db + if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb')) { + @unlink($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'); + } + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + echo $this->_dependencyDB->getMessage(); + echo 'Unrecoverable error'; + exit(1); + } + } + $initializing = false; + } + } + } + // }}} + // {{{ destructor + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } + } + + // }}} + + // {{{ _assertStateDir() + + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertStateDir($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 . '__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; + } + + // }}} + // {{{ _assertChannelStateDir() + + /** + * 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; + } + + // }}} + // {{{ _assertChannelDir() + + /** + * 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; + } + + // }}} + // {{{ _packageFileName() + + /** + * 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'; + } + + // }}} + // {{{ _channelFileName() + + /** + * 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'; + } + + // }}} + // {{{ getChannelAliasFileName() + + /** + * @param string + * @return string + */ + function _getChannelAliasFileName($alias) + { + return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . + DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; + } + + // }}} + // {{{ _getChannelFromAlias() + + /** + * 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 == '__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))); + } else { + return $channel; + } + } + // }}} + // {{{ _getChannelFromAlias() + + /** + * 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'; + } + return false; + } + $channel = $this->_getChannel($channel); + if (PEAR::isError($channel)) { + return $channel; + } + return $channel->getAlias(); + } + // }}} + // {{{ _channelDirectoryName() + + /** + * 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; + } else { + $ch = $this->_getChannelFromAlias($channel); + if (!$ch) { + $ch = $channel; + } + return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . + str_replace('/', '_', $ch)); + } + } + + // }}} + // {{{ _openPackageFile() + + 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; + } + + // }}} + // {{{ _closePackageFile() + + function _closePackageFile($fp) + { + fclose($fp); + } + + // }}} + // {{{ _openChannelFile() + + 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; + } + + // }}} + // {{{ _closePackageFile() + + function _closeChannelFile($fp) + { + fclose($fp); + } + + // }}} + // {{{ _rebuildFileMap() + + 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; + } + + // }}} + // {{{ _readFileMap() + + function _readFileMap() + { + if (!file_exists($this->filemap)) { + return array(); + } + $fp = @fopen($this->filemap, 'r'); + if (!$fp) { + return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); + } + clearstatcache(); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $fsize = filesize($this->filemap); + fclose($fp); + $data = file_get_contents($this->filemap); + set_magic_quotes_runtime($rt); + $tmp = unserialize($data); + if (!$tmp && $fsize > 7) { + return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); + } + $this->filemap_cache = $tmp; + return true; + } + + // }}} + // {{{ _lock() + + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (!eregi('Windows 9', php_uname())) { + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + if (!$this->_assertStateDir()) { + if ($mode == LOCK_EX) { + return $this->raiseError('Registry directory is not writeable by the current user'); + } else { + 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; + } + + // }}} + // {{{ _unlock() + + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->lock_fp)) { + fclose($this->lock_fp); + } + $this->lock_fp = null; + return $ret; + } + + // }}} + // {{{ _packageExists() + + function _packageExists($package, $channel = false) + { + return file_exists($this->_packageFileName($package, $channel)); + } + + // }}} + // {{{ _channelExists() + + /** + * 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; + } + return $a; + } + + // }}} + // {{{ _addChannel() + + /** + * @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'))) { + return false; + } + } + $ret = $this->_assertChannelDir(); + if (PEAR::isError($ret)) { + return $ret; + } + $ret = $this->_assertChannelStateDir($channel->getName()); + if (PEAR::isError($ret)) { + return $ret; + } + if ($channel->getAlias() != $channel->getName()) { + if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && + $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { + $channel->setAlias($channel->getName()); + } + if (!$this->hasWriteAccess()) { + return false; + } + $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); + if (!$fp) { + return false; + } + fwrite($fp, $channel->getName()); + fclose($fp); + } + if (!$this->hasWriteAccess()) { + return false; + } + $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); + if (!$fp) { + return false; + } + $info = $channel->toArray(); + if ($lastmodified) { + $info['_lastmodified'] = $lastmodified; + } else { + $info['_lastmodified'] = date('r'); + } + fwrite($fp, serialize($info)); + fclose($fp); + return true; + } + + // }}} + // {{{ _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 (!is_string($channel)) { + if (is_a($channel, 'PEAR_ChannelFile')) { + if (!$channel->validate()) { + return false; + } + $channel = $channel->getName(); + } else { + return false; + } + } + if ($this->_getChannelFromAlias($channel) == '__uri') { + return false; + } + if ($this->_getChannelFromAlias($channel) == 'pecl.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; + } + + // }}} + // {{{ _isChannelAlias() + + /** + * Determine whether a channel exists in the registry + * @param string Channel Alias + * @return boolean + */ + function _isChannelAlias($alias) + { + return file_exists($this->_getChannelAliasFileName($alias)); + } + + // }}} + // {{{ _packageInfo() + + /** + * @param string|null + * @param string|null + * @param string|null + * @return array|null + * @access private + */ + function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if ($package === null) { + if ($channel === null) { + $channels = $this->_listChannels(); + $ret = array(); + foreach ($channels as $channel) { + $channel = strtolower($channel); + $ret[$channel] = array(); + $packages = $this->_listPackages($channel); + foreach ($packages as $package) { + $ret[$channel][] = $this->_packageInfo($package, null, $channel); + } + } + return $ret; + } + $ps = $this->_listPackages($channel); + if (!count($ps)) { + return array(); + } + return array_map(array(&$this, '_packageInfo'), + $ps, array_fill(0, count($ps), null), + array_fill(0, count($ps), $channel)); + } + $fp = $this->_openPackageFile($package, 'r', $channel); + if ($fp === null) { + return null; + } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closePackageFile($fp); + $data = file_get_contents($this->_packageFileName($package, $channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + if ($key === null) { + return $data; + } + // compatibility for package.xml version 2.0 + if (isset($data['old'][$key])) { + return $data['old'][$key]; + } + if (isset($data[$key])) { + return $data[$key]; + } + return null; + } + + // }}} + // {{{ _channelInfo() + + /** + * @param string Channel name + * @param bool whether to strictly retrieve info of channels, not just aliases + * @return array|null + */ + function _channelInfo($channel, $noaliases = false) + { + if (!$this->_channelExists($channel, $noaliases)) { + return null; + } + $fp = $this->_openChannelFile($channel, 'r'); + if ($fp === null) { + return null; + } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closeChannelFile($fp); + $data = file_get_contents($this->_channelFileName($channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + return $data; + } + + // }}} + // {{{ _listChannels() + + function _listChannels() + { + $channellist = array(); + if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { + return array('pear.php.net', 'pecl.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('__uri', $channellist)) { + $channellist[] = '__uri'; + } + + natsort($channellist); + return $channellist; + } + + // }}} + // {{{ _listPackages() + + 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; + } + + // }}} + // {{{ _listChannelPackages() + + function _listChannelPackages($channel) + { + $pkglist = array(); + if (!file_exists($this->_channelDirectoryName($channel)) || + !is_dir($this->_channelDirectoryName($channel))) { + return array(); + } + $dp = opendir($this->_channelDirectoryName($channel)); + if (!$dp) { + return $pkglist; + } + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + closedir($dp); + return $pkglist; + } + + // }}} + + function _listAllPackages() + { + $ret = array(); + foreach ($this->_listChannels() as $channel) { + $ret[$channel] = $this->_listPackages($channel); + } + return $ret; + } + + /** + * Add an installed package to the registry + * @param string package name + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + * @access private + */ + function _addPackage($package, $info) + { + if ($this->_packageExists($package)) { + return false; + } + $fp = $this->_openPackageFile($package, 'wb'); + if ($fp === null) { + return false; + } + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); + } + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _addPackage2($info) + { + if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { + return false; + } + + if (!$info->validate()) { + if (class_exists('PEAR_Common')) { + $ui = PEAR_Frontend::singleton(); + if ($ui) { + foreach ($info->getValidationWarnings() as $err) { + $ui->log($err['message'], true); + } + } + } + return false; + } + $channel = $info->getChannel(); + $package = $info->getPackage(); + $save = $info; + if ($this->_packageExists($package, $channel)) { + return false; + } + if (!$this->_channelExists($channel, true)) { + return false; + } + $info = $info->toArray(true); + if (!$info) { + return false; + } + $fp = $this->_openPackageFile($package, 'wb', $channel); + if ($fp === null) { + return false; + } + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param array parsed package.xml 1.0 + * @param bool this parameter is only here for BC. Don't use it. + * @access private + */ + function _updatePackage($package, $info, $merge = true) + { + $oldinfo = $this->_packageInfo($package); + if (empty($oldinfo)) { + return false; + } + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + return false; + } + if (is_object($info)) { + $info = $info->toArray(); + } + $info['_lastmodified'] = time(); + $newinfo = $info; + if ($merge) { + $info = array_merge($oldinfo, $info); + } else { + $diff = $info; + } + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($newinfo['filelist'])) { + $this->_rebuildFileMap(); + } + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _updatePackage2($info) + { + if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { + return false; + } + $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); + if ($fp === null) { + return false; + } + $save = $info; + $info = $save->getArray(true); + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param string Channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + * @access private + */ + function &_getPackage($package, $channel = 'pear.php.net') + { + $info = $this->_packageInfo($package, null, $channel); + if ($info === null) { + return $info; + } + $a = $this->_config; + if (!$a) { + $this->_config = &new PEAR_Config; + $this->_config->set('php_dir', $this->statedir); + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $pkg = &new PEAR_PackageFile($this->_config); + $pf = &$pkg->fromArray($info); + return $pf; + } + + /** + * @param string channel name + * @param bool whether to strictly retrieve channel names + * @return PEAR_ChannelFile|PEAR_Error + * @access private + */ + function &_getChannel($channel, $noaliases = false) + { + $ch = false; + if ($this->_channelExists($channel, $noaliases)) { + $chinfo = $this->_channelInfo($channel, $noaliases); + if ($chinfo) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); + } + } + if ($ch) { + if ($ch->validate()) { + return $ch; + } + foreach ($ch->getErrors(true) as $err) { + $message = $err['message'] . "\n"; + } + $ch = PEAR::raiseError($message); + return $ch; + } + if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setName('pear.php.net'); + $pear_channel->setAlias('pear'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + return $pear_channel; + } + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setName('pecl.php.net'); + $pear_channel->setAlias('pecl'); + $pear_channel->setSummary('PHP Extension Community Library'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + return $pear_channel; + } + if ($this->_getChannelFromAlias($channel) == '__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->addFunction('xmlrpc', '1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + return $private; + } + return $ch; + } + + // {{{ packageExists() + + /** + * @param string Package name + * @param string Channel name + * @return bool + */ + function packageExists($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + + // {{{ channelExists() + + /** + * @param string channel name + * @param bool if true, then aliases will be ignored + * @return bool + */ + function channelExists($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelExists($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + // {{{ isAlias() + + /** + * Determines whether the parameter is an alias of a channel + * @param string + * @return bool + */ + function isAlias($alias) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_isChannelAlias($alias); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + /** + * @param string|null + * @param string|null + * @param string + * @return array|null + */ + function packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ channelInfo() + + /** + * Retrieve a raw array of channel data. + * + * Do not use this, instead use {@link getChannel()} for normal + * operations. Array structure is undefined in this method + * @param string channel name + * @param bool whether to strictly retrieve information only on non-aliases + * @return array|null|PEAR_Error + */ + function channelInfo($channel = null, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelInfo($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + /** + * @param string + */ + function channelName($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getChannelFromAlias($channel); + $this->_unlock(); + return $ret; + } + + /** + * @param string + */ + function channelAlias($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getAlias($channel); + $this->_unlock(); + return $ret; + } + // {{{ listPackages() + + function listPackages($channel = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages($channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listAllPackages() + + function listAllPackages() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listAllPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listChannel() + + function listChannels() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listChannels(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + /** + * Add an installed package to the registry + * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object + * that will be passed to {@link addPackage2()} + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + */ + function addPackage($package, $info) + { + if (is_object($info)) { + return $this->addPackage2($info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage($package, $info); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($info); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ addPackage2() + + function addPackage2($info) + { + if (!is_object($info)) { + return $this->addPackage($info['package'], $info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + return $ret; + } + + // }}} + // {{{ updateChannel() + + /** + * For future expandibility purposes, separate this + * @param PEAR_ChannelFile + */ + function updateChannel($channel, $lastmodified = null) + { + if ($channel->getName() == '__uri') { + return false; + } + return $this->addChannel($channel, $lastmodified, true); + } + + // }}} + // {{{ deleteChannel() + + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function deleteChannel($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_deleteChannel($channel); + $this->_unlock(); + if ($ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + return $ret; + } + + // }}} + // {{{ addChannel() + + /** + * @param PEAR_ChannelFile Channel object + * @param string Last-Modified header from HTTP for caching + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function addChannel($channel, $lastmodified = false, $update = false) + { + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; + } + if (!$channel->validate()) { + return false; + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addChannel($channel, $update, $lastmodified); + $this->_unlock(); + if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + return $ret; + } + + // }}} + // {{{ deletePackage() + + function deletePackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $file = $this->_packageFileName($package, $channel); + if (file_exists($file)) { + $ret = @unlink($file); + } else { + $ret = false; + } + $this->_rebuildFileMap(); + $this->_unlock(); + $p = array('channel' => $channel, 'package' => $package); + $this->_dependencyDB->uninstallPackage($p); + return $ret; + } + + // }}} + // {{{ updatePackage() + + function updatePackage($package, $info, $merge = true) + { + if (is_object($info)) { + return $this->updatePackage2($info, $merge); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_updatePackage($package, $info, $merge); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($this->packageInfo($package)); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ updatePackage2() + + function updatePackage2($info) + { + if (!is_object($info)) { + return $this->updatePackage($info['package'], $info, $merge); + } + if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { + return false; + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_updatePackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + return $ret; + } + + // }}} + // {{{ getChannel() + /** + * @param string channel name + * @param bool whether to strictly return raw channels (no aliases) + * @return PEAR_ChannelFile|PEAR_Error + */ + function &getChannel($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = &$this->_getChannel($channel, $noaliases); + $this->_unlock(); + if (!$ret) { + return PEAR::raiseError('Unknown channel: ' . $channel); + } + return $ret; + } + + // }}} + // {{{ getPackage() + /** + * @param string package name + * @param string channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + */ + function &getPackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $pf = &$this->_getPackage($package, $channel); + $this->_unlock(); + return $pf; + } + + // }}} + + /** + * Get PEAR_PackageFile_v[1/2] objects representing the contents of + * a dependency group that are installed. + * + * This is used at uninstall-time + * @param array + * @return array|false + */ + function getInstalledGroup($group) + { + $ret = array(); + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } + foreach ($group['package'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } + foreach ($group['subpackage'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (!count($ret)) { + return false; + } + return $ret; + } + + // {{{ getChannelValidator() + /** + * @param string channel name + * @return PEAR_Validate|false + */ + function &getChannelValidator($channel) + { + $chan = $this->getChannel($channel); + if (PEAR::isError($chan)) { + return $chan; + } + $val = $chan->getValidationObject(); + return $val; + } + // }}} + // {{{ getChannels() + /** + * @param string channel name + * @return array an array of PEAR_ChannelFile objects representing every installed channel + */ + function &getChannels() + { + $ret = array(); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + foreach ($this->_listChannels() as $channel) { + $e = &$this->_getChannel($channel); + if (!$e || PEAR::isError($e)) { + continue; + } + $ret[] = $e; + } + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ checkFileMap() + + /** + * Test whether a file or set of files belongs to a package. + * + * If an array is passed in + * @param string|array file path, absolute or relative to the pear + * install dir + * @param string|array name of PEAR package or array('package' => name, 'channel' => + * channel) of a package that will be ignored + * @param string API version - 1.1 will exclude any files belonging to a package + * @param array private recursion variable + * @return array|false which package and channel the file belongs to, or an empty + * string if the file does not belong to an installed package, + * or belongs to the second parameter's package + */ + function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) + { + if (is_array($path)) { + static $notempty; + if (empty($notempty)) { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'PEAR/Installer/Role.php'; + } + $notempty = create_function('$a','return !empty($a);'); + } + $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) + : strtolower($package); + $pkgs = array(); + foreach ($path as $name => $attrs) { + if (is_array($attrs)) { + if (isset($attrs['install-as'])) { + $name = $attrs['install-as']; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; + } + if (isset($attrs['baseinstalldir'])) { + $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; + } + } + $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); + if (PEAR::isError($pkgs[$name])) { + return $pkgs[$name]; + } + } + return array_filter($pkgs, $notempty); + } + if (empty($this->filemap_cache)) { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $err = $this->_readFileMap(); + $this->_unlock(); + if (PEAR::isError($err)) { + return $err; + } + } + if (!$attrs) { + $attrs = array('role' => 'php'); // any old call would be for PHP role only + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + $l = strlen($this->install_dir); + if (substr($path, 0, $l) == $this->install_dir) { + $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + return false; + } + + // }}} + // {{{ flush() + /** + * Force a reload of the filemap + * @since 1.5.0RC3 + */ + function flushFileMap() + { + $this->filemap_cache = null; + clearstatcache(); // ensure that the next read gets the full, current filemap + } + + // }}} + // {{{ apiVersion() + /** + * Get the expected API version. Channels API is version 1.1, as it is backwards + * compatible with 1.0 + * @return string + */ + function apiVersion() + { + return '1.1'; + } + // }}} + + + /** + * Parse a package name, or validate a parsed package name array + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',] + * ['group' => 'groupname']) + * or a string of format + * [channel://][channame/]pname[-version|-state][/group=groupname] + * @return array|PEAR_Error + */ + function parsePackageName($param, $defaultchannel = 'pear.php.net') + { + $saveparam = $param; + if (is_array($param)) { + // convert to string for error messages + $saveparam = $this->parsedPackageNameToString($param); + // process the array + if (!isset($param['package'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in index "param"', + 'package', null, null, $param); + } + if (!isset($param['uri'])) { + if (!isset($param['channel'])) { + $param['channel'] = $defaultchannel; + } + } else { + $param['channel'] = '__uri'; + } + } else { + $components = @parse_url((string) $param); + if (isset($components['scheme'])) { + if ($components['scheme'] == 'http') { + // uri package + $param = array('uri' => $param, 'channel' => '__uri'); + } elseif($components['scheme'] != 'channel') { + return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . + 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); + } + } + if (!isset($components['path'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in "' . $param . '"', + 'package', null, null, $param); + } + if (isset($components['host'])) { + // remove the leading "/" + $components['path'] = substr($components['path'], 1); + } + if (!isset($components['scheme'])) { + if (strpos($components['path'], '/') !== false) { + if ($components['path']{0} == '/') { + return PEAR::raiseError('parsePackageName(): this is not ' . + 'a package name, it begins with "/" in "' . $param . '"', + 'invalid', null, null, $param); + } + $parts = explode('/', $components['path']); + $components['host'] = array_shift($parts); + if (count($parts) > 1) { + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } else { + $components['path'] = implode('/', $parts); + } + } else { + $components['host'] = $defaultchannel; + } + } else { + if (strpos($components['path'], '/')) { + $parts = explode('/', $components['path']); + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } + } + + if (is_array($param)) { + $param['package'] = $components['path']; + } else { + $param = array( + 'package' => $components['path'] + ); + if (isset($components['host'])) { + $param['channel'] = $components['host']; + } + } + if (isset($components['fragment'])) { + $param['group'] = $components['fragment']; + } + if (isset($components['user'])) { + $param['user'] = $components['user']; + } + if (isset($components['pass'])) { + $param['pass'] = $components['pass']; + } + if (isset($components['query'])) { + parse_str($components['query'], $param['opts']); + } + // check for extension + $pathinfo = pathinfo($param['package']); + if (isset($pathinfo['extension']) && + in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { + $param['extension'] = $pathinfo['extension']; + $param['package'] = substr($pathinfo['basename'], 0, + strlen($pathinfo['basename']) - 4); + } + // check for version + if (strpos($param['package'], '-')) { + $test = explode('-', $param['package']); + if (count($test) != 2) { + return PEAR::raiseError('parsePackageName(): only one version/state ' . + 'delimiter "-" is allowed in "' . $saveparam . '"', + 'version', null, null, $param); + } + list($param['package'], $param['version']) = $test; + } + } + // validation + $info = $this->channelExists($param['channel']); + if (PEAR::isError($info)) { + return $info; + } + if (!$info) { + return PEAR::raiseError('unknown channel "' . $param['channel'] . + '" in "' . $saveparam . '"', 'channel', null, null, $param); + } + $chan = $this->getChannel($param['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + if (!$chan) { + return PEAR::raiseError("Exception: corrupt registry, could not " . + "retrieve channel " . $param['channel'] . " information", + 'registry', null, null, $param); + } + $param['channel'] = $chan->getName(); + $validate = $chan->getValidationObject(); + $vpackage = $chan->getValidationPackage(); + // validate package name + if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { + return PEAR::raiseError('parsePackageName(): invalid package name "' . + $param['package'] . '" in "' . $saveparam . '"', + 'package', null, null, $param); + } + if (isset($param['group'])) { + if (!PEAR_Validate::validGroupName($param['group'])) { + return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . + '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, + $param); + } + } + if (isset($param['state'])) { + if (!in_array(strtolower($param['state']), $validate->getValidStates())) { + return PEAR::raiseError('parsePackageName(): state "' . $param['state'] + . '" is not a valid state in "' . $saveparam . '"', + 'state', null, null, $param); + } + } + if (isset($param['version'])) { + if (isset($param['state'])) { + return PEAR::raiseError('parsePackageName(): cannot contain both ' . + 'a version and a stability (state) in "' . $saveparam . '"', + 'version/state', null, null, $param); + } + // check whether version is actually a state + if (in_array(strtolower($param['version']), $validate->getValidStates())) { + $param['state'] = strtolower($param['version']); + unset($param['version']); + } else { + if (!$validate->validVersion($param['version'])) { + return PEAR::raiseError('parsePackageName(): "' . $param['version'] . + '" is neither a valid version nor a valid state in "' . + $saveparam . '"', 'version/state', null, null, $param); + } + } + } + return $param; + } + + /** + * @param array + * @return string + */ + function parsedPackageNameToString($parsed, $brief = false) + { + if (is_string($parsed)) { + return $parsed; + } + if (is_object($parsed)) { + $p = $parsed; + $parsed = array( + 'package' => $p->getPackage(), + 'channel' => $p->getChannel(), + 'version' => $p->getVersion(), + ); + } + if (isset($parsed['uri'])) { + return $parsed['uri']; + } + if ($brief) { + if ($channel = $this->channelAlias($parsed['channel'])) { + return $channel . '/' . $parsed['package']; + } + } + $upass = ''; + if (isset($parsed['user'])) { + $upass = $parsed['user']; + if (isset($parsed['pass'])) { + $upass .= ':' . $parsed['pass']; + } + $upass = "$upass@"; + } + $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; + if (isset($parsed['version']) || isset($parsed['state'])) { + $ver = isset($parsed['version']) ? $parsed['version'] : ''; + $ver .= isset($parsed['state']) ? $parsed['state'] : ''; + $ret .= '-' . $ver; + } + if (isset($parsed['extension'])) { + $ret .= '.' . $parsed['extension']; + } + if (isset($parsed['opts'])) { + $ret .= '?'; + foreach ($parsed['opts'] as $name => $value) { + $parsed['opts'][$name] = "$name=$value"; + } + $ret .= implode('&', $parsed['opts']); + } + if (isset($parsed['group'])) { + $ret .= '#' . $parsed['group']; + } + return $ret; + } +} + +?> diff --git a/vas/rest/class/PEAR/Remote.php b/vas/rest/class/PEAR/Remote.php new file mode 100755 index 0000000000000000000000000000000000000000..09ddb997a3ae83ce44e079efd9f4c74706d61e8a --- /dev/null +++ b/vas/rest/class/PEAR/Remote.php @@ -0,0 +1,498 @@ +<?php +/** + * PEAR_Remote + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Remote.php,v 1.80 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * needed for PEAR_Error + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +/** + * This is a class for doing remote operations against the central + * PEAR database. + * + * @nodep XML_RPC_Value + * @nodep XML_RPC_Message + * @nodep XML_RPC_Client + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Remote extends PEAR +{ + // {{{ properties + + var $config = null; + var $cache = null; + /** + * @var PEAR_Registry + * @access private + */ + var $_registry; + + // }}} + + // {{{ PEAR_Remote(config_object) + + function PEAR_Remote(&$config) + { + $this->PEAR(); + $this->config = &$config; + $this->_registry = &$this->config->getRegistry(); + } + + // }}} + // {{{ setRegistry() + + function setRegistry(&$reg) + { + $this->_registry = &$reg; + } + // }}} + // {{{ getCache() + + + function getCache($args) + { + $id = md5(serialize($args)); + $cachedir = $this->config->get('cache_dir'); + $filename = $cachedir . DIRECTORY_SEPARATOR . 'xmlrpc_cache_' . $id; + if (!file_exists($filename)) { + return null; + } + + $fp = fopen($filename, 'rb'); + if (!$fp) { + return null; + } + fclose($fp); + $content = file_get_contents($filename); + $result = array( + 'age' => time() - filemtime($filename), + 'lastChange' => filemtime($filename), + 'content' => unserialize($content), + ); + return $result; + } + + // }}} + + // {{{ saveCache() + + function saveCache($args, $data) + { + $id = md5(serialize($args)); + $cachedir = $this->config->get('cache_dir'); + if (!file_exists($cachedir)) { + System::mkdir(array('-p', $cachedir)); + } + $filename = $cachedir.'/xmlrpc_cache_'.$id; + + $fp = @fopen($filename, "wb"); + if ($fp) { + fwrite($fp, serialize($data)); + fclose($fp); + } + } + + // }}} + + // {{{ clearCache() + + function clearCache($method, $args) + { + array_unshift($args, $method); + array_unshift($args, $this->config->get('default_channel')); // cache by channel + $id = md5(serialize($args)); + $cachedir = $this->config->get('cache_dir'); + $filename = $cachedir.'/xmlrpc_cache_'.$id; + if (file_exists($filename)) { + @unlink($filename); + } + } + + // }}} + // {{{ call(method, [args...]) + + function call($method) + { + $_args = $args = func_get_args(); + + $server_channel = $this->config->get('default_channel'); + $channel = $this->_registry->getChannel($server_channel); + if (!PEAR::isError($channel)) { + $mirror = $this->config->get('preferred_mirror'); + if ($channel->getMirror($mirror)) { + if ($channel->supports('xmlrpc', $method, $mirror)) { + $server_channel = $server_host = $mirror; // use the preferred mirror + $server_port = $channel->getPort($mirror); + } elseif (!$channel->supports('xmlrpc', $method)) { + return $this->raiseError("Channel $server_channel does not " . + "support xml-rpc method $method"); + } + } + if (!isset($server_host)) { + if (!$channel->supports('xmlrpc', $method)) { + return $this->raiseError("Channel $server_channel does not support " . + "xml-rpc method $method"); + } else { + $server_host = $server_channel; + $server_port = $channel->getPort(); + } + } + } else { + return $this->raiseError("Unknown channel '$server_channel'"); + } + + array_unshift($_args, $server_channel); // cache by channel + $this->cache = $this->getCache($_args); + $cachettl = $this->config->get('cache_ttl'); + // If cache is newer than $cachettl seconds, we use the cache! + if ($this->cache !== null && $this->cache['age'] < $cachettl) { + return $this->cache['content']; + } + $fp = false; + if (extension_loaded("xmlrpc")) { + $result = call_user_func_array(array(&$this, 'call_epi'), $args); + if (!PEAR::isError($result)) { + $this->saveCache($_args, $result); + } + return $result; + } elseif (!($fp = fopen('XML/RPC.php', 'r', true))) { + return $this->raiseError("For this remote PEAR operation you need to load the xmlrpc extension or install XML_RPC"); + } + include_once 'XML/RPC.php'; + if ($fp) { + fclose($fp); + } + + array_shift($args); + $username = $this->config->get('username'); + $password = $this->config->get('password'); + $eargs = array(); + foreach($args as $arg) { + $eargs[] = $this->_encode($arg); + } + $f = new XML_RPC_Message($method, $eargs); + if ($this->cache !== null) { + $maxAge = '?maxAge='.$this->cache['lastChange']; + } else { + $maxAge = ''; + } + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($proxy = parse_url($this->config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'https://' . $proxy_host; + } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + } + $shost = $server_host; + if ($channel->getSSL()) { + $shost = "https://$shost"; + } + $c = new XML_RPC_Client('/' . $channel->getPath('xmlrpc') + . $maxAge, $shost, $server_port, $proxy_host, $proxy_port, + $proxy_user, $proxy_pass); + if ($username && $password) { + $c->setCredentials($username, $password); + } + if ($this->config->get('verbose') >= 3) { + $c->setDebug(1); + } + $r = $c->send($f); + if (!$r) { + return $this->raiseError("XML_RPC send failed"); + } + $v = $r->value(); + if ($e = $r->faultCode()) { + if ($e == $GLOBALS['XML_RPC_err']['http_error'] && strstr($r->faultString(), '304 Not Modified') !== false) { + return $this->cache['content']; + } + return $this->raiseError($r->faultString(), $e); + } + + $result = XML_RPC_decode($v); + $this->saveCache($_args, $result); + return $result; + } + + // }}} + + // {{{ call_epi(method, [args...]) + + function call_epi($method) + { + if (!extension_loaded("xmlrpc")) { + return $this->raiseError("xmlrpc extension is not loaded"); + } + $server_channel = $this->config->get('default_channel'); + $channel = $this->_registry->getChannel($server_channel); + if (!PEAR::isError($channel)) { + $mirror = $this->config->get('preferred_mirror'); + if ($channel->getMirror($mirror)) { + if ($channel->supports('xmlrpc', $method, $mirror)) { + $server_channel = $server_host = $mirror; // use the preferred mirror + $server_port = $channel->getPort($mirror); + } elseif (!$channel->supports('xmlrpc', $method)) { + return $this->raiseError("Channel $server_channel does not " . + "support xml-rpc method $method"); + } + } + if (!isset($server_host)) { + if (!$channel->supports('xmlrpc', $method)) { + return $this->raiseError("Channel $server_channel does not support " . + "xml-rpc method $method"); + } else { + $server_host = $server_channel; + $server_port = $channel->getPort(); + } + } + } else { + return $this->raiseError("Unknown channel '$server_channel'"); + } + $params = func_get_args(); + array_shift($params); + $method = str_replace("_", ".", $method); + $request = xmlrpc_encode_request($method, $params); + if ($http_proxy = $this->config->get('http_proxy')) { + $proxy = parse_url($http_proxy); + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'https://' . $proxy_host; + } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : null; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + $fp = @fsockopen($proxy_host, $proxy_port); + $use_proxy = true; + if ($channel->getSSL()) { + $server_host = "https://$server_host"; + } + } else { + $use_proxy = false; + $ssl = $channel->getSSL(); + $fp = @fsockopen(($ssl ? 'ssl://' : '') . $server_host, $server_port); + if (!$fp) { + $server_host = "$ssl$server_host"; // for error-reporting + } + } + if (!$fp && $http_proxy) { + return $this->raiseError("PEAR_Remote::call: fsockopen(`$proxy_host', $proxy_port) failed"); + } elseif (!$fp) { + return $this->raiseError("PEAR_Remote::call: fsockopen(`$server_host', $server_port) failed"); + } + $len = strlen($request); + $req_headers = "Host: $server_host:$server_port\r\n" . + "Content-type: text/xml\r\n" . + "Content-length: $len\r\n"; + $username = $this->config->get('username'); + $password = $this->config->get('password'); + if ($username && $password) { + $req_headers .= "Cookie: PEAR_USER=$username; PEAR_PW=$password\r\n"; + $tmp = base64_encode("$username:$password"); + $req_headers .= "Authorization: Basic $tmp\r\n"; + } + if ($this->cache !== null) { + $maxAge = '?maxAge='.$this->cache['lastChange']; + } else { + $maxAge = ''; + } + + if ($use_proxy && $proxy_host != '' && $proxy_user != '') { + $req_headers .= 'Proxy-Authorization: Basic ' + .base64_encode($proxy_user.':'.$proxy_pass) + ."\r\n"; + } + + if ($this->config->get('verbose') > 3) { + print "XMLRPC REQUEST HEADERS:\n"; + var_dump($req_headers); + print "XMLRPC REQUEST BODY:\n"; + var_dump($request); + } + + if ($use_proxy && $proxy_host != '') { + $post_string = "POST http://".$server_host; + if ($proxy_port > '') { + $post_string .= ':'.$server_port; + } + } else { + $post_string = "POST "; + } + + $path = '/' . $channel->getPath('xmlrpc'); + fwrite($fp, ($post_string . $path . "$maxAge HTTP/1.0\r\n$req_headers\r\n$request")); + $response = ''; + $line1 = fgets($fp, 2048); + if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) { + return $this->raiseError("PEAR_Remote: invalid HTTP response from XML-RPC server"); + } + switch ($matches[1]) { + case "200": // OK + break; + case "304": // Not Modified + return $this->cache['content']; + case "401": // Unauthorized + if ($username && $password) { + return $this->raiseError("PEAR_Remote ($server_host:$server_port) " . + ": authorization failed", 401); + } else { + return $this->raiseError("PEAR_Remote ($server_host:$server_port) " . + ": authorization required, please log in first", 401); + } + default: + return $this->raiseError("PEAR_Remote ($server_host:$server_port) : " . + "unexpected HTTP response", (int)$matches[1], null, null, + "$matches[1] $matches[2]"); + } + while (trim(fgets($fp, 2048)) != ''); // skip rest of headers + while ($chunk = fread($fp, 10240)) { + $response .= $chunk; + } + fclose($fp); + if ($this->config->get('verbose') > 3) { + print "XMLRPC RESPONSE:\n"; + var_dump($response); + } + $ret = xmlrpc_decode($response); + if (is_array($ret) && isset($ret['__PEAR_TYPE__'])) { + if ($ret['__PEAR_TYPE__'] == 'error') { + if (isset($ret['__PEAR_CLASS__'])) { + $class = $ret['__PEAR_CLASS__']; + } else { + $class = "PEAR_Error"; + } + if ($ret['code'] === '') $ret['code'] = null; + if ($ret['message'] === '') $ret['message'] = null; + if ($ret['userinfo'] === '') $ret['userinfo'] = null; + if (strtolower($class) == 'db_error') { + $ret = $this->raiseError(PEAR::errorMessage($ret['code']), + $ret['code'], null, null, + $ret['userinfo']); + } else { + $ret = $this->raiseError($ret['message'], $ret['code'], + null, null, $ret['userinfo']); + } + } + } elseif (is_array($ret) && sizeof($ret) == 1 && isset($ret[0]) + && is_array($ret[0]) && + !empty($ret[0]['faultString']) && + !empty($ret[0]['faultCode'])) { + extract($ret[0]); + $faultString = "XML-RPC Server Fault: " . + str_replace("\n", " ", $faultString); + return $this->raiseError($faultString, $faultCode); + } elseif (is_array($ret) && sizeof($ret) == 2 && !empty($ret['faultString']) && + !empty($ret['faultCode'])) { + extract($ret); + $faultString = "XML-RPC Server Fault: " . + str_replace("\n", " ", $faultString); + return $this->raiseError($faultString, $faultCode); + } + return $ret; + } + + // }}} + + // {{{ _encode + + // a slightly extended version of XML_RPC_encode + function _encode($php_val) + { + global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double; + global $XML_RPC_String, $XML_RPC_Array, $XML_RPC_Struct; + + $type = gettype($php_val); + $xmlrpcval = new XML_RPC_Value; + + switch($type) { + case "array": + reset($php_val); + $firstkey = key($php_val); + end($php_val); + $lastkey = key($php_val); + reset($php_val); + if ($firstkey === 0 && is_int($lastkey) && + ($lastkey + 1) == count($php_val)) { + $is_continuous = true; + reset($php_val); + $size = count($php_val); + for ($expect = 0; $expect < $size; $expect++, next($php_val)) { + if (key($php_val) !== $expect) { + $is_continuous = false; + break; + } + } + if ($is_continuous) { + reset($php_val); + $arr = array(); + while (list($k, $v) = each($php_val)) { + $arr[$k] = $this->_encode($v); + } + $xmlrpcval->addArray($arr); + break; + } + } + // fall though if not numerical and continuous + case "object": + $arr = array(); + while (list($k, $v) = each($php_val)) { + $arr[$k] = $this->_encode($v); + } + $xmlrpcval->addStruct($arr); + break; + case "integer": + $xmlrpcval->addScalar($php_val, $XML_RPC_Int); + break; + case "double": + $xmlrpcval->addScalar($php_val, $XML_RPC_Double); + break; + case "string": + case "NULL": + $xmlrpcval->addScalar($php_val, $XML_RPC_String); + break; + case "boolean": + $xmlrpcval->addScalar($php_val, $XML_RPC_Boolean); + break; + case "unknown type": + default: + return null; + } + return $xmlrpcval; + } + + // }}} + +} + +?> diff --git a/vas/rest/class/PEAR/RunTest.php b/vas/rest/class/PEAR/RunTest.php new file mode 100755 index 0000000000000000000000000000000000000000..85f49d9baf6fad5c73f8ed404b1688b9c900a61a --- /dev/null +++ b/vas/rest/class/PEAR/RunTest.php @@ -0,0 +1,927 @@ +<?php +/** + * PEAR_RunTest + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: RunTest.php,v 1.67 2008/05/14 02:30:16 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + +/** + * for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +define('DETAILED', 1); +putenv("PHP_PEAR_RUNTESTS=1"); + +/** + * Simplified version of PHP's test suite + * + * Try it with: + * + * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + */ +class PEAR_RunTest +{ + var $_headers = array(); + var $_logger; + var $_options; + var $_php; + var $tests_count; + var $xdebug_loaded; + /** + * Saved value of php executable, used to reset $_php when we + * have a test that uses cgi + * + * @var unknown_type + */ + var $_savephp; + var $ini_overwrites = array( + 'output_handler=', + 'open_basedir=', + 'safe_mode=0', + 'disable_functions=', + 'output_buffering=Off', + 'display_errors=1', + 'log_errors=0', + 'html_errors=0', + 'track_errors=1', + 'report_memleaks=0', + 'report_zend_debug=0', + 'docref_root=', + 'docref_ext=.html', + 'error_prepend_string=', + 'error_append_string=', + 'auto_prepend_file=', + 'auto_append_file=', + 'magic_quotes_runtime=0', + 'xdebug.default_enable=0', + 'allow_url_fopen=1', + ); + + /** + * An object that supports the PEAR_Common->log() signature, or null + * @param PEAR_Common|null + */ + function PEAR_RunTest($logger = null, $options = array()) + { + if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 0); + } + if (!defined('E_STRICT')) { + define('E_STRICT', 0); + } + $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT)); + if (is_null($logger)) { + require_once 'PEAR/Common.php'; + $logger = new PEAR_Common; + } + $this->_logger = $logger; + $this->_options = $options; + + $conf = &PEAR_Config::singleton(); + $this->_php = $conf->get('php_bin'); + } + + /** + * Taken from php-src/run-tests.php + * + * @param string $commandline command name + * @param array $env + * @param string $stdin standard input to pass to the command + * @return unknown + */ + function system_with_timeout($commandline, $env = null, $stdin = null) + { + $data = ''; + if (version_compare(phpversion(), '5.0.0', '<')) { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes); + } else { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes, null, $env, array('suppress_errors' => true)); + } + + if (!$proc) { + return false; + } + + if (is_string($stdin)) { + fwrite($pipes[0], $stdin); + } + fclose($pipes[0]); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $e = $w = null; + $n = @stream_select($r, $w, $e, 60); + + if ($n === 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc); + return array(1234567890, $data); + } else if ($n > 0) { + $line = fread($pipes[1], 8192); + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + if (function_exists('proc_get_status')) { + $stat = proc_get_status($proc); + if ($stat['signaled']) { + $data .= "\nTermsig=".$stat['stopsig']; + } + } + $code = proc_close($proc); + if (function_exists('proc_get_status')) { + $code = $stat['exitcode']; + } + return array($code, $data); + } + + /** + * Turns a PHP INI string into an array + * + * Turns -d "include_path=/foo/bar" into this: + * array( + * 'include_path' => array( + * 'operator' => '-d', + * 'value' => '/foo/bar', + * ) + * ) + * Works both with quotes and without + * + * @param string an PHP INI string, -d "include_path=/foo/bar" + * @return array + */ + function iniString2array($ini_string) + { + if (!$ini_string) { + return array(); + } + $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY); + $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1]; + $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2]; + // FIXME review if this is really the struct to go with + $array = array($key => array('operator' => $split[0], 'value' => $value)); + return $array; + } + + function settings2array($settings, $ini_settings) + { + foreach ($settings as $setting) { + if (strpos($setting, '=') !== false) { + $setting = explode('=', $setting, 2); + $name = trim(strtolower($setting[0])); + $value = trim($setting[1]); + $ini_settings[$name] = $value; + } + } + return $ini_settings; + } + + function settings2params($ini_settings) + { + $settings = ''; + foreach ($ini_settings as $name => $value) { + if (is_array($value)) { + $operator = $value['operator']; + $value = $value['value']; + } else { + $operator = '-d'; + } + $value = addslashes($value); + $settings .= " $operator \"$name=$value\""; + } + return $settings; + } + + function runPHPUnit($file, $ini_settings = '') + { + if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) { + $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file); + break; + } elseif (file_exists($file)) { + $file = realpath($file); + } + $cmd = "$this->_php$ini_settings -f $file"; + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + $savedir = getcwd(); // in case the test moves us around + chdir(dirname($file)); + echo `$cmd`; + chdir($savedir); + return 'PASSED'; // we have no way of knowing this information so assume passing + } + + /** + * Runs an individual test case. + * + * @param string The filename of the test + * @param array|string INI settings to be applied to the test run + * @param integer Number what the current running test is of the + * whole test suite being runned. + * + * @return string|object Returns PASSED, WARNED, FAILED depending on how the + * test came out. + * PEAR Error when the tester it self fails + */ + function run($file, $ini_settings = array(), $test_number = 1) + { + if (isset($this->_savephp)) { + $this->_php = $this->_savephp; + unset($this->_savephp); + } + if (empty($this->_options['cgi'])) { + // try to see if php-cgi is in the path + $res = $this->system_with_timeout('php-cgi -v'); + if (false !== $res && !(is_array($res) && $res === array(127, ''))) { + $this->_options['cgi'] = 'php-cgi'; + } + } + if (1 < $len = strlen($this->tests_count)) { + $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT); + $test_nr = "[$test_number/$this->tests_count] "; + } else { + $test_nr = ''; + } + + $file = realpath($file); + $section_text = $this->_readFile($file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) { + return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file"); + } + + $cwd = getcwd(); + + $pass_options = ''; + if (!empty($this->_options['ini'])) { + $pass_options = $this->_options['ini']; + } + + if (is_string($ini_settings)) { + $ini_settings = $this->iniString2array($ini_settings); + } + + $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings); + if ($section_text['INI']) { + if (strpos($section_text['INI'], '{PWD}') !== false) { + $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); + } + $ini = preg_split( "/[\n\r]+/", $section_text['INI']); + $ini_settings = $this->settings2array($ini, $ini_settings); + } + $ini_settings = $this->settings2params($ini_settings); + $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file); + + $tested = trim($section_text['TEST']); + $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' '; + + if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) || + !empty($section_text['UPLOAD']) || !empty($section_text['GET']) || + !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { + if (empty($this->_options['cgi'])) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info'); + } + return 'SKIPPED'; + } + $this->_savephp = $this->_php; + $this->_php = $this->_options['cgi']; + } + + $temp_dir = realpath(dirname($file)); + $main_file_name = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + $this->_cleanupOldFiles($file); + + // Check if test should be skipped. + $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings); + if (count($res) != 2) { + return $res; + } + $info = $res['info']; + $warn = $res['warn']; + + // We've satisfied the preconditions - run the test! + if (isset($this->_options['coverage']) && $this->xdebug_loaded) { + $len_f = 5; + if (substr($section_text['FILE'], 0, 5) != '<?php' + && substr($section_text['FILE'], 0, 2) == '<?') { + $len_f = 2; + } + + $text = '<?php' . "\n" . 'xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);' . "\n"; + $new = substr($section_text['FILE'], $len_f, strlen($section_text['FILE'])); + $text .= substr($new, 0, strrpos($new, '?>')); + $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug'; + $text .= "\n" . + "\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);'; + } + $text .= "\n" . 'xdebug_stop_code_coverage();' . "\n" . '?>'; + + $this->save_text($temp_file, $text); + } else { + $this->save_text($temp_file, $section_text['FILE']); + } + + $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; + $cmd = "$this->_php$ini_settings -f \"$temp_file\" $args 2>&1"; + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + // Reset environment from any previous test. + $env = $this->_resetEnv($section_text, $temp_file); + + $section_text = $this->_processUpload($section_text, $file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + $post = trim($section_text['POST_RAW']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + foreach ($raw_lines as $i => $line) { + if (empty($env['CONTENT_TYPE']) && + preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + if ($started) { + $request .= "\n"; + } + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'POST'; + + $this->save_text($tmp_post, $request); + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + $post = trim($section_text['POST']); + $this->save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } else { + $env['REQUEST_METHOD'] = 'GET'; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + } + + if (OS_WINDOWS && isset($section_text['RETURNS'])) { + ob_start(); + system($cmd, $return_value); + $out = ob_get_contents(); + ob_end_clean(); + $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); + $returnfail = ($return_value != $section_text['RETURNS']); + } else { + $returnfail = false; + $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null; + $out = $this->system_with_timeout($cmd, $env, $stdin); + $return_value = $out[0]; + $out = $out[1]; + } + + $output = preg_replace('/\r\n/', "\n", trim($out)); + + if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) { + @unlink(realpath($tmp_post)); + } + chdir($cwd); // in case the test moves us around + + $this->_testCleanup($section_text, $temp_clean); + + /* when using CGI, strip the headers from the output */ + $output = $this->_stripHeadersCGI($output); + + if (isset($section_text['EXPECTHEADERS'])) { + $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']); + $missing = array_diff_assoc($testheaders, $this->_headers); + $changed = ''; + foreach ($missing as $header => $value) { + if (isset($this->_headers[$header])) { + $changed .= "-$header: $value\n+$header: "; + $changed .= $this->_headers[$header]; + } else { + $changed .= "-$header: $value\n"; + } + } + if ($missing) { + // tack on failed headers to output: + $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed"; + } + } + // Does the output match what is expected? + do { + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + if (isset($section_text['EXPECTF'])) { + $wanted_re = preg_quote($wanted_re, '/'); + // Stick to basics + $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy + $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); + $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); + $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); + $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); + $wanted_re = str_replace("%c", ".", $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } + /* DEBUG YOUR REGEX HERE + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); + */ + if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } else { + if (isset($section_text['EXPECTFILE'])) { + $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']); + if (!($fp = @fopen($f, 'rb'))) { + return PEAR::raiseError('--EXPECTFILE-- section file ' . + $f . ' not found'); + } + fclose($fp); + $section_text['EXPECT'] = file_get_contents($f); + } + $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT'])); + // compare and leave on success + if (!$returnfail && 0 == strcmp($output, $wanted)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } + } while (false); + + if (array_key_exists('FAIL', $section_text)) { + // we expect a particular failure + // this is only used for testing PEAR_RunTest + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $faildiff = $this->generate_diff($wanted, $output, null, $expectf); + $faildiff = preg_replace('/\r/', '', $faildiff); + $wanted = preg_replace('/\r/', '', trim($section_text['FAIL'])); + if ($faildiff == $wanted) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + unset($section_text['EXPECTF']); + $output = $faildiff; + if (isset($section_text['RETURNS'])) { + return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' . + $file); + } + } + + // Test failed so we need to report details. + $txt = $warn ? 'WARN ' : 'FAIL '; + $this->_logger->log(0, $txt . $test_nr . $tested . $info); + + // write .exp + $res = $this->_writeLog($exp_filename, $wanted); + if (PEAR::isError($res)) { + return $res; + } + + // write .out + $res = $this->_writeLog($output_filename, $output); + if (PEAR::isError($res)) { + return $res; + } + + // write .diff + $returns = isset($section_text['RETURNS']) ? + array(trim($section_text['RETURNS']), $return_value) : null; + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $data = $this->generate_diff($wanted, $output, $returns, $expectf); + $res = $this->_writeLog($diff_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + // write .log + $data = " +---- EXPECTED OUTPUT +$wanted +---- ACTUAL OUTPUT +$output +---- FAILED +"; + + if ($returnfail) { + $data .= " +---- EXPECTED RETURN +$section_text[RETURNS] +---- ACTUAL RETURN +$return_value +"; + } + + $res = $this->_writeLog($log_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + if (isset($this->_options['tapoutput'])) { + $wanted = explode("\n", $wanted); + $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted); + $output = explode("\n", $output); + $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output); + return array($wanted . $output . 'not ok', ' - ' . $tested); + } + return $warn ? 'WARNED' : 'FAILED'; + } + + function generate_diff($wanted, $output, $rvalue, $wanted_re) + { + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $wr = explode("\n", $wanted_re); + $w1 = array_diff_assoc($w, $o); + $o1 = array_diff_assoc($o, $w); + $o2 = $w2 = array(); + foreach ($w1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) { + $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val; + } + } + foreach ($o1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $val)) { + $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val; + } + } + $diff = array_merge($w2, $o2); + ksort($diff); + $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : ''; + return implode("\r\n", $diff) . $extra; + } + + // Write the given text to a temporary file, and return the filename. + function save_text($filename, $text) + { + if (!$fp = fopen($filename, 'w')) { + return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); + } + fwrite($fp, $text); + fclose($fp); + if (1 < DETAILED) echo " +FILE $filename {{{ +$text +}}} +"; + } + + function _cleanupOldFiles($file) + { + $temp_dir = realpath(dirname($file)); + $mainFileName = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + @unlink($diff_filename); + @unlink($log_filename); + @unlink($exp_filename); + @unlink($output_filename); + @unlink($memcheck_filename); + @unlink($temp_file); + @unlink($temp_skipif); + @unlink($tmp_post); + @unlink($temp_clean); + } + + function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings) + { + $info = ''; + $warn = false; + if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) { + $this->save_text($temp_skipif, $section_text['SKIPIF']); + $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\""); + $output = $output[1]; + $loutput = ltrim($output); + unlink($temp_skipif); + if (!strncasecmp('skip', $loutput, 4)) { + $skipreason = "SKIP $tested"; + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { + $skipreason .= '(reason: ' . $m[1] . ')'; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, $skipreason); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip ' . $reason); + } + return 'SKIPPED'; + } + + if (!strncasecmp('info', $loutput, 4) + && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { + $info = " (info: $m[1])"; + } + + if (!strncasecmp('warn', $loutput, 4) + && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $m[1])"; + } + } + + return array('warn' => $warn, 'info' => $info); + } + + function _stripHeadersCGI($output) + { + $this->headers = array(); + if (!empty($this->_options['cgi']) && + $this->_php == $this->_options['cgi'] && + preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) { + $output = isset($match[2]) ? trim($match[2]) : ''; + $this->_headers = $this->_processHeaders($match[1]); + } + + return $output; + } + + /** + * Return an array that can be used with array_diff() to compare headers + * + * @param string $text + */ + function _processHeaders($text) + { + $headers = array(); + $rh = preg_split("/[\n\r]+/", $text); + foreach ($rh as $line) { + if (strpos($line, ':')!== false) { + $line = explode(':', $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + return $headers; + } + + function _readFile($file) + { + // Load the sections of the test file. + $section_text = array( + 'TEST' => '(unnamed test)', + 'SKIPIF' => '', + 'GET' => '', + 'COOKIE' => '', + 'POST' => '', + 'ARGS' => '', + 'INI' => '', + 'CLEAN' => '', + ); + + if (!is_file($file) || !$fp = fopen($file, "r")) { + return PEAR::raiseError("Cannot open test file: $file"); + } + + $section = ''; + while (!feof($fp)) { + $line = fgets($fp); + + // Match the beginning of a section. + if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { + $section = $r[1]; + $section_text[$section] = ''; + continue; + } elseif (empty($section)) { + fclose($fp); + return PEAR::raiseError("Invalid sections formats in test file: $file"); + } + + // Add to the section text. + $section_text[$section] .= $line; + } + fclose($fp); + + return $section_text; + } + + function _writeLog($logname, $data) + { + if (!$log = fopen($logname, 'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log, $data); + fclose($log); + } + + function _resetEnv($section_text, $temp_file) + { + $env = $_ENV; + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + if (!empty($section_text['ENV'])) { + foreach (explode("\n", trim($section_text['ENV'])) as $e) { + $e = explode('=', trim($e), 2); + if (!empty($e[0]) && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + } + if (array_key_exists('GET', $section_text)) { + $env['QUERY_STRING'] = trim($section_text['GET']); + } else { + $env['QUERY_STRING'] = ''; + } + if (array_key_exists('COOKIE', $section_text)) { + $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); + } else { + $env['HTTP_COOKIE'] = ''; + } + $env['REDIRECT_STATUS'] = '1'; + $env['PATH_TRANSLATED'] = $temp_file; + $env['SCRIPT_FILENAME'] = $temp_file; + + return $env; + } + + function _processUpload($section_text, $file) + { + if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) { + $upload_files = trim($section_text['UPLOAD']); + $upload_files = explode("\n", $upload_files); + + $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" . + "-----------------------------20896060251896012921717172737\n"; + foreach ($upload_files as $fileinfo) { + $fileinfo = explode('=', $fileinfo); + if (count($fileinfo) != 2) { + return PEAR::raiseError("Invalid UPLOAD section in test file: $file"); + } + if (!realpath(dirname($file) . '/' . $fileinfo[1])) { + return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " . + "in test file: $file"); + } + $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]); + $fileinfo[1] = basename($fileinfo[1]); + $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n"; + $request .= "Content-Type: text/plain\n\n"; + $request .= $file_contents . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + + if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + // encode POST raw + $post = trim($section_text['POST']); + $post = explode('&', $post); + foreach ($post as $i => $post_info) { + $post_info = explode('=', $post_info); + if (count($post_info) != 2) { + return PEAR::raiseError("Invalid POST data in test file: $file"); + } + $post_info[0] = rawurldecode($post_info[0]); + $post_info[1] = rawurldecode($post_info[1]); + $post[$i] = $post_info; + } + foreach ($post as $post_info) { + $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n"; + $request .= $post_info[1] . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + unset($section_text['POST']); + } + $section_text['POST_RAW'] = $request; + } + + return $section_text; + } + + function _testCleanup($section_text, $temp_clean) + { + if ($section_text['CLEAN']) { + // perform test cleanup + $this->save_text($temp_clean, $section_text['CLEAN']); + $this->system_with_timeout("$this->_php $temp_clean"); + if (file_exists($temp_clean)) { + unlink($temp_clean); + } + } + } +} \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Common.php b/vas/rest/class/PEAR/Task/Common.php new file mode 100755 index 0000000000000000000000000000000000000000..5841f286d6c16d8625a83d179c2e6d63fa1c0d7d --- /dev/null +++ b/vas/rest/class/PEAR/Task/Common.php @@ -0,0 +1,208 @@ +<?php +/** + * PEAR_Task_Common, base class for installer tasks + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Common.php,v 1.18 2008/05/13 21:28:20 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/**#@+ + * Error codes for task validation routines + */ +define('PEAR_TASK_ERROR_NOATTRIBS', 1); +define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); +define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); +define('PEAR_TASK_ERROR_INVALID', 4); +/**#@-*/ +define('PEAR_TASK_PACKAGE', 1); +define('PEAR_TASK_INSTALL', 2); +define('PEAR_TASK_PACKAGEANDINSTALL', 3); +/** + * A task is an operation that manipulates the contents of a file. + * + * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been + * processed and installed, and are designed to operate on all files containing the task. + * The Post-install script task simply takes advantage of the fact that it will be run + * after installation, replace is a simple task. + * + * Combining tasks is possible, but ordering is significant. + * + * <file name="test.php" role="php"> + * <tasks:replace from="@data-dir@" to="data_dir" type="pear-config"/> + * <tasks:postinstallscript/> + * </file> + * + * 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 <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + * @abstract + */ +class PEAR_Task_Common +{ + /** + * Valid types for this version are 'simple' and 'multiple' + * + * - simple tasks operate on the contents of a file and write out changes to disk + * - multiple tasks operate on the contents of many files and write out the + * changes directly to disk + * + * Child task classes must override this property. + * @access protected + */ + var $type = 'simple'; + /** + * Determines which install phase this task is executed under + */ + var $phase = PEAR_TASK_INSTALL; + /** + * @access protected + */ + var $config; + /** + * @access protected + */ + var $registry; + /** + * @access protected + */ + var $logger; + /** + * @access protected + */ + var $installphase; + /** + * @param PEAR_Config + * @param PEAR_Common + */ + function PEAR_Task_Common(&$config, &$logger, $phase) + { + $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 <file> tag + * @return true|array On error, return an array in format: + * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) + * + * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in + * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array + * of legal values in + * @static + * @abstract + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param array attributes from the <file> tag containing this task + * @param string|null last installed version of this package + * @abstract + */ + 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 + */ + 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 + * @static + * @abstract + */ + function run($tasks) + { + } + + /** + * @static + * @final + */ + function hasPostinstallTasks() + { + return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); + } + + /** + * @static + * @final + */ + function runPostinstallTasks() + { + foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { + $err = call_user_func(array($class, 'run'), + $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); + if ($err) { + return PEAR_Task_Common::throwError($err); + } + } + unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); + } + + /** + * Determines whether a role is a script + * @return bool + */ + function isScript() + { + return $this->type == 'script'; + } + + function throwError($msg, $code = -1) + { + include_once 'PEAR.php'; + return PEAR::raiseError($msg, $code); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Postinstallscript.php b/vas/rest/class/PEAR/Task/Postinstallscript.php new file mode 100755 index 0000000000000000000000000000000000000000..024c058536cc9d58fc1fea114e6151d7f59d4790 --- /dev/null +++ b/vas/rest/class/PEAR/Task/Postinstallscript.php @@ -0,0 +1,329 @@ +<?php +/** + * <tasks:postinstallscript> + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Postinstallscript.php,v 1.20 2008/05/13 21:28:20 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the postinstallscript file task. + * + * Note that post-install scripts are handled separately from installation, by the + * "pear run-scripts" command + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Postinstallscript extends PEAR_Task_Common +{ + var $type = 'script'; + var $_class; + var $_params; + var $_obj; + /** + * + * @var PEAR_PackageFile_v2 + */ + var $_pkg; + var $_contents; + var $phase = PEAR_TASK_INSTALL; + + /** + * Validate the raw xml at parsing-time. + * + * This also attempts to validate the script to make sure it meets the criteria + * for a post-install script + * @param PEAR_PackageFile_v2 + * @param array The XML contents of the <postinstallscript> tag + * @param PEAR_Config + * @param array the entire parsed <file> tag + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($fileXml['role'] != 'php') { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must be role="php"'); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $file = $pkg->getFileContents($fileXml['name']); + if (PEAR::isError($file)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" is not valid: ' . + $file->getMessage()); + } elseif ($file === null) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" could not be retrieved for processing!'); + } else { + $analysis = $pkg->analyzeSourceCode($file, true); + if (!$analysis) { + PEAR::popErrorHandling(); + $warnings = ''; + foreach ($pkg->getValidationWarnings() as $warn) { + $warnings .= $warn['message'] . "\n"; + } + return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . + $fileXml['name'] . '" failed: ' . $warnings); + } + if (count($analysis['declared_classes']) != 1) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare exactly 1 class'); + } + $class = $analysis['declared_classes'][0]; + if ($class != str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall') { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" class "' . $class . '" must be named "' . + str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall"'); + } + if (!isset($analysis['declared_methods'][$class])) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + $methods = array('init' => 0, 'run' => 1); + foreach ($analysis['declared_methods'][$class] as $method) { + if (isset($methods[$method])) { + unset($methods[$method]); + } + } + if (count($methods)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + } + 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'] . '" <paramgroup> 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; // <param> 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 raw, parsed xml + * @param array attributes from the <file> tag containing this task + * @param string|null last installed version of this package, if any (useful for upgrades) + */ + 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 + */ + 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 PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file name + * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError) + */ + function startSession($pkg, $contents) + { + 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 + * @static + */ + function run() + { + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Postinstallscript/rw.php b/vas/rest/class/PEAR/Task/Postinstallscript/rw.php new file mode 100755 index 0000000000000000000000000000000000000000..3f2a97cc6d3c52b7ca993058c24cbc1751be3d96 --- /dev/null +++ b/vas/rest/class/PEAR/Task/Postinstallscript/rw.php @@ -0,0 +1,176 @@ +<?php +/** + * <tasks:postinstallscript> - read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: rw.php,v 1.12 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Postinstallscript.php'; +/** + * Abstracts the postinstallscript file task xml. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript +{ + /** + * parent package file object + * + * @var PEAR_PackageFile_v2_rw + */ + var $_pkg; + /** + * Enter description here... + * + * @param PEAR_PackageFile_v2_rw $pkg + * @param PEAR_Config $config + * @param PEAR_Frontend $logger + * @param array $fileXml + * @return PEAR_Task_Postinstallscript_rw + */ + function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } + + function getName() + { + return 'postinstallscript'; + } + + /** + * add a simple <paramgroup> 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 <paramgroup> containing + * a <conditiontype> tag + * @param string $id <paramgroup> id as seen by the script + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions + */ + 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 <paramgroup> to the post-install script with conditions + * + * This inserts a <paramgroup> 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 <paramgroup> + * + * @param string $id <paramgroup> id as seen by the script + * @param string $oldgroup <paramgroup> id of the section referenced by + * <conditiontype> + * @param string $param name of the <param> from the older section referenced + * by <contitiontype> + * @param string $value value to match of the parameter + * @param string $conditiontype one of '=', '!=', 'preg_match' + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions + */ + function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', + $params = false, $instructions = false) + { + 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; + } + + function getXml() + { + return $this->_params; + } + + /** + * Use to set up a param tag for use in creating a paramgroup + * @static + */ + 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, + ); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Replace.php b/vas/rest/class/PEAR/Task/Replace.php new file mode 100755 index 0000000000000000000000000000000000000000..9a941819baed05afbb6824e0cffeb89f5630bda7 --- /dev/null +++ b/vas/rest/class/PEAR/Task/Replace.php @@ -0,0 +1,182 @@ +<?php +/** + * <tasks:replace> + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Replace.php,v 1.17 2008/05/13 21:28:20 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the replace file task. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Replace extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGEANDINSTALL; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + 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 + */ + function init($xml, $attribs) + { + $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; + } + + /** + * Do a package.xml 1.0 replacement, with additional package-info fields available + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $subst_from = $subst_to = array(); + foreach ($this->_replacements as $a) { + $a = $a['attribs']; + $to = ''; + if ($a['type'] == 'pear-config') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if ($a['to'] == 'master_server') { + $chan = $this->registry->getChannel($pkg->getChannel()); + if (!PEAR::isError($chan)) { + $to = $chan->getServer(); + } else { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } else { + if ($this->config->isDefinedLayer('ftp')) { + // try the remote config file first + $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); + if (is_null($to)) { + // then default to local + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } else { + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } + if (is_null($to)) { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } elseif ($a['type'] == 'php-const') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if (defined($a['to'])) { + $to = constant($a['to']); + } else { + $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); + return false; + } + } else { + if ($t = $pkg->packageInfo($a['to'])) { + $to = $t; + } else { + $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); + return false; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + $this->logger->log(3, "doing " . sizeof($subst_from) . + " substitution(s) for $dest"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + return $contents; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Replace/rw.php b/vas/rest/class/PEAR/Task/Replace/rw.php new file mode 100755 index 0000000000000000000000000000000000000000..fe03d2e61b9b84996929b450cb0f41b858a7a3ad --- /dev/null +++ b/vas/rest/class/PEAR/Task/Replace/rw.php @@ -0,0 +1,67 @@ +<?php +/** + * <tasks:replace> - read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: rw.php,v 1.4 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Replace.php'; +/** + * Abstracts the replace task xml. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Replace_rw extends PEAR_Task_Replace +{ + function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } + + function setInfo($from, $to, $type) + { + $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); + } + + function getName() + { + return 'replace'; + } + + function getXml() + { + return $this->_params; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Unixeol.php b/vas/rest/class/PEAR/Task/Unixeol.php new file mode 100755 index 0000000000000000000000000000000000000000..bfd3f11c2f144db21942d51d331dd876ce865ba3 --- /dev/null +++ b/vas/rest/class/PEAR/Task/Unixeol.php @@ -0,0 +1,83 @@ +<?php +/** + * <tasks:unixeol> + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Unixeol.php,v 1.10 2008/05/13 21:28:20 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the unix line endings file task. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Unixeol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with line endings customized for the current OS + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $this->logger->log(3, "replacing all line endings with \\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Unixeol/rw.php b/vas/rest/class/PEAR/Task/Unixeol/rw.php new file mode 100755 index 0000000000000000000000000000000000000000..f04f0f00b9d68b98e0cb2b2fe037688b9f7eb369 --- /dev/null +++ b/vas/rest/class/PEAR/Task/Unixeol/rw.php @@ -0,0 +1,62 @@ +<?php +/** + * <tasks:unixeol> - read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: rw.php,v 1.5 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Unixeol.php'; +/** + * Abstracts the unixeol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol +{ + function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'unixeol'; + } + + function getXml() + { + return ''; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Windowseol.php b/vas/rest/class/PEAR/Task/Windowseol.php new file mode 100755 index 0000000000000000000000000000000000000000..1a1be1e4c37426ccd8f31dcf4a32f3a02c4d66ec --- /dev/null +++ b/vas/rest/class/PEAR/Task/Windowseol.php @@ -0,0 +1,83 @@ +<?php +/** + * <tasks:windowseol> + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Windowseol.php,v 1.9 2008/05/13 21:28:20 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the windows line endsings file task. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Windowseol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with windows line endings + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Task/Windowseol/rw.php b/vas/rest/class/PEAR/Task/Windowseol/rw.php new file mode 100755 index 0000000000000000000000000000000000000000..c61a15d8903f92a997cc120ebe9106368bf4afac --- /dev/null +++ b/vas/rest/class/PEAR/Task/Windowseol/rw.php @@ -0,0 +1,62 @@ +<?php +/** + * <tasks:windowseol> - read/write version + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: rw.php,v 1.5 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Windowseol.php'; +/** + * Abstracts the windowseol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol +{ + function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'windowseol'; + } + + function getXml() + { + return ''; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/Validate.php b/vas/rest/class/PEAR/Validate.php new file mode 100755 index 0000000000000000000000000000000000000000..34796b79303ae6d4761dfca34b677191077a1d98 --- /dev/null +++ b/vas/rest/class/PEAR/Validate.php @@ -0,0 +1,634 @@ +<?php +/** + * PEAR_Validate + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Validate.php,v 1.52 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/**#@+ + * Constants for install stage + */ +define('PEAR_VALIDATE_INSTALLING', 1); +define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others +define('PEAR_VALIDATE_NORMAL', 3); +define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others +define('PEAR_VALIDATE_PACKAGING', 7); +/**#@-*/ +require_once 'PEAR/Common.php'; +require_once 'PEAR/Validator/PECL.php'; + +/** + * Validation class for package.xml - channel-level advanced validation + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Validate +{ + var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + var $_packagexml; + /** + * @var int one of the PEAR_VALIDATE_* constants + */ + var $_state = PEAR_VALIDATE_NORMAL; + /** + * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) + * @var array + * @access private + */ + var $_failures = array('error' => array(), 'warning' => array()); + + /** + * Override this method to handle validation of normal package names + * @param string + * @return bool + * @access protected + */ + function _validPackageName($name) + { + return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); + } + + /** + * @param string package name to validate + * @param string name of channel-specific validation package + * @final + */ + function validPackageName($name, $validatepackagename = false) + { + if ($validatepackagename) { + if (strtolower($name) == strtolower($validatepackagename)) { + return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); + } + } + return $this->_validPackageName($name); + } + + /** + * This validates a bundle name, and bundle names must conform + * to the PEAR naming convention, so the method is final and static. + * @param string + * @final + * @static + */ + function validGroupName($name) + { + return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); + } + + /** + * Determine whether $state represents a valid stability level + * @param string + * @return bool + * @static + * @final + */ + function validState($state) + { + return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); + } + + /** + * Get a list of valid stability levels + * @return array + * @static + * @final + */ + function getValidStates() + { + return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + } + + /** + * Determine whether a version is a properly formatted version number that can be used + * by version_compare + * @param string + * @return bool + * @static + * @final + */ + function validVersion($ver) + { + return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function setPackageFile(&$pf) + { + $this->_packagexml = &$pf; + } + + /** + * @access private + */ + function _addFailure($field, $reason) + { + $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); + } + + /** + * @access private + */ + function _addWarning($field, $reason) + { + $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); + } + + function getFailures() + { + $failures = $this->_failures; + $this->_failures = array('warnings' => array(), 'errors' => array()); + return $failures; + } + + /** + * @param int one of the PEAR_VALIDATE_* constants + */ + function validate($state = null) + { + if (!isset($this->_packagexml)) { + return false; + } + if ($state !== null) { + $this->_state = $state; + } + $this->_failures = array('warnings' => array(), 'errors' => array()); + $this->validatePackageName(); + $this->validateVersion(); + $this->validateMaintainers(); + $this->validateDate(); + $this->validateSummary(); + $this->validateDescription(); + $this->validateLicense(); + $this->validateNotes(); + if ($this->_packagexml->getPackagexmlVersion() == '1.0') { + $this->validateState(); + $this->validateFilelist(); + } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') { + $this->validateTime(); + $this->validateStability(); + $this->validateDeps(); + $this->validateMainFilelist(); + $this->validateReleaseFilelist(); + //$this->validateGlobalTasks(); + $this->validateChangelog(); + } + return !((bool) count($this->_failures['errors'])); + } + + /** + * @access protected + */ + function validatePackageName() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING || + $this->_state == PEAR_VALIDATE_NORMAL) { + if (($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') && + $this->_packagexml->getExtends()) { + $version = $this->_packagexml->getVersion() . ''; + $name = $this->_packagexml->getPackage(); + $test = array_shift($a = explode('.', $version)); + if ($test == '0') { + return true; + } + $vlen = strlen($test); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if ($majver != $test) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name should ' . + 'have a postfix equal to the major version like "' . + $this->_packagexml->getExtends() . $test . '"'); + return true; + } elseif (substr($name, 0, strlen($name) - $vlen) != + $this->_packagexml->getExtends()) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name must ' . + 'be an extension like "' . $this->_packagexml->getExtends() . + $test . '"'); + return true; + } + } + } + if (!$this->validPackageName($this->_packagexml->getPackage())) { + $this->_addFailure('name', 'package name "' . + $this->_packagexml->getPackage() . '" is invalid'); + return false; + } + } + + /** + * @access protected + */ + function validateVersion() + { + if ($this->_state != PEAR_VALIDATE_PACKAGING) { + if (!$this->validVersion($this->_packagexml->getVersion())) { + $this->_addFailure('version', + 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); + } + return false; + } + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + if (count($versioncomponents) != 3) { + $this->_addWarning('version', + 'A version number should have 3 decimals (x.y.z)'); + return true; + } + $name = $this->_packagexml->getPackage(); + // version must be based upon state + switch ($this->_packagexml->getState()) { + case 'snapshot' : + return true; + case 'devel' : + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } else { + $this->_addWarning('version', + 'packages with devel stability must be < version 1.0.0'); + } + return true; + break; + case 'alpha' : + case 'beta' : + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + if (substr($versioncomponents[2], 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions ' . + 'must have capital RC, not lower-case rc'); + return false; + } + } + if (!$this->_packagexml->getExtends()) { + if ($versioncomponents[0] == '1') { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 1.*.0000 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 1.*.0RC1 or 1.*.0beta24 etc. + return true; + } else { + // version 1.*.0 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + 'bugfix versions (1.3.x where x > 0) probably should ' . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + 'major versions greater than 1 are not allowed for packages ' . + 'without an <extends> tag or an identical postfix (foo2 v2.0.0)'); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } else { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + if ($versioncomponents[0] == $majver) { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 2.*.0000 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return false; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 2.*.0RC1 or 2.*.0beta24 etc. + return true; + } else { + // version 2.*.0 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 cannot be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + "bugfix versions ($majver.x.y where y > 0) should " . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } + return true; + break; + case 'stable' : + if ($versioncomponents[0] == '0') { + $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . + 'be stable'); + return true; + } + if (!is_numeric($versioncomponents[2])) { + if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', + $versioncomponents[2])) { + $this->_addWarning('version', 'version "' . $version . '" or any ' . + 'RC/beta/alpha version cannot be stable'); + return true; + } + } + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_packagexml->getExtends()) { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + } elseif ($versioncomponents[0] > 1) { + $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . + '1 for any package that does not have an <extends> tag'); + } + return true; + break; + default : + return false; + break; + } + } + + /** + * @access protected + */ + function validateMaintainers() + { + // maintainers can only be truly validated server-side for most channels + // but allow this customization for those who wish it + return true; + } + + /** + * @access protected + */ + function validateDate() + { + if ($this->_state == PEAR_VALIDATE_NORMAL || + $this->_state == PEAR_VALIDATE_PACKAGING) { + + if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', + $this->_packagexml->getDate(), $res) || + count($res) < 4 + || !checkdate($res[2], $res[3], $res[1]) + ) { + $this->_addFailure('date', 'invalid release date "' . + $this->_packagexml->getDate() . '"'); + return false; + } + + + if ($this->_state == PEAR_VALIDATE_PACKAGING && + $this->_packagexml->getDate() != date('Y-m-d')) { + $this->_addWarning('date', 'Release Date "' . + $this->_packagexml->getDate() . '" is not today'); + } + } + return true; + } + + /** + * @access protected + */ + function validateTime() + { + if (!$this->_packagexml->getTime()) { + // default of no time value set + return true; + } + // packager automatically sets time, so only validate if + // pear validate is called + if ($this->_state = PEAR_VALIDATE_NORMAL) { + if (!preg_match('/\d\d:\d\d:\d\d/', + $this->_packagexml->getTime())) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + if (strtotime($this->_packagexml->getTime()) == -1) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + } + return true; + } + + /** + * @access protected + */ + function validateState() + { + // this is the closest to "final" php4 can get + if (!PEAR_Validate::validState($this->_packagexml->getState())) { + if (strtolower($this->_packagexml->getState() == 'rc')) { + $this->_addFailure('state', 'RC is not a state, it is a version ' . + 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); + } + $this->_addFailure('state', 'invalid release state "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + return false; + } + return true; + } + + /** + * @access protected + */ + function validateStability() + { + $ret = true; + $packagestability = $this->_packagexml->getState(); + $apistability = $this->_packagexml->getState('api'); + if (!PEAR_Validate::validState($packagestability)) { + $this->_addFailure('state', 'invalid release stability "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + $ret = false; + } + $apistates = PEAR_Validate::getValidStates(); + array_shift($apistates); // snapshot is not allowed + if (!in_array($apistability, $apistates)) { + $this->_addFailure('state', 'invalid API stability "' . + $this->_packagexml->getState('api') . '", must be one of: ' . + implode(', ', $apistates)); + $ret = false; + } + return $ret; + } + + /** + * @access protected + */ + function validateSummary() + { + return true; + } + + /** + * @access protected + */ + function validateDescription() + { + return true; + } + + /** + * @access protected + */ + function validateLicense() + { + return true; + } + + /** + * @access protected + */ + function validateNotes() + { + return true; + } + + /** + * for package.xml 2.0 only - channels can't use package.xml 1.0 + * @access protected + */ + function validateDependencies() + { + return true; + } + + /** + * for package.xml 1.0 only + * @access private + */ + function _validateFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateMainFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateReleaseFilelist() + { + return true; // placeholder for now + } + + /** + * @access protected + */ + function validateChangelog() + { + return true; + } + + /** + * @access protected + */ + function validateFilelist() + { + return true; + } + + /** + * @access protected + */ + function validateDeps() + { + return true; + } +} +?> diff --git a/vas/rest/class/PEAR/Validator/PECL.php b/vas/rest/class/PEAR/Validator/PECL.php new file mode 100755 index 0000000000000000000000000000000000000000..354a5bed1d4dc7220f44fc287592228feed60f66 --- /dev/null +++ b/vas/rest/class/PEAR/Validator/PECL.php @@ -0,0 +1,63 @@ +<?php +/** + * Channel Validator for the pecl.php.net channel + * + * PHP 4 and PHP 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PECL.php,v 1.9 2008/01/03 20:26:37 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a5 + */ +/** + * This is the parent class for all validators + */ +require_once 'PEAR/Validate.php'; +/** + * Channel Validator for the pecl.php.net channel + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a5 + */ +class PEAR_Validator_PECL extends PEAR_Validate +{ + function validateVersion() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + $last = array_pop($versioncomponents); + if (substr($last, 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions must have ' . + 'upper-case RC, not lower-case rc'); + return false; + } + } + return true; + } + + function validatePackageName() + { + $ret = parent::validatePackageName(); + if ($this->_packagexml->getPackageType() == 'extsrc' || + $this->_packagexml->getPackageType() == 'zendextsrc') { + if (strtolower($this->_packagexml->getPackage()) != + strtolower($this->_packagexml->getProvidesExtension())) { + $this->_addWarning('providesextension', 'package name "' . + $this->_packagexml->getPackage() . '" is different from extension name "' . + $this->_packagexml->getProvidesExtension() . '"'); + } + } + return $ret; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PEAR/XMLParser.php b/vas/rest/class/PEAR/XMLParser.php new file mode 100755 index 0000000000000000000000000000000000000000..faabc073d58cc081cf15320842fa12e81b2383aa --- /dev/null +++ b/vas/rest/class/PEAR/XMLParser.php @@ -0,0 +1,261 @@ +<?php +/** + * PEAR_XMLParser + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: XMLParser.php,v 1.13 2008/01/03 20:26:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Parser for any xml file + * @category pear + * @package PEAR + * @author Greg Beaver <cellog@php.net> + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_XMLParser +{ + /** + * unserilialized data + * @var string $_serializedData + */ + var $_unserializedData = null; + + /** + * name of the root tag + * @var string $_root + */ + var $_root = null; + + /** + * stack for all data that is found + * @var array $_dataStack + */ + var $_dataStack = array(); + + /** + * stack for all values that are generated + * @var array $_valStack + */ + var $_valStack = array(); + + /** + * current tag depth + * @var int $_depth + */ + var $_depth = 0; + + /** + * @return array + */ + function getData() + { + return $this->_unserializedData; + } + + /** + * @param string xml content + * @return true|PEAR_Error + */ + function parse($data) + { + if (!extension_loaded('xml')) { + include_once 'PEAR.php'; + return PEAR::raiseError("XML Extension not found", 1); + } + $this->_valStack = array(); + $this->_dataStack = array(); + $this->_depth = 0; + + if (version_compare(phpversion(), '5.0.0', 'lt')) { + if (strpos($data, 'encoding="UTF-8"')) { + $data = utf8_decode($data); + } + $xp = xml_parser_create('ISO-8859-1'); + } else { + if (strpos($data, 'encoding="UTF-8"')) { + $xp = xml_parser_create('UTF-8'); + } else { + $xp = xml_parser_create('ISO-8859-1'); + } + } + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xp, $this); + xml_set_element_handler($xp, 'startHandler', 'endHandler'); + xml_set_character_data_handler($xp, 'cdataHandler'); + if (!xml_parse($xp, $data)) { + $msg = xml_error_string(xml_get_error_code($xp)); + $line = xml_get_current_line_number($xp); + xml_parser_free($xp); + include_once 'PEAR.php'; + return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); + } + xml_parser_free($xp); + return true; + } + + /** + * Start element handler for XML parser + * + * @access private + * @param object $parser XML parser object + * @param string $element XML element + * @param array $attribs attributes of XML tag + * @return void + */ + function startHandler($parser, $element, $attribs) + { + $type = 'string'; + + $this->_depth++; + $this->_dataStack[$this->_depth] = null; + + $val = array( + 'name' => $element, + 'value' => null, + 'type' => $type, + 'childrenKeys' => array(), + 'aggregKeys' => array() + ); + + if (count($attribs) > 0) { + $val['children'] = array(); + $val['type'] = 'array'; + + $val['children']['attribs'] = $attribs; + + } + + array_push($this->_valStack, $val); + } + + /** + * post-process data + * + * @param string $data + * @param string $element element name + */ + function postProcess($data, $element) + { + return trim($data); + } + + /** + * End element handler for XML parser + * + * @access private + * @param object XML parser object + * @param string + * @return void + */ + function endHandler($parser, $element) + { + $value = array_pop($this->_valStack); + $data = $this->postProcess($this->_dataStack[$this->_depth], $element); + + // adjust type of the value + switch(strtolower($value['type'])) { + + /* + * unserialize an array + */ + case 'array': + if ($data !== '') { + $value['children']['_content'] = $data; + } + if (isset($value['children'])) { + $value['value'] = $value['children']; + } else { + $value['value'] = array(); + } + break; + + /* + * unserialize a null value + */ + case 'null': + $data = null; + break; + + /* + * unserialize any scalar value + */ + default: + settype($data, $value['type']); + $value['value'] = $data; + break; + } + $parent = array_pop($this->_valStack); + if ($parent === null) { + $this->_unserializedData = &$value['value']; + $this->_root = &$value['name']; + return true; + } else { + // parent has to be an array + if (!isset($parent['children']) || !is_array($parent['children'])) { + $parent['children'] = array(); + if ($parent['type'] != 'array') { + $parent['type'] = 'array'; + } + } + + if (!empty($value['name'])) { + // there already has been a tag with this name + if (in_array($value['name'], $parent['childrenKeys'])) { + // no aggregate has been created for this tag + if (!in_array($value['name'], $parent['aggregKeys'])) { + if (isset($parent['children'][$value['name']])) { + $parent['children'][$value['name']] = array($parent['children'][$value['name']]); + } else { + $parent['children'][$value['name']] = array(); + } + array_push($parent['aggregKeys'], $value['name']); + } + array_push($parent['children'][$value['name']], $value['value']); + } else { + $parent['children'][$value['name']] = &$value['value']; + array_push($parent['childrenKeys'], $value['name']); + } + } else { + array_push($parent['children'],$value['value']); + } + array_push($this->_valStack, $parent); + } + + $this->_depth--; + } + + /** + * Handler for character data + * + * @access private + * @param object XML parser object + * @param string CDATA + * @return void + */ + function cdataHandler($parser, $cdata) + { + $this->_dataStack[$this->_depth] .= $cdata; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/PHPMailer/extras/EasyPeasyICS.php b/vas/rest/class/PHPMailer/extras/EasyPeasyICS.php new file mode 100755 index 0000000000000000000000000000000000000000..d8bfcfae65957cfd3015494bd5c3a3ca22219f6a --- /dev/null +++ b/vas/rest/class/PHPMailer/extras/EasyPeasyICS.php @@ -0,0 +1,148 @@ +<?php +/** + * EasyPeasyICS Simple ICS/vCal data generator. + * @author Marcus Bointon <phpmailer@synchromedia.co.uk> + * @author Manuel Reinhard <manu@sprain.ch> + * + * Built with inspiration from + * http://stackoverflow.com/questions/1463480/how-can-i-use-php-to-dynamically-publish-an-ical-file-to-be-read-by-google-calend/1464355#1464355 + * History: + * 2010/12/17 - Manuel Reinhard - when it all started + * 2014 PHPMailer project becomes maintainer + */ + +/** + * Class EasyPeasyICS. + * Simple ICS data generator + * @package phpmailer + * @subpackage easypeasyics + */ +class EasyPeasyICS +{ + /** + * The name of the calendar + * @var string + */ + protected $calendarName; + /** + * The array of events to add to this calendar + * @var array + */ + protected $events = array(); + + /** + * Constructor + * @param string $calendarName + */ + public function __construct($calendarName = "") + { + $this->calendarName = $calendarName; + } + + /** + * Add an event to this calendar. + * @param string $start The start date and time as a unix timestamp + * @param string $end The end date and time as a unix timestamp + * @param string $summary A summary or title for the event + * @param string $description A description of the event + * @param string $url A URL for the event + * @param string $uid A unique identifier for the event - generated automatically if not provided + * @return array An array of event details, including any generated UID + */ + public function addEvent($start, $end, $summary = '', $description = '', $url = '', $uid = '') + { + if (empty($uid)) { + $uid = md5(uniqid(mt_rand(), true)) . '@EasyPeasyICS'; + } + $event = array( + 'start' => gmdate('Ymd', $start) . 'T' . gmdate('His', $start) . 'Z', + 'end' => gmdate('Ymd', $end) . 'T' . gmdate('His', $end) . 'Z', + 'summary' => $summary, + 'description' => $description, + 'url' => $url, + 'uid' => $uid + ); + $this->events[] = $event; + return $event; + } + + /** + * @return array Get the array of events. + */ + public function getEvents() + { + return $this->events; + } + + /** + * Clear all events. + */ + public function clearEvents() + { + $this->events = array(); + } + + /** + * Get the name of the calendar. + * @return string + */ + public function getName() + { + return $this->calendarName; + } + + /** + * Set the name of the calendar. + * @param $name + */ + public function setName($name) + { + $this->calendarName = $name; + } + + /** + * Render and optionally output a vcal string. + * @param bool $output Whether to output the calendar data directly (the default). + * @return string The complete rendered vlal + */ + public function render($output = true) + { + //Add header + $ics = 'BEGIN:VCALENDAR +METHOD:PUBLISH +VERSION:2.0 +X-WR-CALNAME:' . $this->calendarName . ' +PRODID:-//hacksw/handcal//NONSGML v1.0//EN'; + + //Add events + foreach ($this->events as $event) { + $ics .= ' +BEGIN:VEVENT +UID:' . $event['uid'] . ' +DTSTAMP:' . gmdate('Ymd') . 'T' . gmdate('His') . 'Z +DTSTART:' . $event['start'] . ' +DTEND:' . $event['end'] . ' +SUMMARY:' . str_replace("\n", "\\n", $event['summary']) . ' +DESCRIPTION:' . str_replace("\n", "\\n", $event['description']) . ' +URL;VALUE=URI:' . $event['url'] . ' +END:VEVENT'; + } + + //Add footer + $ics .= ' +END:VCALENDAR'; + + if ($output) { + //Output + $filename = $this->calendarName; + //Filename needs quoting if it contains spaces + if (strpos($filename, ' ') !== false) { + $filename = '"'.$filename.'"'; + } + header('Content-type: text/calendar; charset=utf-8'); + header('Content-Disposition: inline; filename=' . $filename . '.ics'); + echo $ics; + } + return $ics; + } +} diff --git a/vas/rest/class/PHPMailer/extras/README.md b/vas/rest/class/PHPMailer/extras/README.md new file mode 100755 index 0000000000000000000000000000000000000000..dac79e05fad5fdef31371fbbe9e7a7af0f2cf950 --- /dev/null +++ b/vas/rest/class/PHPMailer/extras/README.md @@ -0,0 +1,17 @@ +#PHPMailer Extras + +These classes provide optional additional functions to PHPMailer. + +These are not loaded by the PHPMailer autoloader, so in some cases you may need to `require` them yourself before using them. + +##EasyPeasyICS + +This class was originally written by Manuel Reinhard and provides a simple means of generating ICS/vCal files that are used in sending calendar events. PHPMailer does not use it directly, but you can use it to generate content appropriate for placing in the `Ical` property of PHPMailer. The PHPMailer project is now its official home as Manuel has given permission for that and is no longer maintaining it himself. + +##htmlfilter + +This class by Konstantin Riabitsev and Jim Jagielski implements HTML filtering to remove potentially malicious tags, such as `<script>` or `onclick=` attributes that can result in XSS attacks. This is a simple filter and is not as comprehensive as [HTMLawed](http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/) or [HTMLPurifier](http://htmlpurifier.org), but it's easier to use and considerably better than nothing! PHPMailer does not use it directly, but you may want to apply it to user-supplied HTML before using it as a message body. + +##NTLM_SASL_client + +This class by Manuel Lemos (bundled with permission) adds the ability to authenticate with Microsoft Windows mail servers that use NTLM-based authentication. It is used by PHPMailer if you send via SMTP and set the `AuthType` property to `NTLM`; you will also need to use the `Realm` and `Workstation` properties. The original source is [here](http://www.phpclasses.org/browse/file/7495.html). diff --git a/vas/rest/class/PHPMailer/extras/htmlfilter.php b/vas/rest/class/PHPMailer/extras/htmlfilter.php new file mode 100755 index 0000000000000000000000000000000000000000..0c55ddb756bedb4e802d6ca104418934da998825 --- /dev/null +++ b/vas/rest/class/PHPMailer/extras/htmlfilter.php @@ -0,0 +1,1159 @@ +<?php +/** + * htmlfilter.inc + * --------------- + * This set of functions allows you to filter html in order to remove + * any malicious tags from it. Useful in cases when you need to filter + * user input for any cross-site-scripting attempts. + * + * Copyright (C) 2002-2004 by Duke University + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * @Author Konstantin Riabitsev <icon@linux.duke.edu> + * @Author Jim Jagielski <jim@jaguNET.com / jimjag@gmail.com> + * @Version 1.1 ($Date$) + */ + +/** + * This function returns the final tag out of the tag name, an array + * of attributes, and the type of the tag. This function is called by + * tln_sanitize internally. + * + * @param string $tagname the name of the tag. + * @param array $attary the array of attributes and their values + * @param integer $tagtype The type of the tag (see in comments). + * @return string A string with the final tag representation. + */ +function tln_tagprint($tagname, $attary, $tagtype) +{ + if ($tagtype == 2) { + $fulltag = '</' . $tagname . '>'; + } else { + $fulltag = '<' . $tagname; + if (is_array($attary) && sizeof($attary)) { + $atts = array(); + foreach($attary as $attname => $attvalue) { + array_push($atts, "$attname=$attvalue"); + } + $fulltag .= ' ' . join(' ', $atts); + } + if ($tagtype == 3) { + $fulltag .= ' /'; + } + $fulltag .= '>'; + } + return $fulltag; +} + +/** + * A small helper function to use with array_walk. Modifies a by-ref + * value and makes it lowercase. + * + * @param string $val a value passed by-ref. + * @return void since it modifies a by-ref value. + */ +function tln_casenormalize(&$val) +{ + $val = strtolower($val); +} + +/** + * This function skips any whitespace from the current position within + * a string and to the next non-whitespace value. + * + * @param string $body the string + * @param integer $offset the offset within the string where we should start + * looking for the next non-whitespace character. + * @return integer the location within the $body where the next + * non-whitespace char is located. + */ +function tln_skipspace($body, $offset) +{ + preg_match('/^(\s*)/s', substr($body, $offset), $matches); + if (sizeof($matches[1])) { + $count = strlen($matches[1]); + $offset += $count; + } + return $offset; +} + +/** + * This function looks for the next character within a string. It's + * really just a glorified "strpos", except it catches the failures + * nicely. + * + * @param string $body The string to look for needle in. + * @param integer $offset Start looking from this position. + * @param string $needle The character/string to look for. + * @return integer location of the next occurrence of the needle, or + * strlen($body) if needle wasn't found. + */ +function tln_findnxstr($body, $offset, $needle) +{ + $pos = strpos($body, $needle, $offset); + if ($pos === false) { + $pos = strlen($body); + } + return $pos; +} + +/** + * This function takes a PCRE-style regexp and tries to match it + * within the string. + * + * @param string $body The string to look for needle in. + * @param integer $offset Start looking from here. + * @param string $reg A PCRE-style regex to match. + * @return array|boolean Returns a false if no matches found, or an array + * with the following members: + * - integer with the location of the match within $body + * - string with whatever content between offset and the match + * - string with whatever it is we matched + */ +function tln_findnxreg($body, $offset, $reg) +{ + $matches = array(); + $retarr = array(); + $preg_rule = '%^(.*?)(' . $reg . ')%s'; + preg_match($preg_rule, substr($body, $offset), $matches); + if (!isset($matches[0]) || !$matches[0]) { + $retarr = false; + } else { + $retarr[0] = $offset + strlen($matches[1]); + $retarr[1] = $matches[1]; + $retarr[2] = $matches[2]; + } + return $retarr; +} + +/** + * This function looks for the next tag. + * + * @param string $body String where to look for the next tag. + * @param integer $offset Start looking from here. + * @return array|boolean false if no more tags exist in the body, or + * an array with the following members: + * - string with the name of the tag + * - array with attributes and their values + * - integer with tag type (1, 2, or 3) + * - integer where the tag starts (starting "<") + * - integer where the tag ends (ending ">") + * first three members will be false, if the tag is invalid. + */ +function tln_getnxtag($body, $offset) +{ + if ($offset > strlen($body)) { + return false; + } + $lt = tln_findnxstr($body, $offset, '<'); + if ($lt == strlen($body)) { + return false; + } + /** + * We are here: + * blah blah <tag attribute="value"> + * \---------^ + */ + $pos = tln_skipspace($body, $lt + 1); + if ($pos >= strlen($body)) { + return array(false, false, false, $lt, strlen($body)); + } + /** + * There are 3 kinds of tags: + * 1. Opening tag, e.g.: + * <a href="blah"> + * 2. Closing tag, e.g.: + * </a> + * 3. XHTML-style content-less tag, e.g.: + * <img src="blah"/> + */ + switch (substr($body, $pos, 1)) { + case '/': + $tagtype = 2; + $pos++; + break; + case '!': + /** + * A comment or an SGML declaration. + */ + if (substr($body, $pos + 1, 2) == '--') { + $gt = strpos($body, '-->', $pos); + if ($gt === false) { + $gt = strlen($body); + } else { + $gt += 2; + } + return array(false, false, false, $lt, $gt); + } else { + $gt = tln_findnxstr($body, $pos, '>'); + return array(false, false, false, $lt, $gt); + } + break; + default: + /** + * Assume tagtype 1 for now. If it's type 3, we'll switch values + * later. + */ + $tagtype = 1; + break; + } + + /** + * Look for next [\W-_], which will indicate the end of the tag name. + */ + $regary = tln_findnxreg($body, $pos, '[^\w\-_]'); + if ($regary == false) { + return array(false, false, false, $lt, strlen($body)); + } + list($pos, $tagname, $match) = $regary; + $tagname = strtolower($tagname); + + /** + * $match can be either of these: + * '>' indicating the end of the tag entirely. + * '\s' indicating the end of the tag name. + * '/' indicating that this is type-3 xhtml tag. + * + * Whatever else we find there indicates an invalid tag. + */ + switch ($match) { + case '/': + /** + * This is an xhtml-style tag with a closing / at the + * end, like so: <img src="blah"/>. Check if it's followed + * by the closing bracket. If not, then this tag is invalid + */ + if (substr($body, $pos, 2) == '/>') { + $pos++; + $tagtype = 3; + } else { + $gt = tln_findnxstr($body, $pos, '>'); + $retary = array(false, false, false, $lt, $gt); + return $retary; + } + //intentional fall-through + case '>': + return array($tagname, false, $tagtype, $lt, $pos); + break; + default: + /** + * Check if it's whitespace + */ + if (!preg_match('/\s/', $match)) { + /** + * This is an invalid tag! Look for the next closing ">". + */ + $gt = tln_findnxstr($body, $lt, '>'); + return array(false, false, false, $lt, $gt); + } + break; + } + + /** + * At this point we're here: + * <tagname attribute='blah'> + * \-------^ + * + * At this point we loop in order to find all attributes. + */ + $attary = array(); + + while ($pos <= strlen($body)) { + $pos = tln_skipspace($body, $pos); + if ($pos == strlen($body)) { + /** + * Non-closed tag. + */ + return array(false, false, false, $lt, $pos); + } + /** + * See if we arrived at a ">" or "/>", which means that we reached + * the end of the tag. + */ + $matches = array(); + if (preg_match('%^(\s*)(>|/>)%s', substr($body, $pos), $matches)) { + /** + * Yep. So we did. + */ + $pos += strlen($matches[1]); + if ($matches[2] == '/>') { + $tagtype = 3; + $pos++; + } + return array($tagname, $attary, $tagtype, $lt, $pos); + } + + /** + * There are several types of attributes, with optional + * [:space:] between members. + * Type 1: + * attrname[:space:]=[:space:]'CDATA' + * Type 2: + * attrname[:space:]=[:space:]"CDATA" + * Type 3: + * attr[:space:]=[:space:]CDATA + * Type 4: + * attrname + * + * We leave types 1 and 2 the same, type 3 we check for + * '"' and convert to """ if needed, then wrap in + * double quotes. Type 4 we convert into: + * attrname="yes". + */ + $regary = tln_findnxreg($body, $pos, '[^\w\-_]'); + if ($regary == false) { + /** + * Looks like body ended before the end of tag. + */ + return array(false, false, false, $lt, strlen($body)); + } + list($pos, $attname, $match) = $regary; + $attname = strtolower($attname); + /** + * We arrived at the end of attribute name. Several things possible + * here: + * '>' means the end of the tag and this is attribute type 4 + * '/' if followed by '>' means the same thing as above + * '\s' means a lot of things -- look what it's followed by. + * anything else means the attribute is invalid. + */ + switch ($match) { + case '/': + /** + * This is an xhtml-style tag with a closing / at the + * end, like so: <img src="blah"/>. Check if it's followed + * by the closing bracket. If not, then this tag is invalid + */ + if (substr($body, $pos, 2) == '/>') { + $pos++; + $tagtype = 3; + } else { + $gt = tln_findnxstr($body, $pos, '>'); + $retary = array(false, false, false, $lt, $gt); + return $retary; + } + //intentional fall-through + case '>': + $attary{$attname} = '"yes"'; + return array($tagname, $attary, $tagtype, $lt, $pos); + break; + default: + /** + * Skip whitespace and see what we arrive at. + */ + $pos = tln_skipspace($body, $pos); + $char = substr($body, $pos, 1); + /** + * Two things are valid here: + * '=' means this is attribute type 1 2 or 3. + * \w means this was attribute type 4. + * anything else we ignore and re-loop. End of tag and + * invalid stuff will be caught by our checks at the beginning + * of the loop. + */ + if ($char == '=') { + $pos++; + $pos = tln_skipspace($body, $pos); + /** + * Here are 3 possibilities: + * "'" attribute type 1 + * '"' attribute type 2 + * everything else is the content of tag type 3 + */ + $quot = substr($body, $pos, 1); + if ($quot == '\'') { + $regary = tln_findnxreg($body, $pos + 1, '\''); + if ($regary == false) { + return array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + $pos++; + $attary{$attname} = '\'' . $attval . '\''; + } elseif ($quot == '"') { + $regary = tln_findnxreg($body, $pos + 1, '\"'); + if ($regary == false) { + return array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + $pos++; + $attary{$attname} = '"' . $attval . '"'; + } else { + /** + * These are hateful. Look for \s, or >. + */ + $regary = tln_findnxreg($body, $pos, '[\s>]'); + if ($regary == false) { + return array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + /** + * If it's ">" it will be caught at the top. + */ + $attval = preg_replace('/\"/s', '"', $attval); + $attary{$attname} = '"' . $attval . '"'; + } + } elseif (preg_match('|[\w/>]|', $char)) { + /** + * That was attribute type 4. + */ + $attary{$attname} = '"yes"'; + } else { + /** + * An illegal character. Find next '>' and return. + */ + $gt = tln_findnxstr($body, $pos, '>'); + return array(false, false, false, $lt, $gt); + } + break; + } + } + /** + * The fact that we got here indicates that the tag end was never + * found. Return invalid tag indication so it gets stripped. + */ + return array(false, false, false, $lt, strlen($body)); +} + +/** + * Translates entities into literal values so they can be checked. + * + * @param string $attvalue the by-ref value to check. + * @param string $regex the regular expression to check against. + * @param boolean $hex whether the entities are hexadecimal. + * @return boolean True or False depending on whether there were matches. + */ +function tln_deent(&$attvalue, $regex, $hex = false) +{ + preg_match_all($regex, $attvalue, $matches); + if (is_array($matches) && sizeof($matches[0]) > 0) { + $repl = array(); + for ($i = 0; $i < sizeof($matches[0]); $i++) { + $numval = $matches[1][$i]; + if ($hex) { + $numval = hexdec($numval); + } + $repl{$matches[0][$i]} = chr($numval); + } + $attvalue = strtr($attvalue, $repl); + return true; + } else { + return false; + } +} + +/** + * This function checks attribute values for entity-encoded values + * and returns them translated into 8-bit strings so we can run + * checks on them. + * + * @param string $attvalue A string to run entity check against. + */ +function tln_defang(&$attvalue) +{ + /** + * Skip this if there aren't ampersands or backslashes. + */ + if (strpos($attvalue, '&') === false + && strpos($attvalue, '\\') === false + ) { + return; + } + do { + $m = false; + $m = $m || tln_deent($attvalue, '/\�*(\d+);*/s'); + $m = $m || tln_deent($attvalue, '/\�*((\d|[a-f])+);*/si', true); + $m = $m || tln_deent($attvalue, '/\\\\(\d+)/s', true); + } while ($m == true); + $attvalue = stripslashes($attvalue); +} + +/** + * Kill any tabs, newlines, or carriage returns. Our friends the + * makers of the browser with 95% market value decided that it'd + * be funny to make "java[tab]script" be just as good as "javascript". + * + * @param string $attvalue The attribute value before extraneous spaces removed. + */ +function tln_unspace(&$attvalue) +{ + if (strcspn($attvalue, "\t\r\n\0 ") != strlen($attvalue)) { + $attvalue = str_replace( + array("\t", "\r", "\n", "\0", " "), + array('', '', '', '', ''), + $attvalue + ); + } +} + +/** + * This function runs various checks against the attributes. + * + * @param string $tagname String with the name of the tag. + * @param array $attary Array with all tag attributes. + * @param array $rm_attnames See description for tln_sanitize + * @param array $bad_attvals See description for tln_sanitize + * @param array $add_attr_to_tag See description for tln_sanitize + * @param string $trans_image_path + * @param boolean $block_external_images + * @return array with modified attributes. + */ +function tln_fixatts( + $tagname, + $attary, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag, + $trans_image_path, + $block_external_images +) { + foreach($attary as $attname => $attvalue) { + /** + * See if this attribute should be removed. + */ + foreach ($rm_attnames as $matchtag => $matchattrs) { + if (preg_match($matchtag, $tagname)) { + foreach ($matchattrs as $matchattr) { + if (preg_match($matchattr, $attname)) { + unset($attary{$attname}); + continue; + } + } + } + } + /** + * Remove any backslashes, entities, or extraneous whitespace. + */ + $oldattvalue = $attvalue; + tln_defang($attvalue); + if ($attname == 'style' && $attvalue !== $oldattvalue) { + $attvalue = "idiocy"; + $attary{$attname} = $attvalue; + } + tln_unspace($attvalue); + + /** + * Now let's run checks on the attvalues. + * I don't expect anyone to comprehend this. If you do, + * get in touch with me so I can drive to where you live and + * shake your hand personally. :) + */ + foreach ($bad_attvals as $matchtag => $matchattrs) { + if (preg_match($matchtag, $tagname)) { + foreach ($matchattrs as $matchattr => $valary) { + if (preg_match($matchattr, $attname)) { + /** + * There are two arrays in valary. + * First is matches. + * Second one is replacements + */ + list($valmatch, $valrepl) = $valary; + $newvalue = preg_replace($valmatch, $valrepl, $attvalue); + if ($newvalue != $attvalue) { + $attary{$attname} = $newvalue; + $attvalue = $newvalue; + } + } + } + } + } + if ($attname == 'style') { + if (preg_match('/[\0-\37\200-\377]+/', $attvalue)) { + $attary{$attname} = '"disallowed character"'; + } + preg_match_all("/url\s*\((.+)\)/si", $attvalue, $aMatch); + if (count($aMatch)) { + foreach($aMatch[1] as $sMatch) { + $urlvalue = $sMatch; + tln_fixurl($attname, $urlvalue, $trans_image_path, $block_external_images); + $attary{$attname} = str_replace($sMatch, $urlvalue, $attvalue); + } + } + } + } + /** + * See if we need to append any attributes to this tag. + */ + foreach ($add_attr_to_tag as $matchtag => $addattary) { + if (preg_match($matchtag, $tagname)) { + $attary = array_merge($attary, $addattary); + } + } + return $attary; +} + +function tln_fixurl($attname, &$attvalue, $trans_image_path, $block_external_images) +{ + $sQuote = '"'; + $attvalue = trim($attvalue); + if ($attvalue && ($attvalue[0] =='"'|| $attvalue[0] == "'")) { + // remove the double quotes + $sQuote = $attvalue[0]; + $attvalue = trim(substr($attvalue,1,-1)); + } + + /** + * Replace empty src tags with the blank image. src is only used + * for frames, images, and image inputs. Doing a replace should + * not affect them working as should be, however it will stop + * IE from being kicked off when src for img tags are not set + */ + if ($attvalue == '') { + $attvalue = $sQuote . $trans_image_path . $sQuote; + } else { + // first, disallow 8 bit characters and control characters + if (preg_match('/[\0-\37\200-\377]+/',$attvalue)) { + switch ($attname) { + case 'href': + $attvalue = $sQuote . 'http://invalid-stuff-detected.example.com' . $sQuote; + break; + default: + $attvalue = $sQuote . $trans_image_path . $sQuote; + break; + } + } else { + $aUrl = parse_url($attvalue); + if (isset($aUrl['scheme'])) { + switch(strtolower($aUrl['scheme'])) { + case 'mailto': + case 'http': + case 'https': + case 'ftp': + if ($attname != 'href') { + if ($block_external_images == true) { + $attvalue = $sQuote . $trans_image_path . $sQuote; + } else { + if (!isset($aUrl['path'])) { + $attvalue = $sQuote . $trans_image_path . $sQuote; + } + } + } else { + $attvalue = $sQuote . $attvalue . $sQuote; + } + break; + case 'outbind': + $attvalue = $sQuote . $attvalue . $sQuote; + break; + case 'cid': + $attvalue = $sQuote . $attvalue . $sQuote; + break; + default: + $attvalue = $sQuote . $trans_image_path . $sQuote; + break; + } + } else { + if (!isset($aUrl['path']) || $aUrl['path'] != $trans_image_path) { + $$attvalue = $sQuote . $trans_image_path . $sQuote; + } + } + } + } +} + +function tln_fixstyle($body, $pos, $trans_image_path, $block_external_images) +{ + // workaround for </style> in between comments + $content = ''; + $sToken = ''; + $bSucces = false; + $bEndTag = false; + for ($i=$pos,$iCount=strlen($body);$i<$iCount;++$i) { + $char = $body{$i}; + switch ($char) { + case '<': + $sToken = $char; + break; + case '/': + if ($sToken == '<') { + $sToken .= $char; + $bEndTag = true; + } else { + $content .= $char; + } + break; + case '>': + if ($bEndTag) { + $sToken .= $char; + if (preg_match('/\<\/\s*style\s*\>/i',$sToken,$aMatch)) { + $newpos = $i + 1; + $bSucces = true; + break 2; + } else { + $content .= $sToken; + } + $bEndTag = false; + } else { + $content .= $char; + } + break; + case '!': + if ($sToken == '<') { + // possible comment + if (isset($body{$i+2}) && substr($body,$i,3) == '!--') { + $i = strpos($body,'-->',$i+3); + if ($i === false) { // no end comment + $i = strlen($body); + } + $sToken = ''; + } + } else { + $content .= $char; + } + break; + default: + if ($bEndTag) { + $sToken .= $char; + } else { + $content .= $char; + } + break; + } + } + if ($bSucces == FALSE){ + return array(FALSE, strlen($body)); + } + + + + /** + * First look for general BODY style declaration, which would be + * like so: + * body {background: blah-blah} + * and change it to .bodyclass so we can just assign it to a <div> + */ + $content = preg_replace("|body(\s*\{.*?\})|si", ".bodyclass\\1", $content); + + /** + * Fix url('blah') declarations. + */ + // $content = preg_replace("|url\s*\(\s*([\'\"])\s*\S+script\s*:.*?([\'\"])\s*\)|si", + // "url(\\1$trans_image_path\\2)", $content); + + // first check for 8bit sequences and disallowed control characters + if (preg_match('/[\16-\37\200-\377]+/',$content)) { + $content = '<!-- style block removed by html filter due to presence of 8bit characters -->'; + return array($content, $newpos); + } + + // remove @import line + $content = preg_replace("/^\s*(@import.*)$/mi","\n<!-- @import rules forbidden -->\n",$content); + + $content = preg_replace("/(\\\\)?u(\\\\)?r(\\\\)?l(\\\\)?/i", 'url', $content); + preg_match_all("/url\s*\((.+)\)/si",$content,$aMatch); + if (count($aMatch)) { + $aValue = $aReplace = array(); + foreach($aMatch[1] as $sMatch) { + // url value + $urlvalue = $sMatch; + tln_fixurl('style',$urlvalue, $trans_image_path, $block_external_images); + $aValue[] = $sMatch; + $aReplace[] = $urlvalue; + } + $content = str_replace($aValue,$aReplace,$content); + } + + /** + * Remove any backslashes, entities, and extraneous whitespace. + */ + $contentTemp = $content; + tln_defang($contentTemp); + tln_unspace($contentTemp); + + $match = array('/\/\*.*\*\//', + '/expression/i', + '/behaviou*r/i', + '/binding/i', + '/include-source/i', + '/javascript/i', + '/script/i', + '/position/i'); + $replace = array('','idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', ''); + $contentNew = preg_replace($match, $replace, $contentTemp); + if ($contentNew !== $contentTemp) { + $content = $contentNew; + } + return array($content, $newpos); +} + +function tln_body2div($attary, $trans_image_path) +{ + $divattary = array('class' => "'bodyclass'"); + $text = '#000000'; + $has_bgc_stl = $has_txt_stl = false; + $styledef = ''; + if (is_array($attary) && sizeof($attary) > 0){ + foreach ($attary as $attname=>$attvalue){ + $quotchar = substr($attvalue, 0, 1); + $attvalue = str_replace($quotchar, "", $attvalue); + switch ($attname){ + case 'background': + $styledef .= "background-image: url('$trans_image_path'); "; + break; + case 'bgcolor': + $has_bgc_stl = true; + $styledef .= "background-color: $attvalue; "; + break; + case 'text': + $has_txt_stl = true; + $styledef .= "color: $attvalue; "; + break; + } + } + // Outlook defines a white bgcolor and no text color. This can lead to + // white text on a white bg with certain themes. + if ($has_bgc_stl && !$has_txt_stl) { + $styledef .= "color: $text; "; + } + if (strlen($styledef) > 0){ + $divattary{"style"} = "\"$styledef\""; + } + } + return $divattary; +} + +/** + * + * @param string $body The HTML you wish to filter + * @param array $tag_list see description above + * @param array $rm_tags_with_content see description above + * @param array $self_closing_tags see description above + * @param boolean $force_tag_closing see description above + * @param array $rm_attnames see description above + * @param array $bad_attvals see description above + * @param array $add_attr_to_tag see description above + * @param string $trans_image_path + * @param boolean $block_external_images + + * @return string Sanitized html safe to show on your pages. + */ +function tln_sanitize( + $body, + $tag_list, + $rm_tags_with_content, + $self_closing_tags, + $force_tag_closing, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag, + $trans_image_path, + $block_external_images +) { + /** + * Normalize rm_tags and rm_tags_with_content. + */ + $rm_tags = array_shift($tag_list); + @array_walk($tag_list, 'tln_casenormalize'); + @array_walk($rm_tags_with_content, 'tln_casenormalize'); + @array_walk($self_closing_tags, 'tln_casenormalize'); + /** + * See if tag_list is of tags to remove or tags to allow. + * false means remove these tags + * true means allow these tags + */ + $curpos = 0; + $open_tags = array(); + $trusted = "<!-- begin tln_sanitized html -->\n"; + $skip_content = false; + /** + * Take care of netscape's stupid javascript entities like + * &{alert('boo')}; + */ + $body = preg_replace('/&(\{.*?\};)/si', '&\\1', $body); + while (($curtag = tln_getnxtag($body, $curpos)) != false) { + list($tagname, $attary, $tagtype, $lt, $gt) = $curtag; + $free_content = substr($body, $curpos, $lt-$curpos); + /** + * Take care of <style> + */ + if ($tagname == "style" && $tagtype == 1){ + list($free_content, $curpos) = + tln_fixstyle($body, $gt+1, $trans_image_path, $block_external_images); + if ($free_content != FALSE){ + if ( !empty($attary) ) { + $attary = tln_fixatts($tagname, + $attary, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag, + $trans_image_path, + $block_external_images + ); + } + $trusted .= tln_tagprint($tagname, $attary, $tagtype); + $trusted .= $free_content; + $trusted .= tln_tagprint($tagname, null, 2); + } + continue; + } + if ($skip_content == false){ + $trusted .= $free_content; + } + if ($tagname != false) { + if ($tagtype == 2) { + if ($skip_content == $tagname) { + /** + * Got to the end of tag we needed to remove. + */ + $tagname = false; + $skip_content = false; + } else { + if ($skip_content == false) { + if ($tagname == "body") { + $tagname = "div"; + } + if (isset($open_tags{$tagname}) && + $open_tags{$tagname} > 0 + ) { + $open_tags{$tagname}--; + } else { + $tagname = false; + } + } + } + } else { + /** + * $rm_tags_with_content + */ + if ($skip_content == false) { + /** + * See if this is a self-closing type and change + * tagtype appropriately. + */ + if ($tagtype == 1 + && in_array($tagname, $self_closing_tags) + ) { + $tagtype = 3; + } + /** + * See if we should skip this tag and any content + * inside it. + */ + if ($tagtype == 1 + && in_array($tagname, $rm_tags_with_content) + ) { + $skip_content = $tagname; + } else { + if (($rm_tags == false + && in_array($tagname, $tag_list)) || + ($rm_tags == true + && !in_array($tagname, $tag_list)) + ) { + $tagname = false; + } else { + /** + * Convert body into div. + */ + if ($tagname == "body"){ + $tagname = "div"; + $attary = tln_body2div($attary, $trans_image_path); + } + if ($tagtype == 1) { + if (isset($open_tags{$tagname})) { + $open_tags{$tagname}++; + } else { + $open_tags{$tagname} = 1; + } + } + /** + * This is where we run other checks. + */ + if (is_array($attary) && sizeof($attary) > 0) { + $attary = tln_fixatts( + $tagname, + $attary, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag, + $trans_image_path, + $block_external_images + ); + } + } + } + } + } + if ($tagname != false && $skip_content == false) { + $trusted .= tln_tagprint($tagname, $attary, $tagtype); + } + } + $curpos = $gt + 1; + } + $trusted .= substr($body, $curpos, strlen($body) - $curpos); + if ($force_tag_closing == true) { + foreach ($open_tags as $tagname => $opentimes) { + while ($opentimes > 0) { + $trusted .= '</' . $tagname . '>'; + $opentimes--; + } + } + $trusted .= "\n"; + } + $trusted .= "<!-- end tln_sanitized html -->\n"; + return $trusted; +} + +// +// Use the nifty htmlfilter library +// + + +function HTMLFilter($body, $trans_image_path, $block_external_images = false) +{ + + $tag_list = array( + false, + "object", + "meta", + "html", + "head", + "base", + "link", + "frame", + "iframe", + "plaintext", + "marquee" + ); + + $rm_tags_with_content = array( + "script", + "applet", + "embed", + "title", + "frameset", + "xmp", + "xml" + ); + + $self_closing_tags = array( + "img", + "br", + "hr", + "input", + "outbind" + ); + + $force_tag_closing = true; + + $rm_attnames = array( + "/.*/" => + array( + // "/target/i", + "/^on.*/i", + "/^dynsrc/i", + "/^data.*/i", + "/^lowsrc.*/i" + ) + ); + + $bad_attvals = array( + "/.*/" => + array( + "/^src|background/i" => + array( + array( + '/^([\'"])\s*\S+script\s*:.*([\'"])/si', + '/^([\'"])\s*mocha\s*:*.*([\'"])/si', + '/^([\'"])\s*about\s*:.*([\'"])/si' + ), + array( + "\\1$trans_image_path\\2", + "\\1$trans_image_path\\2", + "\\1$trans_image_path\\2" + ) + ), + "/^href|action/i" => + array( + array( + '/^([\'"])\s*\S+script\s*:.*([\'"])/si', + '/^([\'"])\s*mocha\s*:*.*([\'"])/si', + '/^([\'"])\s*about\s*:.*([\'"])/si' + ), + array( + "\\1#\\1", + "\\1#\\1", + "\\1#\\1" + ) + ), + "/^style/i" => + array( + array( + "/\/\*.*\*\//", + "/expression/i", + "/binding/i", + "/behaviou*r/i", + "/include-source/i", + '/position\s*:/i', + '/(\\\\)?u(\\\\)?r(\\\\)?l(\\\\)?/i', + '/url\s*\(\s*([\'"])\s*\S+script\s*:.*([\'"])\s*\)/si', + '/url\s*\(\s*([\'"])\s*mocha\s*:.*([\'"])\s*\)/si', + '/url\s*\(\s*([\'"])\s*about\s*:.*([\'"])\s*\)/si', + '/(.*)\s*:\s*url\s*\(\s*([\'"]*)\s*\S+script\s*:.*([\'"]*)\s*\)/si' + ), + array( + "", + "idiocy", + "idiocy", + "idiocy", + "idiocy", + "idiocy", + "url", + "url(\\1#\\1)", + "url(\\1#\\1)", + "url(\\1#\\1)", + "\\1:url(\\2#\\3)" + ) + ) + ) + ); + + if ($block_external_images) { + array_push( + $bad_attvals{'/.*/'}{'/^src|background/i'}[0], + '/^([\'\"])\s*https*:.*([\'\"])/si' + ); + array_push( + $bad_attvals{'/.*/'}{'/^src|background/i'}[1], + "\\1$trans_image_path\\1" + ); + array_push( + $bad_attvals{'/.*/'}{'/^style/i'}[0], + '/url\(([\'\"])\s*https*:.*([\'\"])\)/si' + ); + array_push( + $bad_attvals{'/.*/'}{'/^style/i'}[1], + "url(\\1$trans_image_path\\1)" + ); + } + + $add_attr_to_tag = array( + "/^a$/i" => + array('target' => '"_blank"') + ); + + $trusted = tln_sanitize( + $body, + $tag_list, + $rm_tags_with_content, + $self_closing_tags, + $force_tag_closing, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag, + $trans_image_path, + $block_external_images + ); + return $trusted; +} diff --git a/vas/rest/class/PHPMailer/extras/ntlm_sasl_client.php b/vas/rest/class/PHPMailer/extras/ntlm_sasl_client.php new file mode 100755 index 0000000000000000000000000000000000000000..3fd539240f70fa0deb76754deb08cb3bcbd71e57 --- /dev/null +++ b/vas/rest/class/PHPMailer/extras/ntlm_sasl_client.php @@ -0,0 +1,185 @@ +<?php +/* + * ntlm_sasl_client.php + * + * @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $ + * + */ + +define("SASL_NTLM_STATE_START", 0); +define("SASL_NTLM_STATE_IDENTIFY_DOMAIN", 1); +define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2); +define("SASL_NTLM_STATE_DONE", 3); +define("SASL_FAIL", -1); +define("SASL_CONTINUE", 1); + +class ntlm_sasl_client_class +{ + public $credentials = array(); + public $state = SASL_NTLM_STATE_START; + + public function initialize(&$client) + { + if (!function_exists($function = "mcrypt_encrypt") + || !function_exists($function = "mhash") + ) { + $extensions = array( + "mcrypt_encrypt" => "mcrypt", + "mhash" => "mhash" + ); + $client->error = "the extension " . $extensions[$function] . + " required by the NTLM SASL client class is not available in this PHP configuration"; + return (0); + } + return (1); + } + + public function ASCIIToUnicode($ascii) + { + for ($unicode = "", $a = 0; $a < strlen($ascii); $a++) { + $unicode .= substr($ascii, $a, 1) . chr(0); + } + return ($unicode); + } + + public function typeMsg1($domain, $workstation) + { + $domain_length = strlen($domain); + $workstation_length = strlen($workstation); + $workstation_offset = 32; + $domain_offset = $workstation_offset + $workstation_length; + return ( + "NTLMSSP\0" . + "\x01\x00\x00\x00" . + "\x07\x32\x00\x00" . + pack("v", $domain_length) . + pack("v", $domain_length) . + pack("V", $domain_offset) . + pack("v", $workstation_length) . + pack("v", $workstation_length) . + pack("V", $workstation_offset) . + $workstation . + $domain + ); + } + + public function NTLMResponse($challenge, $password) + { + $unicode = $this->ASCIIToUnicode($password); + $md4 = mhash(MHASH_MD4, $unicode); + $padded = $md4 . str_repeat(chr(0), 21 - strlen($md4)); + $iv_size = mcrypt_get_iv_size(MCRYPT_DES, MCRYPT_MODE_ECB); + $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); + for ($response = "", $third = 0; $third < 21; $third += 7) { + for ($packed = "", $p = $third; $p < $third + 7; $p++) { + $packed .= str_pad(decbin(ord(substr($padded, $p, 1))), 8, "0", STR_PAD_LEFT); + } + for ($key = "", $p = 0; $p < strlen($packed); $p += 7) { + $s = substr($packed, $p, 7); + $b = $s . ((substr_count($s, "1") % 2) ? "0" : "1"); + $key .= chr(bindec($b)); + } + $ciphertext = mcrypt_encrypt(MCRYPT_DES, $key, $challenge, MCRYPT_MODE_ECB, $iv); + $response .= $ciphertext; + } + return $response; + } + + public function typeMsg3($ntlm_response, $user, $domain, $workstation) + { + $domain_unicode = $this->ASCIIToUnicode($domain); + $domain_length = strlen($domain_unicode); + $domain_offset = 64; + $user_unicode = $this->ASCIIToUnicode($user); + $user_length = strlen($user_unicode); + $user_offset = $domain_offset + $domain_length; + $workstation_unicode = $this->ASCIIToUnicode($workstation); + $workstation_length = strlen($workstation_unicode); + $workstation_offset = $user_offset + $user_length; + $lm = ""; + $lm_length = strlen($lm); + $lm_offset = $workstation_offset + $workstation_length; + $ntlm = $ntlm_response; + $ntlm_length = strlen($ntlm); + $ntlm_offset = $lm_offset + $lm_length; + $session = ""; + $session_length = strlen($session); + $session_offset = $ntlm_offset + $ntlm_length; + return ( + "NTLMSSP\0" . + "\x03\x00\x00\x00" . + pack("v", $lm_length) . + pack("v", $lm_length) . + pack("V", $lm_offset) . + pack("v", $ntlm_length) . + pack("v", $ntlm_length) . + pack("V", $ntlm_offset) . + pack("v", $domain_length) . + pack("v", $domain_length) . + pack("V", $domain_offset) . + pack("v", $user_length) . + pack("v", $user_length) . + pack("V", $user_offset) . + pack("v", $workstation_length) . + pack("v", $workstation_length) . + pack("V", $workstation_offset) . + pack("v", $session_length) . + pack("v", $session_length) . + pack("V", $session_offset) . + "\x01\x02\x00\x00" . + $domain_unicode . + $user_unicode . + $workstation_unicode . + $lm . + $ntlm + ); + } + + public function start(&$client, &$message, &$interactions) + { + if ($this->state != SASL_NTLM_STATE_START) { + $client->error = "NTLM authentication state is not at the start"; + return (SASL_FAIL); + } + $this->credentials = array( + "user" => "", + "password" => "", + "realm" => "", + "workstation" => "" + ); + $defaults = array(); + $status = $client->GetCredentials($this->credentials, $defaults, $interactions); + if ($status == SASL_CONTINUE) { + $this->state = SASL_NTLM_STATE_IDENTIFY_DOMAIN; + } + unset($message); + return ($status); + } + + public function step(&$client, $response, &$message, &$interactions) + { + switch ($this->state) { + case SASL_NTLM_STATE_IDENTIFY_DOMAIN: + $message = $this->typeMsg1($this->credentials["realm"], $this->credentials["workstation"]); + $this->state = SASL_NTLM_STATE_RESPOND_CHALLENGE; + break; + case SASL_NTLM_STATE_RESPOND_CHALLENGE: + $ntlm_response = $this->NTLMResponse(substr($response, 24, 8), $this->credentials["password"]); + $message = $this->typeMsg3( + $ntlm_response, + $this->credentials["user"], + $this->credentials["realm"], + $this->credentials["workstation"] + ); + $this->state = SASL_NTLM_STATE_DONE; + break; + case SASL_NTLM_STATE_DONE: + $client->error = "NTLM authentication was finished without success"; + return (SASL_FAIL); + default: + $client->error = "invalid NTLM authentication step state"; + return (SASL_FAIL); + } + return (SASL_CONTINUE); + } +} diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-am.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-am.php new file mode 100755 index 0000000000000000000000000000000000000000..ff2a969501f581d10fd4098cc904809277cf1ad6 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-am.php @@ -0,0 +1,26 @@ +<?php +/** + * Armenian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Hrayr Grigoryan <hrayr@bits.am> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP -ի սխալ: չհաջողվեց ստուգել իսկությունը.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP -ի սխալ: չհաջողվեց կապ հաստատել SMTP սերվերի հետ.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP -ի սխալ: տվյալները ընդունված չեն.'; +$PHPMAILER_LANG['empty_message'] = 'Հաղորդագրությունը դատարկ է'; +$PHPMAILER_LANG['encoding'] = 'Կոդավորման անհայտ տեսակ: '; +$PHPMAILER_LANG['execute'] = 'Չհաջողվեց իրականացնել հրամանը: '; +$PHPMAILER_LANG['file_access'] = 'Ֆայլը հասանելի չէ: '; +$PHPMAILER_LANG['file_open'] = 'Ֆայլի սխալ: ֆայլը չհաջողվեց բացել: '; +$PHPMAILER_LANG['from_failed'] = 'Ուղարկողի հետևյալ հասցեն սխալ է: '; +$PHPMAILER_LANG['instantiate'] = 'Հնարավոր չէ կանչել mail ֆունկցիան.'; +$PHPMAILER_LANG['invalid_address'] = 'Հասցեն սխալ է: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' փոստային սերվերի հետ չի աշխատում.'; +$PHPMAILER_LANG['provide_address'] = 'Անհրաժեշտ է տրամադրել գոնե մեկ ստացողի e-mail հասցե.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP -ի սխալ: չի հաջողվել ուղարկել հետևյալ ստացողների հասցեներին: '; +$PHPMAILER_LANG['signing'] = 'Ստորագրման սխալ: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP -ի connect() ֆունկցիան չի հաջողվել'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP սերվերի սխալ: '; +$PHPMAILER_LANG['variable_set'] = 'Չի հաջողվում ստեղծել կամ վերափոխել փոփոխականը: '; +$PHPMAILER_LANG['extension_missing'] = 'Հավելվածը բացակայում է: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ar.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ar.php new file mode 100755 index 0000000000000000000000000000000000000000..790e2a5ec81b86aaae05b2b543d717702b6e7fbe --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ar.php @@ -0,0 +1,27 @@ +<?php +/** + * Arabic PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author bahjat al mostafa <bahjat983@hotmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'خطأ SMTP : لا يمكن تأكيد الهوية.'; +$PHPMAILER_LANG['connect_host'] = 'خطأ SMTP: لا يمكن الاتصال بالخادم SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'خطأ SMTP: لم يتم قبول المعلومات .'; +$PHPMAILER_LANG['empty_message'] = 'نص الرسالة فارغ'; +$PHPMAILER_LANG['encoding'] = 'ترميز غير معروف: '; +$PHPMAILER_LANG['execute'] = 'لا يمكن تنفيذ : '; +$PHPMAILER_LANG['file_access'] = 'لا يمكن الوصول للملف: '; +$PHPMAILER_LANG['file_open'] = 'خطأ في الملف: لا يمكن فتحه: '; +$PHPMAILER_LANG['from_failed'] = 'خطأ على مستوى عنوان المرسل : '; +$PHPMAILER_LANG['instantiate'] = 'لا يمكن توفير خدمة البريد.'; +$PHPMAILER_LANG['invalid_address'] = 'الإرسال غير ممكن لأن عنوان البريد الإلكتروني غير صالح: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' برنامج الإرسال غير مدعوم.'; +$PHPMAILER_LANG['provide_address'] = 'يجب توفير عنوان البريد الإلكتروني لمستلم واحد على الأقل.'; +$PHPMAILER_LANG['recipients_failed'] = 'خطأ SMTP: الأخطاء التالية ' . + 'فشل في الارسال لكل من : '; +$PHPMAILER_LANG['signing'] = 'خطأ في التوقيع: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() غير ممكن.'; +$PHPMAILER_LANG['smtp_error'] = 'خطأ على مستوى الخادم SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'لا يمكن تعيين أو إعادة تعيين متغير: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-az.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-az.php new file mode 100755 index 0000000000000000000000000000000000000000..3749d83d603cb6c35e09c42428e043de4acb9e9c --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-az.php @@ -0,0 +1,26 @@ +<?php +/** + * Azerbaijani PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author @mirjalal + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP xətası: Giriş uğursuz oldu.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP xətası: SMTP serverinə qoşulma uğursuz oldu.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP xətası: Verilənlər qəbul edilməyib.'; +$PHPMAILER_LANG['empty_message'] = 'Boş mesaj göndərilə bilməz.'; +$PHPMAILER_LANG['encoding'] = 'Qeyri-müəyyən kodlaşdırma: '; +$PHPMAILER_LANG['execute'] = 'Əmr yerinə yetirilmədi: '; +$PHPMAILER_LANG['file_access'] = 'Fayla giriş yoxdur: '; +$PHPMAILER_LANG['file_open'] = 'Fayl xətası: Fayl açıla bilmədi: '; +$PHPMAILER_LANG['from_failed'] = 'Göstərilən poçtlara göndərmə uğursuz oldu: '; +$PHPMAILER_LANG['instantiate'] = 'Mail funksiyası işə salına bilmədi.'; +$PHPMAILER_LANG['invalid_address'] = 'Düzgün olmayan e-mail adresi: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' - e-mail kitabxanası dəstəklənmir.'; +$PHPMAILER_LANG['provide_address'] = 'Ən azı bir e-mail adresi daxil edilməlidir.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP xətası: Aşağıdakı ünvanlar üzrə alıcılara göndərmə uğursuzdur: '; +$PHPMAILER_LANG['signing'] = 'İmzalama xətası: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP serverinə qoşulma uğursuz oldu.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP serveri xətası: '; +$PHPMAILER_LANG['variable_set'] = 'Dəyişənin quraşdırılması uğursuz oldu: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ba.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ba.php new file mode 100755 index 0000000000000000000000000000000000000000..576c4bb53439c6b0086608885fc9d403790eb895 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ba.php @@ -0,0 +1,26 @@ +<?php +/** + * Bosnian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Ermin Islamagić <ermin@islamagic.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Greška: Neuspjela prijava.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Greška: Nije moguće spojiti se sa SMTP serverom.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Greška: Podatci nisu prihvaćeni.'; +$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznata kriptografija: '; +$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: '; +$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: '; +$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP Greška: Slanje sa navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Greška: Slanje na navedene e-mail adrese nije uspjelo: '; +$PHPMAILER_LANG['instantiate'] = 'Ne mogu pokrenuti mail funkcionalnost.'; +$PHPMAILER_LANG['invalid_address'] = 'E-mail nije poslan. Neispravna e-mail adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nije podržan.'; +$PHPMAILER_LANG['provide_address'] = 'Definišite barem jednu adresu primaoca.'; +$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Spajanje na SMTP server nije uspjelo.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP greška: '; +$PHPMAILER_LANG['variable_set'] = 'Nije moguće postaviti varijablu ili je vratiti nazad: '; +$PHPMAILER_LANG['extension_missing'] = 'Nedostaje ekstenzija: '; \ No newline at end of file diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-be.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-be.php new file mode 100755 index 0000000000000000000000000000000000000000..e2f98f0f6d9d924986266b5ff2d543429f79fb31 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-be.php @@ -0,0 +1,26 @@ +<?php +/** + * Belarusian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Aleksander Maksymiuk <info@setpro.pl> + */ + +$PHPMAILER_LANG['authenticate'] = 'Памылка SMTP: памылка ідэнтыфікацыі.'; +$PHPMAILER_LANG['connect_host'] = 'Памылка SMTP: нельга ўстанавіць сувязь з SMTP-серверам.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Памылка SMTP: звесткі непрынятыя.'; +$PHPMAILER_LANG['empty_message'] = 'Пустое паведамленне.'; +$PHPMAILER_LANG['encoding'] = 'Невядомая кадыроўка тэксту: '; +$PHPMAILER_LANG['execute'] = 'Нельга выканаць каманду: '; +$PHPMAILER_LANG['file_access'] = 'Няма доступу да файла: '; +$PHPMAILER_LANG['file_open'] = 'Нельга адкрыць файл: '; +$PHPMAILER_LANG['from_failed'] = 'Няправільны адрас адпраўніка: '; +$PHPMAILER_LANG['instantiate'] = 'Нельга прымяніць функцыю mail().'; +$PHPMAILER_LANG['invalid_address'] = 'Нельга даслаць паведамленне, няправільны email атрымальніка: '; +$PHPMAILER_LANG['provide_address'] = 'Запоўніце, калі ласка, правільны email атрымальніка.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - паштовы сервер не падтрымліваецца.'; +$PHPMAILER_LANG['recipients_failed'] = 'Памылка SMTP: няправільныя атрымальнікі: '; +$PHPMAILER_LANG['signing'] = 'Памылка подпісу паведамлення: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Памылка сувязі з SMTP-серверам.'; +$PHPMAILER_LANG['smtp_error'] = 'Памылка SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Нельга ўстанавіць або перамяніць значэнне пераменнай: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-bg.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-bg.php new file mode 100755 index 0000000000000000000000000000000000000000..b22941f6b57f7ca0995f44dde1f3e79ef23d8792 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-bg.php @@ -0,0 +1,26 @@ +<?php +/** + * Bulgarian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Mikhail Kyosev <mialygk@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP грешка: Не може да се удостовери пред сървъра.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP грешка: Не може да се свърже с SMTP хоста.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP грешка: данните не са приети.'; +$PHPMAILER_LANG['empty_message'] = 'Съдържанието на съобщението е празно'; +$PHPMAILER_LANG['encoding'] = 'Неизвестно кодиране: '; +$PHPMAILER_LANG['execute'] = 'Не може да се изпълни: '; +$PHPMAILER_LANG['file_access'] = 'Няма достъп до файл: '; +$PHPMAILER_LANG['file_open'] = 'Файлова грешка: Не може да се отвори файл: '; +$PHPMAILER_LANG['from_failed'] = 'Следните адреси за подател са невалидни: '; +$PHPMAILER_LANG['instantiate'] = 'Не може да се инстанцира функцията mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Невалиден адрес: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' - пощенски сървър не се поддържа.'; +$PHPMAILER_LANG['provide_address'] = 'Трябва да предоставите поне един email адрес за получател.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP грешка: Следните адреси за Получател са невалидни: '; +$PHPMAILER_LANG['signing'] = 'Грешка при подписване: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP провален connect().'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP сървърна грешка: '; +$PHPMAILER_LANG['variable_set'] = 'Не може да се установи или възстанови променлива: '; +$PHPMAILER_LANG['extension_missing'] = 'Липсва разширение: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ca.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ca.php new file mode 100755 index 0000000000000000000000000000000000000000..4117596c6f1ea30712659094731175417bacb31f --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ca.php @@ -0,0 +1,26 @@ +<?php +/** + * Catalan PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Ivan <web AT microstudi DOT com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Error SMTP: No s’ha pogut autenticar.'; +$PHPMAILER_LANG['connect_host'] = 'Error SMTP: No es pot connectar al servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Dades no acceptades.'; +$PHPMAILER_LANG['empty_message'] = 'El cos del missatge està buit.'; +$PHPMAILER_LANG['encoding'] = 'Codificació desconeguda: '; +$PHPMAILER_LANG['execute'] = 'No es pot executar: '; +$PHPMAILER_LANG['file_access'] = 'No es pot accedir a l’arxiu: '; +$PHPMAILER_LANG['file_open'] = 'Error d’Arxiu: No es pot obrir l’arxiu: '; +$PHPMAILER_LANG['from_failed'] = 'La(s) següent(s) adreces de remitent han fallat: '; +$PHPMAILER_LANG['instantiate'] = 'No s’ha pogut crear una instància de la funció Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Adreça d’email invalida: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no està suportat'; +$PHPMAILER_LANG['provide_address'] = 'S’ha de proveir almenys una adreça d’email com a destinatari.'; +$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Els següents destinataris han fallat: '; +$PHPMAILER_LANG['signing'] = 'Error al signar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ha fallat el SMTP Connect().'; +$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'No s’ha pogut establir o restablir la variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ch.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ch.php new file mode 100755 index 0000000000000000000000000000000000000000..4fda6b85d7f3425fe136abecc77c644e6b668410 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ch.php @@ -0,0 +1,26 @@ +<?php +/** + * Chinese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author LiuXin <http://www.80x86.cn/blog/> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:身份验证失败。'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 错误: 不能连接SMTP主机。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误: 数据不可接受。'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '未知编码:'; +$PHPMAILER_LANG['execute'] = '不能执行: '; +$PHPMAILER_LANG['file_access'] = '不能访问文件:'; +$PHPMAILER_LANG['file_open'] = '文件错误:不能打开文件:'; +$PHPMAILER_LANG['from_failed'] = '下面的发送地址邮件发送失败了: '; +$PHPMAILER_LANG['instantiate'] = '不能实现mail方法。'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' 您所选择的发送邮件的方法并不支持。'; +$PHPMAILER_LANG['provide_address'] = '您必须提供至少一个 收信人的email地址。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误: 下面的 收件人失败了: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-cs.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-cs.php new file mode 100755 index 0000000000000000000000000000000000000000..1160cf0cc4a162eb0fc2c3de9eace53d611d4920 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-cs.php @@ -0,0 +1,25 @@ +<?php +/** + * Czech PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'Chyba SMTP: Autentizace selhala.'; +$PHPMAILER_LANG['connect_host'] = 'Chyba SMTP: Nelze navázat spojení se SMTP serverem.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Chyba SMTP: Data nebyla přijata.'; +$PHPMAILER_LANG['empty_message'] = 'Prázdné tělo zprávy'; +$PHPMAILER_LANG['encoding'] = 'Neznámé kódování: '; +$PHPMAILER_LANG['execute'] = 'Nelze provést: '; +$PHPMAILER_LANG['file_access'] = 'Nelze získat přístup k souboru: '; +$PHPMAILER_LANG['file_open'] = 'Chyba souboru: Nelze otevřít soubor pro čtení: '; +$PHPMAILER_LANG['from_failed'] = 'Následující adresa odesílatele je nesprávná: '; +$PHPMAILER_LANG['instantiate'] = 'Nelze vytvořit instanci emailové funkce.'; +$PHPMAILER_LANG['invalid_address'] = 'Neplatná adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer není podporován.'; +$PHPMAILER_LANG['provide_address'] = 'Musíte zadat alespoň jednu emailovou adresu příjemce.'; +$PHPMAILER_LANG['recipients_failed'] = 'Chyba SMTP: Následující adresy příjemců nejsou správně: '; +$PHPMAILER_LANG['signing'] = 'Chyba přihlašování: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() selhal.'; +$PHPMAILER_LANG['smtp_error'] = 'Chyba SMTP serveru: '; +$PHPMAILER_LANG['variable_set'] = 'Nelze nastavit nebo změnit proměnnou: '; +$PHPMAILER_LANG['extension_missing'] = 'Chybí rozšíření: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-da.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-da.php new file mode 100755 index 0000000000000000000000000000000000000000..e725f4b477c86455458a2f75d68e3fc776045503 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-da.php @@ -0,0 +1,26 @@ +<?php +/** + * Danish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Mikael Stokkebro <info@stokkebro.dk> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Kunne ikke logge på.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data kunne ikke accepteres.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunne ikke køre: '; +$PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; +$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; +$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; +$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-de.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-de.php new file mode 100755 index 0000000000000000000000000000000000000000..aa987a9caffde62fbcc3b5f2391e978772f9c102 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-de.php @@ -0,0 +1,25 @@ +<?php +/** + * German PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP-Fehler: Authentifizierung fehlgeschlagen.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP-Fehler: Konnte keine Verbindung zum SMTP-Host herstellen.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-Fehler: Daten werden nicht akzeptiert.'; +$PHPMAILER_LANG['empty_message'] = 'E-Mail-Inhalt ist leer.'; +$PHPMAILER_LANG['encoding'] = 'Unbekannte Kodierung: '; +$PHPMAILER_LANG['execute'] = 'Konnte folgenden Befehl nicht ausführen: '; +$PHPMAILER_LANG['file_access'] = 'Zugriff auf folgende Datei fehlgeschlagen: '; +$PHPMAILER_LANG['file_open'] = 'Dateifehler: Konnte folgende Datei nicht öffnen: '; +$PHPMAILER_LANG['from_failed'] = 'Die folgende Absenderadresse ist nicht korrekt: '; +$PHPMAILER_LANG['instantiate'] = 'Mail-Funktion konnte nicht initialisiert werden.'; +$PHPMAILER_LANG['invalid_address'] = 'Die Adresse ist ungültig: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wird nicht unterstützt.'; +$PHPMAILER_LANG['provide_address'] = 'Bitte geben Sie mindestens eine Empfängeradresse an.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP-Fehler: Die folgenden Empfänger sind nicht korrekt: '; +$PHPMAILER_LANG['signing'] = 'Fehler beim Signieren: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Verbindung zum SMTP-Server fehlgeschlagen.'; +$PHPMAILER_LANG['smtp_error'] = 'Fehler vom SMTP-Server: '; +$PHPMAILER_LANG['variable_set'] = 'Kann Variable nicht setzen oder zurücksetzen: '; +$PHPMAILER_LANG['extension_missing'] = 'Fehlende Erweiterung: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-el.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-el.php new file mode 100755 index 0000000000000000000000000000000000000000..7109641e49741d0151915cbb4d22301b33616229 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-el.php @@ -0,0 +1,25 @@ +<?php +/** + * Greek PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Σφάλμα: Αδυναμία πιστοποίησης (authentication).'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Σφάλμα: Αδυναμία σύνδεσης στον SMTP-Host.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Σφάλμα: Τα δεδομένα δεν έγιναν αποδεκτά.'; +$PHPMAILER_LANG['empty_message'] = 'Το E-Mail δεν έχει περιεχόμενο .'; +$PHPMAILER_LANG['encoding'] = 'Αγνωστο Encoding-Format: '; +$PHPMAILER_LANG['execute'] = 'Αδυναμία εκτέλεσης ακόλουθης εντολής: '; +$PHPMAILER_LANG['file_access'] = 'Αδυναμία προσπέλασης του αρχείου: '; +$PHPMAILER_LANG['file_open'] = 'Σφάλμα Αρχείου: Δεν είναι δυνατό το άνοιγμα του ακόλουθου αρχείου: '; +$PHPMAILER_LANG['from_failed'] = 'Η παρακάτω διεύθυνση αποστολέα δεν είναι σωστή: '; +$PHPMAILER_LANG['instantiate'] = 'Αδυναμία εκκίνησης Mail function.'; +$PHPMAILER_LANG['invalid_address'] = 'Το μήνυμα δεν εστάλη, η διεύθυνση δεν είναι έγκυρη: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer δεν υποστηρίζεται.'; +$PHPMAILER_LANG['provide_address'] = 'Παρακαλούμε δώστε τουλάχιστον μια e-mail διεύθυνση παραλήπτη.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Σφάλμα: Οι παρακάτω διευθύνσεις παραλήπτη δεν είναι έγκυρες: '; +$PHPMAILER_LANG['signing'] = 'Σφάλμα υπογραφής: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Αποτυχία σύνδεσης στον SMTP Server.'; +$PHPMAILER_LANG['smtp_error'] = 'Σφάλμα από τον SMTP Server: '; +$PHPMAILER_LANG['variable_set'] = 'Αδυναμία ορισμού ή αρχικοποίησης μεταβλητής: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-eo.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-eo.php new file mode 100755 index 0000000000000000000000000000000000000000..5ca6cb709525f511c4c7041b8d49a7c73a10bf39 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-eo.php @@ -0,0 +1,25 @@ +<?php +/** + * Esperanto PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'Eraro de servilo SMTP : aŭtentigo malsukcesis.'; +$PHPMAILER_LANG['connect_host'] = 'Eraro de servilo SMTP : konektado al servilo malsukcesis.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Eraro de servilo SMTP : neĝustaj datumoj.'; +$PHPMAILER_LANG['empty_message'] = 'Teksto de mesaĝo mankas.'; +$PHPMAILER_LANG['encoding'] = 'Nekonata kodoprezento: '; +$PHPMAILER_LANG['execute'] = 'Lanĉi rulumadon ne eblis: '; +$PHPMAILER_LANG['file_access'] = 'Aliro al dosiero ne sukcesis: '; +$PHPMAILER_LANG['file_open'] = 'Eraro de dosiero: malfermo neeblas: '; +$PHPMAILER_LANG['from_failed'] = 'Jena adreso de sendinto malsukcesis: '; +$PHPMAILER_LANG['instantiate'] = 'Genero de retmesaĝa funkcio neeblis.'; +$PHPMAILER_LANG['invalid_address'] = 'Retadreso ne validas: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mesaĝilo ne subtenata.'; +$PHPMAILER_LANG['provide_address'] = 'Vi devas tajpi almenaŭ unu recevontan retadreson.'; +$PHPMAILER_LANG['recipients_failed'] = 'Eraro de servilo SMTP : la jenaj poŝtrecivuloj kaŭzis eraron: '; +$PHPMAILER_LANG['signing'] = 'Eraro de subskribo: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP konektado malsukcesis.'; +$PHPMAILER_LANG['smtp_error'] = 'Eraro de servilo SMTP : '; +$PHPMAILER_LANG['variable_set'] = 'Variablo ne pravalorizeblas aŭ ne repravalorizeblas: '; +$PHPMAILER_LANG['extension_missing'] = 'Mankas etendo: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-es.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-es.php new file mode 100755 index 0000000000000000000000000000000000000000..f2c4e8316c0939ce7e8cc5e8589549c463af3353 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-es.php @@ -0,0 +1,26 @@ +<?php +/** + * Spanish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Matt Sturdy <matt.sturdy@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.'; +$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.'; +$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.'; +$PHPMAILER_LANG['encoding'] = 'Codificación desconocida: '; +$PHPMAILER_LANG['execute'] = 'Imposible ejecutar: '; +$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: '; +$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: '; +$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: '; +$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.'; +$PHPMAILER_LANG['provide_address'] = 'Debe proporcionar al menos una dirección de email de destino.'; +$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinos fallaron: '; +$PHPMAILER_LANG['signing'] = 'Error al firmar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.'; +$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-et.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-et.php new file mode 100755 index 0000000000000000000000000000000000000000..7e06da13e615def00230e0f6db96ee1c284c1d70 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-et.php @@ -0,0 +1,27 @@ +<?php +/** + * Estonian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Indrek Päri + * @author Elan Ruusamäe <glen@delfi.ee> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Viga: Autoriseerimise viga.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Viga: Ei õnnestunud luua ühendust SMTP serveriga.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Viga: Vigased andmed.'; +$PHPMAILER_LANG['empty_message'] = 'Tühi kirja sisu'; +$PHPMAILER_LANG["encoding"] = 'Tundmatu kodeering: '; +$PHPMAILER_LANG['execute'] = 'Tegevus ebaõnnestus: '; +$PHPMAILER_LANG['file_access'] = 'Pole piisavalt õiguseid järgneva faili avamiseks: '; +$PHPMAILER_LANG['file_open'] = 'Faili Viga: Faili avamine ebaõnnestus: '; +$PHPMAILER_LANG['from_failed'] = 'Järgnev saatja e-posti aadress on vigane: '; +$PHPMAILER_LANG['instantiate'] = 'mail funktiooni käivitamine ebaõnnestus.'; +$PHPMAILER_LANG['invalid_address'] = 'Saatmine peatatud, e-posti address vigane: '; +$PHPMAILER_LANG['provide_address'] = 'Te peate määrama vähemalt ühe saaja e-posti aadressi.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' maileri tugi puudub.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Viga: Järgnevate saajate e-posti aadressid on vigased: '; +$PHPMAILER_LANG["signing"] = 'Viga allkirjastamisel: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() ebaõnnestus.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP serveri viga: '; +$PHPMAILER_LANG['variable_set'] = 'Ei õnnestunud määrata või lähtestada muutujat: '; +$PHPMAILER_LANG['extension_missing'] = 'Nõutud laiendus on puudu: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-fa.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-fa.php new file mode 100755 index 0000000000000000000000000000000000000000..ad0745c581c411b453a9ab29a266f3c647dab636 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-fa.php @@ -0,0 +1,27 @@ +<?php +/** + * Persian/Farsi PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Ali Jazayeri <jaza.ali@gmail.com> + * @author Mohammad Hossein Mojtahedi <mhm5000@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'خطای SMTP: احراز هویت با شکست مواجه شد.'; +$PHPMAILER_LANG['connect_host'] = 'خطای SMTP: اتصال به سرور SMTP برقرار نشد.'; +$PHPMAILER_LANG['data_not_accepted'] = 'خطای SMTP: دادهها نادرست هستند.'; +$PHPMAILER_LANG['empty_message'] = 'بخش متن پیام خالی است.'; +$PHPMAILER_LANG['encoding'] = 'کدگذاری ناشناخته: '; +$PHPMAILER_LANG['execute'] = 'امکان اجرا وجود ندارد: '; +$PHPMAILER_LANG['file_access'] = 'امکان دسترسی به فایل وجود ندارد: '; +$PHPMAILER_LANG['file_open'] = 'خطای File: امکان بازکردن فایل وجود ندارد: '; +$PHPMAILER_LANG['from_failed'] = 'آدرس فرستنده اشتباه است: '; +$PHPMAILER_LANG['instantiate'] = 'امکان معرفی تابع ایمیل وجود ندارد.'; +$PHPMAILER_LANG['invalid_address'] = 'آدرس ایمیل معتبر نیست: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer پشتیبانی نمیشود.'; +$PHPMAILER_LANG['provide_address'] = 'باید حداقل یک آدرس گیرنده وارد کنید.'; +$PHPMAILER_LANG['recipients_failed'] = 'خطای SMTP: ارسال به آدرس گیرنده با خطا مواجه شد: '; +$PHPMAILER_LANG['signing'] = 'خطا در امضا: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'خطا در اتصال به SMTP.'; +$PHPMAILER_LANG['smtp_error'] = 'خطا در SMTP Server: '; +$PHPMAILER_LANG['variable_set'] = 'امکان ارسال یا ارسال مجدد متغیرها وجود ندارد: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-fi.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-fi.php new file mode 100755 index 0000000000000000000000000000000000000000..ec4e75234971ef55d16526c18bd06a8495b87d24 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-fi.php @@ -0,0 +1,27 @@ +<?php +/** + * Finnish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Jyry Kuukanen + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP-virhe: käyttäjätunnistus epäonnistui.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP-virhe: yhteys palvelimeen ei onnistu.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-virhe: data on virheellinen.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Tuntematon koodaustyyppi: '; +$PHPMAILER_LANG['execute'] = 'Suoritus epäonnistui: '; +$PHPMAILER_LANG['file_access'] = 'Seuraavaan tiedostoon ei ole oikeuksia: '; +$PHPMAILER_LANG['file_open'] = 'Tiedostovirhe: Ei voida avata tiedostoa: '; +$PHPMAILER_LANG['from_failed'] = 'Seuraava lähettäjän osoite on virheellinen: '; +$PHPMAILER_LANG['instantiate'] = 'mail-funktion luonti epäonnistui.'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['mailer_not_supported'] = 'postivälitintyyppiä ei tueta.'; +$PHPMAILER_LANG['provide_address'] = 'Aseta vähintään yksi vastaanottajan sähköpostiosoite.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP-virhe: seuraava vastaanottaja osoite on virheellinen.'; +$PHPMAILER_LANG['encoding'] = 'Tuntematon koodaustyyppi: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-fo.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-fo.php new file mode 100755 index 0000000000000000000000000000000000000000..68cdef1d090c5e681fbebad7974bee4607821904 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-fo.php @@ -0,0 +1,26 @@ +<?php +/** + * Faroese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Dávur Sørensen <http://www.profo-webdesign.dk> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP feilur: Kundi ikki góðkenna.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP feilur: Kundi ikki knýta samband við SMTP vert.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP feilur: Data ikki góðkent.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ókend encoding: '; +$PHPMAILER_LANG['execute'] = 'Kundi ikki útføra: '; +$PHPMAILER_LANG['file_access'] = 'Kundi ikki tilganga fílu: '; +$PHPMAILER_LANG['file_open'] = 'Fílu feilur: Kundi ikki opna fílu: '; +$PHPMAILER_LANG['from_failed'] = 'fylgjandi Frá/From adressa miseydnaðist: '; +$PHPMAILER_LANG['instantiate'] = 'Kuni ikki instantiera mail funktión.'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' er ikki supporterað.'; +$PHPMAILER_LANG['provide_address'] = 'Tú skal uppgeva minst móttakara-emailadressu(r).'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feilur: Fylgjandi móttakarar miseydnaðust: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-fr.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-fr.php new file mode 100755 index 0000000000000000000000000000000000000000..af68c9236881d1bee0f81ea03651b803902cf7a7 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-fr.php @@ -0,0 +1,29 @@ +<?php +/** + * French PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * Some French punctuation requires a thin non-breaking space (U+202F) character before it, + * for example before a colon or exclamation mark. + * There is one of these characters between these quotes: " " + * @see http://unicode.org/udhr/n/notes_fra.html + */ + +$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP : échec de l\'authentification.'; +$PHPMAILER_LANG['connect_host'] = 'Erreur SMTP : impossible de se connecter au serveur SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erreur SMTP : données incorrectes.'; +$PHPMAILER_LANG['empty_message'] = 'Corps du message vide.'; +$PHPMAILER_LANG['encoding'] = 'Encodage inconnu : '; +$PHPMAILER_LANG['execute'] = 'Impossible de lancer l\'exécution : '; +$PHPMAILER_LANG['file_access'] = 'Impossible d\'accéder au fichier : '; +$PHPMAILER_LANG['file_open'] = 'Ouverture du fichier impossible : '; +$PHPMAILER_LANG['from_failed'] = 'L\'adresse d\'expéditeur suivante a échoué : '; +$PHPMAILER_LANG['instantiate'] = 'Impossible d\'instancier la fonction mail.'; +$PHPMAILER_LANG['invalid_address'] = 'L\'adresse courriel n\'est pas valide : '; +$PHPMAILER_LANG['mailer_not_supported'] = ' client de messagerie non supporté.'; +$PHPMAILER_LANG['provide_address'] = 'Vous devez fournir au moins une adresse de destinataire.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP : les destinataires suivants sont en erreur : '; +$PHPMAILER_LANG['signing'] = 'Erreur de signature : '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Échec de la connexion SMTP.'; +$PHPMAILER_LANG['smtp_error'] = 'Erreur du serveur SMTP : '; +$PHPMAILER_LANG['variable_set'] = 'Impossible d\'initialiser ou de réinitialiser une variable : '; +$PHPMAILER_LANG['extension_missing'] = 'Extension manquante : '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-gl.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-gl.php new file mode 100755 index 0000000000000000000000000000000000000000..9b4ce4d8de252e3d95adcf17e9c0c37420edec3d --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-gl.php @@ -0,0 +1,26 @@ +<?php +/** + * Galician PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author by Donato Rouco <donatorouco@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro SMTP: Non puido ser autentificado.'; +$PHPMAILER_LANG['connect_host'] = 'Erro SMTP: Non puido conectar co servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro SMTP: Datos non aceptados.'; +$PHPMAILER_LANG['empty_message'] = 'Corpo da mensaxe vacía'; +$PHPMAILER_LANG['encoding'] = 'Codificación descoñecida: '; +$PHPMAILER_LANG['execute'] = 'Non puido ser executado: '; +$PHPMAILER_LANG['file_access'] = 'Nob puido acceder ó arquivo: '; +$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: No puido abrir o arquivo: '; +$PHPMAILER_LANG['from_failed'] = 'A(s) seguinte(s) dirección(s) de remitente(s) deron erro: '; +$PHPMAILER_LANG['instantiate'] = 'Non puido crear unha instancia da función Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Non puido envia-lo correo: dirección de email inválida: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer non está soportado.'; +$PHPMAILER_LANG['provide_address'] = 'Debe engadir polo menos unha dirección de email coma destino.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro SMTP: Os seguintes destinos fallaron: '; +$PHPMAILER_LANG['signing'] = 'Erro ó firmar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallou.'; +$PHPMAILER_LANG['smtp_error'] = 'Erro do servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Non puidemos axustar ou reaxustar a variábel: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-he.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-he.php new file mode 100755 index 0000000000000000000000000000000000000000..70eb717578f1e4e1c0cbcee855e14b8a91f8f7ce --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-he.php @@ -0,0 +1,26 @@ +<?php +/** + * Hebrew PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Ronny Sherer <ronny@hoojima.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'שגיאת SMTP: פעולת האימות נכשלה.'; +$PHPMAILER_LANG['connect_host'] = 'שגיאת SMTP: לא הצלחתי להתחבר לשרת SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'שגיאת SMTP: מידע לא התקבל.'; +$PHPMAILER_LANG['empty_message'] = 'גוף ההודעה ריק'; +$PHPMAILER_LANG['invalid_address'] = 'כתובת שגויה: '; +$PHPMAILER_LANG['encoding'] = 'קידוד לא מוכר: '; +$PHPMAILER_LANG['execute'] = 'לא הצלחתי להפעיל את: '; +$PHPMAILER_LANG['file_access'] = 'לא ניתן לגשת לקובץ: '; +$PHPMAILER_LANG['file_open'] = 'שגיאת קובץ: לא ניתן לגשת לקובץ: '; +$PHPMAILER_LANG['from_failed'] = 'כתובות הנמענים הבאות נכשלו: '; +$PHPMAILER_LANG['instantiate'] = 'לא הצלחתי להפעיל את פונקציית המייל.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' אינה נתמכת.'; +$PHPMAILER_LANG['provide_address'] = 'חובה לספק לפחות כתובת אחת של מקבל המייל.'; +$PHPMAILER_LANG['recipients_failed'] = 'שגיאת SMTP: הנמענים הבאים נכשלו: '; +$PHPMAILER_LANG['signing'] = 'שגיאת חתימה: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +$PHPMAILER_LANG['smtp_error'] = 'שגיאת שרת SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'לא ניתן לקבוע או לשנות את המשתנה: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-hi.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-hi.php new file mode 100755 index 0000000000000000000000000000000000000000..607a5ee3f9bd3e678f96336cd1837bbf61deeb96 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-hi.php @@ -0,0 +1,26 @@ +<?php +/** + * Hindi PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Yash Karanke <mr.karanke@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP त्रुटि: प्रामाणिकता की जांच नहीं हो सका। '; +$PHPMAILER_LANG['connect_host'] = 'SMTP त्रुटि: SMTP सर्वर से कनेक्ट नहीं हो सका। '; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP त्रुटि: डेटा स्वीकार नहीं किया जाता है। '; +$PHPMAILER_LANG['empty_message'] = 'संदेश खाली है। '; +$PHPMAILER_LANG['encoding'] = 'अज्ञात एन्कोडिंग प्रकार। '; +$PHPMAILER_LANG['execute'] = 'आदेश को निष्पादित करने में विफल। '; +$PHPMAILER_LANG['file_access'] = 'फ़ाइल उपलब्ध नहीं है। '; +$PHPMAILER_LANG['file_open'] = 'फ़ाइल त्रुटि: फाइल को खोला नहीं जा सका। '; +$PHPMAILER_LANG['from_failed'] = 'प्रेषक का पता गलत है। '; +$PHPMAILER_LANG['instantiate'] = 'मेल फ़ंक्शन कॉल नहीं कर सकता है।'; +$PHPMAILER_LANG['invalid_address'] = 'पता गलत है। '; +$PHPMAILER_LANG['mailer_not_supported'] = 'मेल सर्वर के साथ काम नहीं करता है। '; +$PHPMAILER_LANG['provide_address'] = 'आपको कम से कम एक प्राप्तकर्ता का ई-मेल पता प्रदान करना होगा।'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP त्रुटि: निम्न प्राप्तकर्ताओं को पते भेजने में विफल। '; +$PHPMAILER_LANG['signing'] = 'साइनअप त्रुटि:। '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP का connect () फ़ंक्शन विफल हुआ। '; +$PHPMAILER_LANG['smtp_error'] = 'SMTP सर्वर त्रुटि। '; +$PHPMAILER_LANG['variable_set'] = 'चर को बना या संशोधित नहीं किया जा सकता। '; +$PHPMAILER_LANG['extension_missing'] = 'एक्सटेन्षन गायब है: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-hr.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-hr.php new file mode 100755 index 0000000000000000000000000000000000000000..3822920adda1780df96dd7117f5ed4729aabe2e1 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-hr.php @@ -0,0 +1,26 @@ +<?php +/** + * Croatian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Hrvoj3e <hrvoj3e@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Greška: Neuspjela autentikacija.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Greška: Ne mogu se spojiti na SMTP poslužitelj.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Greška: Podatci nisu prihvaćeni.'; +$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznati encoding: '; +$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: '; +$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: '; +$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP Greška: Slanje s navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Greška: Slanje na navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['instantiate'] = 'Ne mogu pokrenuti mail funkcionalnost.'; +$PHPMAILER_LANG['invalid_address'] = 'E-mail nije poslan. Neispravna e-mail adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nije podržan.'; +$PHPMAILER_LANG['provide_address'] = 'Definirajte barem jednu adresu primatelja.'; +$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Spajanje na SMTP poslužitelj nije uspjelo.'; +$PHPMAILER_LANG['smtp_error'] = 'Greška SMTP poslužitelja: '; +$PHPMAILER_LANG['variable_set'] = 'Ne mogu postaviti varijablu niti ju vratiti nazad: '; +$PHPMAILER_LANG['extension_missing'] = 'Nedostaje proširenje: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-hu.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-hu.php new file mode 100755 index 0000000000000000000000000000000000000000..d7ca88870204f9e2a8a063e604bb55bffd3d81aa --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-hu.php @@ -0,0 +1,26 @@ +<?php +/** + * Hungarian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author @dominicus-75 + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP hiba: az azonosítás sikertelen.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP hiba: nem lehet kapcsolódni az SMTP-szerverhez.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP hiba: adatok visszautasítva.'; +$PHPMAILER_LANG['empty_message'] = 'Üres az üzenettörzs.'; +$PHPMAILER_LANG['encoding'] = 'Ismeretlen kódolás: '; +$PHPMAILER_LANG['execute'] = 'Nem lehet végrehajtani: '; +$PHPMAILER_LANG['file_access'] = 'A következő fájl nem elérhető: '; +$PHPMAILER_LANG['file_open'] = 'Fájl hiba: a következő fájlt nem lehet megnyitni: '; +$PHPMAILER_LANG['from_failed'] = 'A feladóként megadott következő cím hibás: '; +$PHPMAILER_LANG['instantiate'] = 'A PHP mail() függvényt nem sikerült végrehajtani.'; +$PHPMAILER_LANG['invalid_address'] = 'Érvénytelen cím: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' a mailer-osztály nem támogatott.'; +$PHPMAILER_LANG['provide_address'] = 'Legalább egy címzettet fel kell tüntetni.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP hiba: a címzettként megadott következő címek hibásak: '; +$PHPMAILER_LANG['signing'] = 'Hibás aláírás: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Hiba az SMTP-kapcsolatban.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP-szerver hiba: '; +$PHPMAILER_LANG['variable_set'] = 'A következő változók beállítása nem sikerült: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-id.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-id.php new file mode 100755 index 0000000000000000000000000000000000000000..97c16e087ffa1bb0a74f589b86238c91a456740f --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-id.php @@ -0,0 +1,27 @@ +<?php +/** + * Indonesian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Cecep Prawiro <cecep.prawiro@gmail.com> + * @author @januridp + */ + +$PHPMAILER_LANG['authenticate'] = 'Kesalahan SMTP: Tidak dapat mengotentikasi.'; +$PHPMAILER_LANG['connect_host'] = 'Kesalahan SMTP: Tidak dapat terhubung ke host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Kesalahan SMTP: Data tidak diterima peladen.'; +$PHPMAILER_LANG['empty_message'] = 'Isi pesan kosong'; +$PHPMAILER_LANG['encoding'] = 'Pengkodean karakter tidak dikenali: '; +$PHPMAILER_LANG['execute'] = 'Tidak dapat menjalankan proses : '; +$PHPMAILER_LANG['file_access'] = 'Tidak dapat mengakses berkas : '; +$PHPMAILER_LANG['file_open'] = 'Kesalahan File: Berkas tidak bisa dibuka : '; +$PHPMAILER_LANG['from_failed'] = 'Alamat pengirim berikut mengakibatkan kesalahan : '; +$PHPMAILER_LANG['instantiate'] = 'Tidak dapat menginisialisasi fungsi surel'; +$PHPMAILER_LANG['invalid_address'] = 'Gagal terkirim, alamat surel tidak benar : '; +$PHPMAILER_LANG['provide_address'] = 'Harus disediakan minimal satu alamat tujuan'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Pengirim tidak didukung'; +$PHPMAILER_LANG['recipients_failed'] = 'Kesalahan SMTP: Alamat tujuan berikut menghasilkan kesalahan : '; +$PHPMAILER_LANG['signing'] = 'Kesalahan dalam tanda tangan : '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() gagal.'; +$PHPMAILER_LANG['smtp_error'] = 'Kesalahan pada pelayan SMTP : '; +$PHPMAILER_LANG['variable_set'] = 'Tidak berhasil mengatur atau mengatur ulang variable : '; +$PHPMAILER_LANG['extension_missing'] = 'Ekstensi hilang: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-it.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-it.php new file mode 100755 index 0000000000000000000000000000000000000000..d2f4643e7150a142751debebfd3657ebbf242b97 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-it.php @@ -0,0 +1,27 @@ +<?php +/** + * Italian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Ilias Bartolini <brain79@inwind.it> + * @author Stefano Sabatini <sabas88@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dati non accettati dal server.'; +$PHPMAILER_LANG['empty_message'] = 'Il corpo del messaggio è vuoto'; +$PHPMAILER_LANG['encoding'] = 'Codifica dei caratteri sconosciuta: '; +$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: '; +$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: '; +$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: '; +$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail'; +$PHPMAILER_LANG['invalid_address'] = 'Impossibile inviare, l\'indirizzo email non è valido: '; +$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato un errore: '; +$PHPMAILER_LANG['signing'] = 'Errore nella firma: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallita.'; +$PHPMAILER_LANG['smtp_error'] = 'Errore del server SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Impossibile impostare o resettare la variabile: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ja.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ja.php new file mode 100755 index 0000000000000000000000000000000000000000..2d778728d7762206d01ff924fc6d24ccd4a5d7d4 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ja.php @@ -0,0 +1,27 @@ +<?php +/** + * Japanese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Mitsuhiro Yoshida <http://mitstek.com/> + * @author Yoshi Sakai <http://bluemooninc.jp/> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTPエラー: 認証できませんでした。'; +$PHPMAILER_LANG['connect_host'] = 'SMTPエラー: SMTPホストに接続できませんでした。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTPエラー: データが受け付けられませんでした。'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = '不明なエンコーディング: '; +$PHPMAILER_LANG['execute'] = '実行できませんでした: '; +$PHPMAILER_LANG['file_access'] = 'ファイルにアクセスできません: '; +$PHPMAILER_LANG['file_open'] = 'ファイルエラー: ファイルを開けません: '; +$PHPMAILER_LANG['from_failed'] = 'Fromアドレスを登録する際にエラーが発生しました: '; +$PHPMAILER_LANG['instantiate'] = 'メール関数が正常に動作しませんでした。'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。'; +$PHPMAILER_LANG['mailer_not_supported'] = ' メーラーがサポートされていません。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレスに 間違いがあります: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ka.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ka.php new file mode 100755 index 0000000000000000000000000000000000000000..dd1af8abec5db96bc8e41a717dda506b14af61f7 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ka.php @@ -0,0 +1,26 @@ +<?php +/** + * Georgian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP შეცდომა: ავტორიზაცია შეუძლებელია.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP შეცდომა: SMTP სერვერთან დაკავშირება შეუძლებელია.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP შეცდომა: მონაცემები არ იქნა მიღებული.'; +$PHPMAILER_LANG['encoding'] = 'კოდირების უცნობი ტიპი: '; +$PHPMAILER_LANG['execute'] = 'შეუძლებელია შემდეგი ბრძანების შესრულება: '; +$PHPMAILER_LANG['file_access'] = 'შეუძლებელია წვდომა ფაილთან: '; +$PHPMAILER_LANG['file_open'] = 'ფაილური სისტემის შეცდომა: არ იხსნება ფაილი: '; +$PHPMAILER_LANG['from_failed'] = 'გამგზავნის არასწორი მისამართი: '; +$PHPMAILER_LANG['instantiate'] = 'mail ფუნქციის გაშვება ვერ ხერხდება.'; +$PHPMAILER_LANG['provide_address'] = 'გთხოვთ მიუთითოთ ერთი ადრესატის e-mail მისამართი მაინც.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - საფოსტო სერვერის მხარდაჭერა არ არის.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP შეცდომა: შემდეგ მისამართებზე გაგზავნა ვერ მოხერხდა: '; +$PHPMAILER_LANG['empty_message'] = 'შეტყობინება ცარიელია'; +$PHPMAILER_LANG['invalid_address'] = 'არ გაიგზავნა, e-mail მისამართის არასწორი ფორმატი: '; +$PHPMAILER_LANG['signing'] = 'ხელმოწერის შეცდომა: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'შეცდომა SMTP სერვერთან დაკავშირებისას'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP სერვერის შეცდომა: '; +$PHPMAILER_LANG['variable_set'] = 'შეუძლებელია შემდეგი ცვლადის შექმნა ან შეცვლა: '; +$PHPMAILER_LANG['extension_missing'] = 'ბიბლიოთეკა არ არსებობს: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ko.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ko.php new file mode 100755 index 0000000000000000000000000000000000000000..9599fa6819200c3f0beb73d687259f339597620d --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ko.php @@ -0,0 +1,26 @@ +<?php +/** + * Korean PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author ChalkPE <amato0617@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 오류: 인증할 수 없습니다.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 오류: SMTP 호스트에 접속할 수 없습니다.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 오류: 데이터가 받아들여지지 않았습니다.'; +$PHPMAILER_LANG['empty_message'] = '메세지 내용이 없습니다'; +$PHPMAILER_LANG['encoding'] = '알 수 없는 인코딩: '; +$PHPMAILER_LANG['execute'] = '실행 불가: '; +$PHPMAILER_LANG['file_access'] = '파일 접근 불가: '; +$PHPMAILER_LANG['file_open'] = '파일 오류: 파일을 열 수 없습니다: '; +$PHPMAILER_LANG['from_failed'] = '다음 From 주소에서 오류가 발생했습니다: '; +$PHPMAILER_LANG['instantiate'] = 'mail 함수를 인스턴스화할 수 없습니다'; +$PHPMAILER_LANG['invalid_address'] = '잘못된 주소: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' 메일러는 지원되지 않습니다.'; +$PHPMAILER_LANG['provide_address'] = '적어도 한 개 이상의 수신자 메일 주소를 제공해야 합니다.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 오류: 다음 수신자에서 오류가 발생했습니다: '; +$PHPMAILER_LANG['signing'] = '서명 오류: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP 연결을 실패하였습니다.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP 서버 오류: '; +$PHPMAILER_LANG['variable_set'] = '변수 설정 및 초기화 불가: '; +$PHPMAILER_LANG['extension_missing'] = '확장자 없음: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-lt.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-lt.php new file mode 100755 index 0000000000000000000000000000000000000000..1253a4fdb491710eeb633875a697e8ebf99c5f14 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-lt.php @@ -0,0 +1,26 @@ +<?php +/** + * Lithuanian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Dainius Kaupaitis <dk@sum.lt> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP klaida: autentifikacija nepavyko.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP klaida: nepavyksta prisijungti prie SMTP stoties.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP klaida: duomenys nepriimti.'; +$PHPMAILER_LANG['empty_message'] = 'Laiško turinys tuščias'; +$PHPMAILER_LANG['encoding'] = 'Neatpažinta koduotė: '; +$PHPMAILER_LANG['execute'] = 'Nepavyko įvykdyti komandos: '; +$PHPMAILER_LANG['file_access'] = 'Byla nepasiekiama: '; +$PHPMAILER_LANG['file_open'] = 'Bylos klaida: Nepavyksta atidaryti: '; +$PHPMAILER_LANG['from_failed'] = 'Neteisingas siuntėjo adresas: '; +$PHPMAILER_LANG['instantiate'] = 'Nepavyko paleisti mail funkcijos.'; +$PHPMAILER_LANG['invalid_address'] = 'Neteisingas adresas: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' pašto stotis nepalaikoma.'; +$PHPMAILER_LANG['provide_address'] = 'Nurodykite bent vieną gavėjo adresą.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP klaida: nepavyko išsiųsti šiems gavėjams: '; +$PHPMAILER_LANG['signing'] = 'Prisijungimo klaida: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP susijungimo klaida'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP stoties klaida: '; +$PHPMAILER_LANG['variable_set'] = 'Nepavyko priskirti reikšmės kintamajam: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-lv.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-lv.php new file mode 100755 index 0000000000000000000000000000000000000000..39bf9a19e22db30904ec98e8df0909e768799b9a --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-lv.php @@ -0,0 +1,26 @@ +<?php +/** + * Latvian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Eduards M. <e@npd.lv> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP kļūda: Autorizācija neizdevās.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Kļūda: Nevar izveidot savienojumu ar SMTP serveri.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Kļūda: Nepieņem informāciju.'; +$PHPMAILER_LANG['empty_message'] = 'Ziņojuma teksts ir tukšs'; +$PHPMAILER_LANG['encoding'] = 'Neatpazīts kodējums: '; +$PHPMAILER_LANG['execute'] = 'Neizdevās izpildīt komandu: '; +$PHPMAILER_LANG['file_access'] = 'Fails nav pieejams: '; +$PHPMAILER_LANG['file_open'] = 'Faila kļūda: Nevar atvērt failu: '; +$PHPMAILER_LANG['from_failed'] = 'Nepareiza sūtītāja adrese: '; +$PHPMAILER_LANG['instantiate'] = 'Nevar palaist sūtīšanas funkciju.'; +$PHPMAILER_LANG['invalid_address'] = 'Nepareiza adrese: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' sūtītājs netiek atbalstīts.'; +$PHPMAILER_LANG['provide_address'] = 'Lūdzu, norādiet vismaz vienu adresātu.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP kļūda: neizdevās nosūtīt šādiem saņēmējiem: '; +$PHPMAILER_LANG['signing'] = 'Autorizācijas kļūda: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP savienojuma kļūda'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP servera kļūda: '; +$PHPMAILER_LANG['variable_set'] = 'Nevar piešķirt mainīgā vērtību: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ms.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ms.php new file mode 100755 index 0000000000000000000000000000000000000000..4e2c34083a99bfd768fc1008fb5cf9981ed27d97 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ms.php @@ -0,0 +1,26 @@ +<?php +/** + * Malaysian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Nawawi Jamili <nawawi@rutweb.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Ralat SMTP: Tidak dapat pengesahan.'; +$PHPMAILER_LANG['connect_host'] = 'Ralat SMTP: Tidak dapat menghubungi hos pelayan SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Ralat SMTP: Data tidak diterima oleh pelayan.'; +$PHPMAILER_LANG['empty_message'] = 'Tiada isi untuk mesej'; +$PHPMAILER_LANG['encoding'] = 'Pengekodan tidak diketahui: '; +$PHPMAILER_LANG['execute'] = 'Tidak dapat melaksanakan: '; +$PHPMAILER_LANG['file_access'] = 'Tidak dapat mengakses fail: '; +$PHPMAILER_LANG['file_open'] = 'Ralat Fail: Tidak dapat membuka fail: '; +$PHPMAILER_LANG['from_failed'] = 'Berikut merupakan ralat dari alamat e-mel: '; +$PHPMAILER_LANG['instantiate'] = 'Tidak dapat memberi contoh fungsi e-mel.'; +$PHPMAILER_LANG['invalid_address'] = 'Alamat emel tidak sah: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' jenis penghantar emel tidak disokong.'; +$PHPMAILER_LANG['provide_address'] = 'Anda perlu menyediakan sekurang-kurangnya satu alamat e-mel penerima.'; +$PHPMAILER_LANG['recipients_failed'] = 'Ralat SMTP: Penerima e-mel berikut telah gagal: '; +$PHPMAILER_LANG['signing'] = 'Ralat pada tanda tangan: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() telah gagal.'; +$PHPMAILER_LANG['smtp_error'] = 'Ralat pada pelayan SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Tidak boleh menetapkan atau menetapkan semula pembolehubah: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-nb.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-nb.php new file mode 100755 index 0000000000000000000000000000000000000000..446105422cb9855ba1e0562bd638ecab9e0e155d --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-nb.php @@ -0,0 +1,25 @@ +<?php +/** + * Norwegian Bokmål PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Feil: Kunne ikke autentisere.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Feil: Kunne ikke koble til SMTP tjener.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Feil: Datainnhold ikke akseptert.'; +$PHPMAILER_LANG['empty_message'] = 'Melding kropp tomt'; +$PHPMAILER_LANG['encoding'] = 'Ukjent koding: '; +$PHPMAILER_LANG['execute'] = 'Kunne ikke utføre: '; +$PHPMAILER_LANG['file_access'] = 'Får ikke tilgang til filen: '; +$PHPMAILER_LANG['file_open'] = 'Fil Feil: Kunne ikke åpne filen: '; +$PHPMAILER_LANG['from_failed'] = 'Følgende Frå adresse feilet: '; +$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere post funksjon.'; +$PHPMAILER_LANG['invalid_address'] = 'Ugyldig adresse: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' sender er ikke støttet.'; +$PHPMAILER_LANG['provide_address'] = 'Du må opppgi minst en mottakeradresse.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feil: Følgende mottakeradresse feilet: '; +$PHPMAILER_LANG['signing'] = 'Signering Feil: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() feilet.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP server feil: '; +$PHPMAILER_LANG['variable_set'] = 'Kan ikke skrive eller omskrive variabel: '; +$PHPMAILER_LANG['extension_missing'] = 'Utvidelse mangler: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-nl.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-nl.php new file mode 100755 index 0000000000000000000000000000000000000000..c36d8b2112706be10ff61701414d64c96c459129 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-nl.php @@ -0,0 +1,26 @@ +<?php +/** + * Dutch PHPMailer language file: refer to PHPMailer.php for definitive list. + * @package PHPMailer + * @author Tuxion <team@tuxion.nl> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP-fout: authenticatie mislukt.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP-fout: kon niet verbinden met SMTP-host.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-fout: data niet geaccepteerd.'; +$PHPMAILER_LANG['empty_message'] = 'Berichttekst is leeg'; +$PHPMAILER_LANG['encoding'] = 'Onbekende codering: '; +$PHPMAILER_LANG['execute'] = 'Kon niet uitvoeren: '; +$PHPMAILER_LANG['file_access'] = 'Kreeg geen toegang tot bestand: '; +$PHPMAILER_LANG['file_open'] = 'Bestandsfout: kon bestand niet openen: '; +$PHPMAILER_LANG['from_failed'] = 'Het volgende afzendersadres is mislukt: '; +$PHPMAILER_LANG['instantiate'] = 'Kon mailfunctie niet initialiseren.'; +$PHPMAILER_LANG['invalid_address'] = 'Ongeldig adres: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.'; +$PHPMAILER_LANG['provide_address'] = 'Er moet minstens één ontvanger worden opgegeven.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP-fout: de volgende ontvangers zijn mislukt: '; +$PHPMAILER_LANG['signing'] = 'Signeerfout: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Verbinding mislukt.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfout: '; +$PHPMAILER_LANG['variable_set'] = 'Kan de volgende variabele niet instellen of resetten: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-pl.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-pl.php new file mode 100755 index 0000000000000000000000000000000000000000..3da0dee91f1d0a1f1d0e2972f8d710be67e72208 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-pl.php @@ -0,0 +1,26 @@ +<?php +/** + * Polish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + */ + +$PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzić uwierzytelnienia.'; +$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.'; +$PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.'; +$PHPMAILER_LANG['encoding'] = 'Nieznany sposób kodowania znaków: '; +$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: '; +$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: '; +$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: '; +$PHPMAILER_LANG['from_failed'] = 'Następujący adres Nadawcy jest nieprawidłowy: '; +$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.'; +$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, '. + 'następujący adres Odbiorcy jest nieprawidłowy: '; +$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email Odbiorcy.'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.'; +$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: '; +$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zakończone niepowodzeniem.'; +$PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: '; +$PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-pt.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-pt.php new file mode 100755 index 0000000000000000000000000000000000000000..f365d5d0b4beb0d465574aabfe580062ccef6781 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-pt.php @@ -0,0 +1,26 @@ +<?php +/** + * Portuguese (European) PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Jonadabe <jonadabe@hotmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro do SMTP: Não foi possível realizar a autenticação.'; +$PHPMAILER_LANG['connect_host'] = 'Erro do SMTP: Não foi possível realizar ligação com o servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro do SMTP: Os dados foram rejeitados.'; +$PHPMAILER_LANG['empty_message'] = 'A mensagem no e-mail está vazia.'; +$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: '; +$PHPMAILER_LANG['execute'] = 'Não foi possível executar: '; +$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder o ficheiro: '; +$PHPMAILER_LANG['file_open'] = 'Abertura do ficheiro: Não foi possível abrir o ficheiro: '; +$PHPMAILER_LANG['from_failed'] = 'Ocorreram falhas nos endereços dos seguintes remententes: '; +$PHPMAILER_LANG['instantiate'] = 'Não foi possível iniciar uma instância da função mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Não foi enviado nenhum e-mail para o endereço de e-mail inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Tem de fornecer pelo menos um endereço como destinatário do e-mail.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro do SMTP: O endereço do seguinte destinatário falhou: '; +$PHPMAILER_LANG['signing'] = 'Erro ao assinar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.'; +$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensão em falta: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-pt_br.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-pt_br.php new file mode 100755 index 0000000000000000000000000000000000000000..4ec10f777ee37f4e2d012684236be8f9822b35a2 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-pt_br.php @@ -0,0 +1,29 @@ +<?php +/** + * Brazilian Portuguese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Paulo Henrique Garcia <paulo@controllerweb.com.br> + * @author Lucas Guimarães <lucas@lucasguimaraes.com> + * @author Phelipe Alves <phelipealvesdesouza@gmail.com> + * @author Fabio Beneditto <fabiobeneditto@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro de SMTP: Não foi possível autenticar.'; +$PHPMAILER_LANG['connect_host'] = 'Erro de SMTP: Não foi possível conectar ao servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro de SMTP: Dados rejeitados.'; +$PHPMAILER_LANG['empty_message'] = 'Mensagem vazia'; +$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: '; +$PHPMAILER_LANG['execute'] = 'Não foi possível executar: '; +$PHPMAILER_LANG['file_access'] = 'Não foi possível acessar o arquivo: '; +$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: Não foi possível abrir o arquivo: '; +$PHPMAILER_LANG['from_failed'] = 'Os seguintes remetentes falharam: '; +$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Você deve informar pelo menos um destinatário.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro de SMTP: Os seguintes destinatários falharam: '; +$PHPMAILER_LANG['signing'] = 'Erro de Assinatura: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.'; +$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensão ausente: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ro.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ro.php new file mode 100755 index 0000000000000000000000000000000000000000..fa100eaa207625bcfe273129663386924b357c64 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ro.php @@ -0,0 +1,26 @@ +<?php +/** + * Romanian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Alex Florea <alecz.fia@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'Eroare SMTP: Autentificarea a eșuat.'; +$PHPMAILER_LANG['connect_host'] = 'Eroare SMTP: Conectarea la serverul SMTP a eșuat.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Eroare SMTP: Datele nu au fost acceptate.'; +$PHPMAILER_LANG['empty_message'] = 'Mesajul este gol.'; +$PHPMAILER_LANG['encoding'] = 'Encodare necunoscută: '; +$PHPMAILER_LANG['execute'] = 'Nu se poate executa următoarea comandă: '; +$PHPMAILER_LANG['file_access'] = 'Nu se poate accesa următorul fișier: '; +$PHPMAILER_LANG['file_open'] = 'Eroare fișier: Nu se poate deschide următorul fișier: '; +$PHPMAILER_LANG['from_failed'] = 'Următoarele adrese From au dat eroare: '; +$PHPMAILER_LANG['instantiate'] = 'Funcția mail nu a putut fi inițializată.'; +$PHPMAILER_LANG['invalid_address'] = 'Adresa de email nu este validă: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.'; +$PHPMAILER_LANG['provide_address'] = 'Trebuie să adăugați cel puțin o adresă de email.'; +$PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Următoarele adrese de email au eșuat: '; +$PHPMAILER_LANG['signing'] = 'A aparut o problemă la semnarea emailului. '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Conectarea la serverul SMTP a eșuat.'; +$PHPMAILER_LANG['smtp_error'] = 'Eroare server SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Nu se poate seta/reseta variabila. '; +$PHPMAILER_LANG['extension_missing'] = 'Lipsește extensia: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-rs.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-rs.php new file mode 100755 index 0000000000000000000000000000000000000000..0502f02143573017d72a3e3667900572482502ed --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-rs.php @@ -0,0 +1,26 @@ +<?php +/** + * Serbian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Александар Јевремовић <ajevremovic@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP грешка: аутентификација није успела.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP грешка: није могуће повезивање са SMTP сервером.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP грешка: подаци нису прихваћени.'; +$PHPMAILER_LANG['empty_message'] = 'Садржај поруке је празан.'; +$PHPMAILER_LANG['encoding'] = 'Непознато кодовање: '; +$PHPMAILER_LANG['execute'] = 'Није могуће извршити наредбу: '; +$PHPMAILER_LANG['file_access'] = 'Није могуће приступити датотеци: '; +$PHPMAILER_LANG['file_open'] = 'Није могуће отворити датотеку: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP грешка: слање са следећих адреса није успело: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP грешка: слање на следеће адресе није успело: '; +$PHPMAILER_LANG['instantiate'] = 'Није могуће покренути mail функцију.'; +$PHPMAILER_LANG['invalid_address'] = 'Порука није послата због неисправне адресе: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' мејлер није подржан.'; +$PHPMAILER_LANG['provide_address'] = 'Потребно је задати најмање једну адресу.'; +$PHPMAILER_LANG['signing'] = 'Грешка приликом пријављивања: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Повезивање са SMTP сервером није успело.'; +$PHPMAILER_LANG['smtp_error'] = 'Грешка SMTP сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Није могуће задати променљиву, нити је вратити уназад: '; +$PHPMAILER_LANG['extension_missing'] = 'Недостаје проширење: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-ru.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-ru.php new file mode 100755 index 0000000000000000000000000000000000000000..4066f6b451c86a82813106a0fb806ff0d1be3119 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-ru.php @@ -0,0 +1,27 @@ +<?php +/** + * Russian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Alexey Chumakov <alex@chumakov.ru> + * @author Foster Snowhill <i18n@forstwoof.ru> + */ + +$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: ошибка авторизации.'; +$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к серверу SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.'; +$PHPMAILER_LANG['encoding'] = 'Неизвестный вид кодировки: '; +$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: '; +$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: '; +$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удается открыть файл: '; +$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: '; +$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail.'; +$PHPMAILER_LANG['provide_address'] = 'Пожалуйста, введите хотя бы один адрес e-mail получателя.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' — почтовый сервер не поддерживается.'; +$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: отправка по следующим адресам получателей не удалась: '; +$PHPMAILER_LANG['empty_message'] = 'Пустое сообщение'; +$PHPMAILER_LANG['invalid_address'] = 'Не отослано, неправильный формат email адреса: '; +$PHPMAILER_LANG['signing'] = 'Ошибка подписи: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ошибка соединения с SMTP-сервером'; +$PHPMAILER_LANG['smtp_error'] = 'Ошибка SMTP-сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Невозможно установить или переустановить переменную: '; +$PHPMAILER_LANG['extension_missing'] = 'Расширение отсутствует: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-sk.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-sk.php new file mode 100755 index 0000000000000000000000000000000000000000..a38f4e52cf2672582df1994d4e772691920436ff --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-sk.php @@ -0,0 +1,26 @@ +<?php +/** + * Slovak PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Michal Tinka <michaltinka@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Chyba autentifikácie.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Nebolo možné nadviazať spojenie so SMTP serverom.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dáta neboli prijaté'; +$PHPMAILER_LANG['empty_message'] = 'Prázdne telo správy.'; +$PHPMAILER_LANG['encoding'] = 'Neznáme kódovanie: '; +$PHPMAILER_LANG['execute'] = 'Nedá sa vykonať: '; +$PHPMAILER_LANG['file_access'] = 'Súbor nebol nájdený: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Súbor sa otvoriť pre čítanie: '; +$PHPMAILER_LANG['from_failed'] = 'Následujúca adresa From je nesprávna: '; +$PHPMAILER_LANG['instantiate'] = 'Nedá sa vytvoriť inštancia emailovej funkcie.'; +$PHPMAILER_LANG['invalid_address'] = 'Neodoslané, emailová adresa je nesprávna: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' emailový klient nieje podporovaný.'; +$PHPMAILER_LANG['provide_address'] = 'Musíte zadať aspoň jednu emailovú adresu príjemcu.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Adresy príjemcov niesu správne '; +$PHPMAILER_LANG['signing'] = 'Chyba prihlasovania: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zlyhalo.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP chyba serveru: '; +$PHPMAILER_LANG['variable_set'] = 'Nemožno nastaviť alebo resetovať premennú: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-sl.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-sl.php new file mode 100755 index 0000000000000000000000000000000000000000..54c9572506a14067bccdadc323d3c70fe61b2783 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-sl.php @@ -0,0 +1,26 @@ +<?php +/** + * Slovene PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Klemen Tušar <techouse@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP napaka: Avtentikacija ni uspela.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP napaka: Ne morem vzpostaviti povezave s SMTP gostiteljem.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP napaka: Strežnik zavrača podatke.'; +$PHPMAILER_LANG['empty_message'] = 'E-poštno sporočilo nima vsebine.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznan tip kodiranja: '; +$PHPMAILER_LANG['execute'] = 'Operacija ni uspela: '; +$PHPMAILER_LANG['file_access'] = 'Nimam dostopa do datoteke: '; +$PHPMAILER_LANG['file_open'] = 'Ne morem odpreti datoteke: '; +$PHPMAILER_LANG['from_failed'] = 'Neveljaven e-naslov pošiljatelja: '; +$PHPMAILER_LANG['instantiate'] = 'Ne morem inicializirati mail funkcije.'; +$PHPMAILER_LANG['invalid_address'] = 'E-poštno sporočilo ni bilo poslano. E-naslov je neveljaven: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer ni podprt.'; +$PHPMAILER_LANG['provide_address'] = 'Prosim vnesite vsaj enega naslovnika.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP napaka: Sledeči naslovniki so neveljavni: '; +$PHPMAILER_LANG['signing'] = 'Napaka pri podpisovanju: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ne morem vzpostaviti povezave s SMTP strežnikom.'; +$PHPMAILER_LANG['smtp_error'] = 'Napaka SMTP strežnika: '; +$PHPMAILER_LANG['variable_set'] = 'Ne morem nastaviti oz. ponastaviti spremenljivke: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-sr.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-sr.php new file mode 100755 index 0000000000000000000000000000000000000000..ed95ca6ea03b17f9138d8b40b8b406b6241eb6cf --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-sr.php @@ -0,0 +1,26 @@ +<?php +/** + * Serbian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Александар Јевремовић <ajevremovic@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP грешка: аутентификација није успела.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP грешка: није могуће повезивање са SMTP сервером.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP грешка: подаци нису прихваћени.'; +$PHPMAILER_LANG['empty_message'] = 'Садржај поруке је празан.'; +$PHPMAILER_LANG['encoding'] = 'Непознато кодовање: '; +$PHPMAILER_LANG['execute'] = 'Није могуће извршити наредбу: '; +$PHPMAILER_LANG['file_access'] = 'Није могуће приступити датотеци: '; +$PHPMAILER_LANG['file_open'] = 'Није могуће отворити датотеку: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP грешка: слање са следећих адреса није успело: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP грешка: слање на следеће адресе није успело: '; +$PHPMAILER_LANG['instantiate'] = 'Није могуће покренути mail функцију.'; +$PHPMAILER_LANG['invalid_address'] = 'Порука није послата због неисправне адресе: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' мејлер није подржан.'; +$PHPMAILER_LANG['provide_address'] = 'Потребно је задати најмање једну адресу.'; +$PHPMAILER_LANG['signing'] = 'Грешка приликом пријављивања: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Повезивање са SMTP сервером није успело.'; +$PHPMAILER_LANG['smtp_error'] = 'Грешка SMTP сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Није могуће задати променљиву, нити је вратити уназад: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-sv.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-sv.php new file mode 100755 index 0000000000000000000000000000000000000000..4408e63eb0e6622b2f22abe20068c3870fa7dbbc --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-sv.php @@ -0,0 +1,26 @@ +<?php +/** + * Swedish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Johan Linnér <johan@linner.biz> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fel: Kunde inte autentisera.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fel: Data accepterades inte.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Okänt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunde inte köra: '; +$PHPMAILER_LANG['file_access'] = 'Ingen åtkomst till fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte öppna fil: '; +$PHPMAILER_LANG['from_failed'] = 'Följande avsändaradress är felaktig: '; +$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.'; +$PHPMAILER_LANG['invalid_address'] = 'Felaktig adress: '; +$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: '; +$PHPMAILER_LANG['signing'] = 'Signerings fel: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() misslyckades.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP server fel: '; +$PHPMAILER_LANG['variable_set'] = 'Kunde inte definiera eller återställa variabel: '; +$PHPMAILER_LANG['extension_missing'] = 'Tillägg ej tillgängligt: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-tr.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-tr.php new file mode 100755 index 0000000000000000000000000000000000000000..cfe8eaae24c48e78c2710e9b0ae0450a6b3a97ed --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-tr.php @@ -0,0 +1,30 @@ +<?php +/** + * Turkish PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Elçin Özel + * @author Can Yılmaz + * @author Mehmet Benlioğlu + * @author @yasinaydin + * @author Ogün Karakuş + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Oturum açılamadı.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Hatası: SMTP sunucusuna bağlanılamadı.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Hatası: Veri kabul edilmedi.'; +$PHPMAILER_LANG['empty_message'] = 'Mesajın içeriği boş'; +$PHPMAILER_LANG['encoding'] = 'Bilinmeyen karakter kodlama: '; +$PHPMAILER_LANG['execute'] = 'Çalıştırılamadı: '; +$PHPMAILER_LANG['file_access'] = 'Dosyaya erişilemedi: '; +$PHPMAILER_LANG['file_open'] = 'Dosya Hatası: Dosya açılamadı: '; +$PHPMAILER_LANG['from_failed'] = 'Belirtilen adreslere gönderme başarısız: '; +$PHPMAILER_LANG['instantiate'] = 'Örnek e-posta fonksiyonu oluşturulamadı.'; +$PHPMAILER_LANG['invalid_address'] = 'Geçersiz e-posta adresi: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' e-posta kütüphanesi desteklenmiyor.'; +$PHPMAILER_LANG['provide_address'] = 'En az bir alıcı e-posta adresi belirtmelisiniz.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hatası: Belirtilen alıcılara ulaşılamadı: '; +$PHPMAILER_LANG['signing'] = 'İmzalama hatası: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() fonksiyonu başarısız.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: '; +$PHPMAILER_LANG['variable_set'] = 'Değişken ayarlanamadı ya da sıfırlanamadı: '; +$PHPMAILER_LANG['extension_missing'] = 'Eklenti bulunamadı: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-uk.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-uk.php new file mode 100755 index 0000000000000000000000000000000000000000..9a7b34674e4b688a950652f5c0d696821e940438 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-uk.php @@ -0,0 +1,27 @@ +<?php +/** + * Ukrainian PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author Yuriy Rudyy <yrudyy@prs.net.ua> + * @fixed by Boris Yurchenko <boris@yurchenko.pp.ua> + */ + +$PHPMAILER_LANG['authenticate'] = 'Помилка SMTP: помилка авторизації.'; +$PHPMAILER_LANG['connect_host'] = 'Помилка SMTP: не вдається під\'єднатися до серверу SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Помилка SMTP: дані не прийняті.'; +$PHPMAILER_LANG['encoding'] = 'Невідомий тип кодування: '; +$PHPMAILER_LANG['execute'] = 'Неможливо виконати команду: '; +$PHPMAILER_LANG['file_access'] = 'Немає доступу до файлу: '; +$PHPMAILER_LANG['file_open'] = 'Помилка файлової системи: не вдається відкрити файл: '; +$PHPMAILER_LANG['from_failed'] = 'Невірна адреса відправника: '; +$PHPMAILER_LANG['instantiate'] = 'Неможливо запустити функцію mail.'; +$PHPMAILER_LANG['provide_address'] = 'Будь-ласка, введіть хоча б одну адресу e-mail отримувача.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - поштовий сервер не підтримується.'; +$PHPMAILER_LANG['recipients_failed'] = 'Помилка SMTP: відправлення наступним отримувачам не вдалося: '; +$PHPMAILER_LANG['empty_message'] = 'Пусте тіло повідомлення'; +$PHPMAILER_LANG['invalid_address'] = 'Не відправлено, невірний формат адреси e-mail: '; +$PHPMAILER_LANG['signing'] = 'Помилка підпису: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Помилка з\'єднання із SMTP-сервером'; +$PHPMAILER_LANG['smtp_error'] = 'Помилка SMTP-сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Неможливо встановити або перевстановити змінну: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-vi.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-vi.php new file mode 100755 index 0000000000000000000000000000000000000000..c60dadebdb34d0a0e860c8f63704ea9fc12633f2 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-vi.php @@ -0,0 +1,26 @@ +<?php +/** + * Vietnamese (Tiếng Việt) PHPMailer language file: refer to English translation for definitive list. + * @package PHPMailer + * @author VINADES.,JSC <contact@vinades.vn> + */ + +$PHPMAILER_LANG['authenticate'] = 'Lỗi SMTP: Không thể xác thực.'; +$PHPMAILER_LANG['connect_host'] = 'Lỗi SMTP: Không thể kết nối máy chủ SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Lỗi SMTP: Dữ liệu không được chấp nhận.'; +$PHPMAILER_LANG['empty_message'] = 'Không có nội dung'; +$PHPMAILER_LANG['encoding'] = 'Mã hóa không xác định: '; +$PHPMAILER_LANG['execute'] = 'Không thực hiện được: '; +$PHPMAILER_LANG['file_access'] = 'Không thể truy cập tệp tin '; +$PHPMAILER_LANG['file_open'] = 'Lỗi Tập tin: Không thể mở tệp tin: '; +$PHPMAILER_LANG['from_failed'] = 'Lỗi địa chỉ gửi đi: '; +$PHPMAILER_LANG['instantiate'] = 'Không dùng được các hàm gửi thư.'; +$PHPMAILER_LANG['invalid_address'] = 'Đại chỉ emai không đúng: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' trình gửi thư không được hỗ trợ.'; +$PHPMAILER_LANG['provide_address'] = 'Bạn phải cung cấp ít nhất một địa chỉ người nhận.'; +$PHPMAILER_LANG['recipients_failed'] = 'Lỗi SMTP: lỗi địa chỉ người nhận: '; +$PHPMAILER_LANG['signing'] = 'Lỗi đăng nhập: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Lỗi kết nối với SMTP'; +$PHPMAILER_LANG['smtp_error'] = 'Lỗi máy chủ smtp '; +$PHPMAILER_LANG['variable_set'] = 'Không thể thiết lập hoặc thiết lập lại biến: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-zh.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-zh.php new file mode 100755 index 0000000000000000000000000000000000000000..3e9e358ceb554cc3151006ef15dcf940b335db89 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-zh.php @@ -0,0 +1,28 @@ +<?php +/** + * Traditional Chinese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author liqwei <liqwei@liqwei.com> + * @author Peter Dave Hello <@PeterDaveHello/> + * @author Jason Chiang <xcojad@gmail.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 錯誤:登入失敗。'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 錯誤:無法連線到 SMTP 主機。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 錯誤:無法接受的資料。'; +$PHPMAILER_LANG['empty_message'] = '郵件內容為空'; +$PHPMAILER_LANG['encoding'] = '未知編碼: '; +$PHPMAILER_LANG['execute'] = '無法執行:'; +$PHPMAILER_LANG['file_access'] = '無法存取檔案:'; +$PHPMAILER_LANG['file_open'] = '檔案錯誤:無法開啟檔案:'; +$PHPMAILER_LANG['from_failed'] = '發送地址錯誤:'; +$PHPMAILER_LANG['instantiate'] = '未知函數呼叫。'; +$PHPMAILER_LANG['invalid_address'] = '因為電子郵件地址無效,無法傳送: '; +$PHPMAILER_LANG['mailer_not_supported'] = '不支援的發信客戶端。'; +$PHPMAILER_LANG['provide_address'] = '必須提供至少一個收件人地址。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 錯誤:以下收件人地址錯誤:'; +$PHPMAILER_LANG['signing'] = '電子簽章錯誤: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP 連線失敗'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP 伺服器錯誤: '; +$PHPMAILER_LANG['variable_set'] = '無法設定或重設變數: '; +$PHPMAILER_LANG['extension_missing'] = '遺失模組 Extension: '; diff --git a/vas/rest/class/PHPMailer/language/phpmailer.lang-zh_cn.php b/vas/rest/class/PHPMailer/language/phpmailer.lang-zh_cn.php new file mode 100755 index 0000000000000000000000000000000000000000..37537802aa71c8b7c95bf936a59bdbbfd7cdd689 --- /dev/null +++ b/vas/rest/class/PHPMailer/language/phpmailer.lang-zh_cn.php @@ -0,0 +1,28 @@ +<?php +/** + * Simplified Chinese PHPMailer language file: refer to English translation for definitive list + * @package PHPMailer + * @author liqwei <liqwei@liqwei.com> + * @author young <masxy@foxmail.com> + * @author Teddysun <i@teddysun.com> + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:登录失败。'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 错误:无法连接到 SMTP 主机。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误:数据不被接受。'; +$PHPMAILER_LANG['empty_message'] = '邮件正文为空。'; +$PHPMAILER_LANG['encoding'] = '未知编码:'; +$PHPMAILER_LANG['execute'] = '无法执行:'; +$PHPMAILER_LANG['file_access'] = '无法访问文件:'; +$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:'; +$PHPMAILER_LANG['from_failed'] = '发送地址错误:'; +$PHPMAILER_LANG['instantiate'] = '未知函数调用。'; +$PHPMAILER_LANG['invalid_address'] = '发送失败,电子邮箱地址是无效的:'; +$PHPMAILER_LANG['mailer_not_supported'] = '发信客户端不被支持。'; +$PHPMAILER_LANG['provide_address'] = '必须提供至少一个收件人地址。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:'; +$PHPMAILER_LANG['signing'] = '登录失败:'; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP服务器连接失败。'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP服务器出错:'; +$PHPMAILER_LANG['variable_set'] = '无法设置或重置变量:'; +$PHPMAILER_LANG['extension_missing'] = '丢失模块 Extension:'; diff --git a/vas/rest/class/PHPMailer/src/Exception.php b/vas/rest/class/PHPMailer/src/Exception.php new file mode 100755 index 0000000000000000000000000000000000000000..9a05dec3ca869c06256c9bc66f2c82ac48b272aa --- /dev/null +++ b/vas/rest/class/PHPMailer/src/Exception.php @@ -0,0 +1,39 @@ +<?php +/** + * PHPMailer Exception class. + * PHP Version 5.5. + * + * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer exception handler. + * + * @author Marcus Bointon <phpmailer@synchromedia.co.uk> + */ +class Exception extends \Exception +{ + /** + * Prettify error message output. + * + * @return string + */ + public function errorMessage() + { + return '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n"; + } +} diff --git a/vas/rest/class/PHPMailer/src/OAuth.php b/vas/rest/class/PHPMailer/src/OAuth.php new file mode 100755 index 0000000000000000000000000000000000000000..0bce7e3468c69c458b110178c0988490d747176d --- /dev/null +++ b/vas/rest/class/PHPMailer/src/OAuth.php @@ -0,0 +1,138 @@ +<?php +/** + * PHPMailer - PHP email creation and transport class. + * PHP Version 5.5. + * + * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2015 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +use League\OAuth2\Client\Grant\RefreshToken; +use League\OAuth2\Client\Provider\AbstractProvider; +use League\OAuth2\Client\Token\AccessToken; + +/** + * OAuth - OAuth2 authentication wrapper class. + * Uses the oauth2-client package from the League of Extraordinary Packages. + * + * @see http://oauth2-client.thephpleague.com + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + */ +class OAuth +{ + /** + * An instance of the League OAuth Client Provider. + * + * @var AbstractProvider + */ + protected $provider; + + /** + * The current OAuth access token. + * + * @var AccessToken + */ + protected $oauthToken; + + /** + * The user's email address, usually used as the login ID + * and also the from address when sending email. + * + * @var string + */ + protected $oauthUserEmail = ''; + + /** + * The client secret, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientSecret = ''; + + /** + * The client ID, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientId = ''; + + /** + * The refresh token, used to obtain new AccessTokens. + * + * @var string + */ + protected $oauthRefreshToken = ''; + + /** + * OAuth constructor. + * + * @param array $options Associative array containing + * `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements + */ + public function __construct($options) + { + $this->provider = $options['provider']; + $this->oauthUserEmail = $options['userName']; + $this->oauthClientSecret = $options['clientSecret']; + $this->oauthClientId = $options['clientId']; + $this->oauthRefreshToken = $options['refreshToken']; + } + + /** + * Get a new RefreshToken. + * + * @return RefreshToken + */ + protected function getGrant() + { + return new RefreshToken(); + } + + /** + * Get a new AccessToken. + * + * @return AccessToken + */ + protected function getToken() + { + return $this->provider->getAccessToken( + $this->getGrant(), + ['refresh_token' => $this->oauthRefreshToken] + ); + } + + /** + * Generate a base64-encoded OAuth token. + * + * @return string + */ + public function getOauth64() + { + // Get a new token if it's not available or has expired + if (null === $this->oauthToken or $this->oauthToken->hasExpired()) { + $this->oauthToken = $this->getToken(); + } + + return base64_encode( + 'user=' . + $this->oauthUserEmail . + "\001auth=Bearer " . + $this->oauthToken . + "\001\001" + ); + } +} diff --git a/vas/rest/class/PHPMailer/src/PHPMailer.php b/vas/rest/class/PHPMailer/src/PHPMailer.php new file mode 100755 index 0000000000000000000000000000000000000000..eb12b17120467f7fd3ee50b13efa3da433240492 --- /dev/null +++ b/vas/rest/class/PHPMailer/src/PHPMailer.php @@ -0,0 +1,4420 @@ +<?php +/** + * PHPMailer - PHP email creation and transport class. + * PHP Version 5.5. + * + * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer - PHP email creation and transport class. + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * + * @var int + */ + public $Priority; + + /** + * The character set of the message. + * + * @var string + */ + public $CharSet = 'iso-8859-1'; + + /** + * The MIME Content-type of the message. + * + * @var string + */ + public $ContentType = 'text/plain'; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * + * @var string + */ + public $Encoding = '8bit'; + + /** + * Holds the most recent mailer error message. + * + * @var string + */ + public $ErrorInfo = ''; + + /** + * The From email address for the message. + * + * @var string + */ + public $From = 'root@localhost'; + + /** + * The From name of the message. + * + * @var string + */ + public $FromName = 'Root User'; + + /** + * The envelope sender of the message. + * This will usually be turned into a Return-Path header by the receiver, + * and is the address that bounces will be sent to. + * If not empty, will be passed via `-f` to sendmail or as the 'MAIL FROM' value over SMTP. + * + * @var string + */ + public $Sender = ''; + + /** + * The Subject of the message. + * + * @var string + */ + public $Subject = ''; + + /** + * An HTML or plain text message body. + * If HTML then call isHTML(true). + * + * @var string + */ + public $Body = ''; + + /** + * The plain-text message body. + * This body can be read by mail clients that do not have HTML email + * capability such as mutt & Eudora. + * Clients that can read HTML will view the normal Body. + * + * @var string + */ + public $AltBody = ''; + + /** + * An iCal message part body. + * Only supported in simple alt or alt_inline message types + * To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator. + * + * @see http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ + * @see http://kigkonsult.se/iCalcreator/ + * + * @var string + */ + public $Ical = ''; + + /** + * The complete compiled MIME message body. + * + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * + * @var string + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * + * @var string + */ + protected $mailHeader = ''; + + /** + * Word-wrap the message body to this number of chars. + * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. + * + * @see static::STD_LINE_LENGTH + * + * @var int + */ + public $WordWrap = 0; + + /** + * Which method to use to send mail. + * Options: "mail", "sendmail", or "smtp". + * + * @var string + */ + public $Mailer = 'mail'; + + /** + * The path to the sendmail program. + * + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + /** + * Whether mail() uses a fully sendmail-compatible MTA. + * One which supports sendmail's "-oi -f" options. + * + * @var bool + */ + public $UseSendmailOptions = true; + + /** + * The email address that a reading confirmation should be sent to, also known as read receipt. + * + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * The hostname to use in the Message-ID header and as default HELO string. + * If empty, PHPMailer attempts to find one with, in order, + * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value + * 'localhost.localdomain'. + * + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * You can set your own, but it must be in the format "<id@domain>", + * as defined in RFC5322 section 3.6.4 or it will be ignored. + * + * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 + * + * @var string + */ + public $MessageID = ''; + + /** + * The message Date to be used in the Date header. + * If empty, the current date will be added. + * + * @var string + */ + public $MessageDate = ''; + + /** + * SMTP hosts. + * Either a single hostname or multiple semicolon-delimited hostnames. + * You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * You can also specify encryption type, for example: + * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). + * Hosts will be tried in order. + * + * @var string + */ + public $Host = 'localhost'; + + /** + * The default SMTP server port. + * + * @var int + */ + public $Port = 25; + + /** + * The SMTP HELO of the message. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * + * @see PHPMailer::$Hostname + * + * @var string + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', 'ssl' or 'tls'. + * + * @var string + */ + public $SMTPSecure = ''; + + /** + * Whether to enable TLS encryption automatically if a server supports it, + * even if `SMTPSecure` is not set to 'tls'. + * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. + * + * @var bool + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * + * @see PHPMailer::$Username + * @see PHPMailer::$Password + * + * @var bool + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * + * @var array + */ + public $SMTPOptions = []; + + /** + * SMTP username. + * + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * + * @var string + */ + public $Password = ''; + + /** + * SMTP auth type. + * Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2, attempted in that order if not specified. + * + * @var string + */ + public $AuthType = ''; + + /** + * An instance of the PHPMailer OAuth class. + * + * @var OAuth + */ + protected $oauth; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timeout = 300; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * * `0` No output + * * `1` Commands + * * `2` Data and commands + * * `3` As 2 plus connection status + * * `4` Low-level data output. + * + * @see SMTP::$do_debug + * + * @var int + */ + public $SMTPDebug = 0; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise. + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @see SMTP::$Debugoutput + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to keep SMTP connection open after each message. + * If this is set to true then to close the connection + * requires an explicit call to smtpClose(). + * + * @var bool + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * Only supported in `mail` and `sendmail` transports, not in SMTP. + * + * @var bool + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * + * @var array + */ + protected $SingleToArray = []; + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * + * @see https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Postfix VERP info + * + * @var bool + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * + * @var bool + */ + public $AllowEmpty = false; + + /** + * DKIM selector. + * + * @var string + */ + public $DKIM_selector = ''; + + /** + * DKIM Identity. + * Usually the email address used as the source of the email. + * + * @var string + */ + public $DKIM_identity = ''; + + /** + * DKIM passphrase. + * Used if your key is encrypted. + * + * @var string + */ + public $DKIM_passphrase = ''; + + /** + * DKIM signing domain name. + * + * @example 'example.com' + * + * @var string + */ + public $DKIM_domain = ''; + + /** + * DKIM private key file path. + * + * @var string + */ + public $DKIM_private = ''; + + /** + * DKIM private key string. + * + * If set, takes precedence over `$DKIM_private`. + * + * @var string + */ + public $DKIM_private_string = ''; + + /** + * Callback Action function name. + * + * The function that handles the result of the send email action. + * It is called out by send() for each email sent. + * + * Value can be any php callable: http://www.php.net/is_callable + * + * Parameters: + * bool $result result of the send action + * array $to email addresses of the recipients + * array $cc cc email addresses + * array $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * string $extra extra information of possible use + * "smtp_transaction_id' => last smtp transaction id + * + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace for none, or a string to use. + * + * @var string + */ + public $XMailer = ''; + + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option. + * + * @see PHPMailer::validateAddress() + * + * @var string|callable + */ + public static $validator = 'php'; + + /** + * An instance of the SMTP sender class. + * + * @var SMTP + */ + protected $smtp; + + /** + * The array of 'to' names and addresses. + * + * @var array + */ + protected $to = []; + + /** + * The array of 'cc' names and addresses. + * + * @var array + */ + protected $cc = []; + + /** + * The array of 'bcc' names and addresses. + * + * @var array + */ + protected $bcc = []; + + /** + * The array of reply-to names and addresses. + * + * @var array + */ + protected $ReplyTo = []; + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * + * @var array + */ + protected $all_recipients = []; + + /** + * An array of names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $all_recipients + * and one of $to, $cc, or $bcc. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + * + * @var array + */ + protected $RecipientsQueue = []; + + /** + * An array of reply-to names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $ReplyTo. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$ReplyTo + * + * @var array + */ + protected $ReplyToQueue = []; + + /** + * The array of attachments. + * + * @var array + */ + protected $attachment = []; + + /** + * The array of custom headers. + * + * @var array + */ + protected $CustomHeader = []; + + /** + * The most recent Message-ID (including angular brackets). + * + * @var string + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * + * @var string + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * + * @var array + */ + protected $boundary = []; + + /** + * The array of available languages. + * + * @var array + */ + protected $language = []; + + /** + * The number of errors encountered. + * + * @var int + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * + * @var string + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * + * @var string + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * + * @var string + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * + * @var string + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * + * @var bool + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * + * @var string + */ + protected $uniqueid = ''; + + /** + * The PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.0.3'; + + /** + * Error severity: message only, continue processing. + * + * @var int + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + * + * @var int + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + * + * @var int + */ + const STOP_CRITICAL = 2; + + /** + * SMTP RFC standard line ending. + * + * @var string + */ + protected static $LE = "\r\n"; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * The lower maximum line length allowed by RFC 2822 section 2.1.1. + * This length does NOT include the line break + * 76 means that lines will be 77 or 78 chars depending on whether + * the line break format is LF or CRLF; both are valid. + * + * @var int + */ + const STD_LINE_LENGTH = 76; + + /** + * Constructor. + * + * @param bool $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = null) + { + if (null !== $exceptions) { + $this->exceptions = (bool) $exceptions; + } + //Pick an appropriate debug output format automatically + $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html'); + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + $this->smtpClose(); + } + + /** + * Call mail() in a safe_mode-aware fashion. + * Also, unless sendmail_path points to sendmail (or something that + * claims to be sendmail), don't pass params (not a perfect fix, + * but it will do). + * + * @param string $to To + * @param string $subject Subject + * @param string $body Message Body + * @param string $header Additional Header(s) + * @param string|null $params Params + * + * @return bool + */ + private function mailPassthru($to, $subject, $body, $header, $params) + { + //Check overloading of mail function to avoid double-encoding + if (ini_get('mbstring.func_overload') & 1) { + $subject = $this->secureHeader($subject); + } else { + $subject = $this->encodeHeader($this->secureHeader($subject)); + } + //Calling mail() with null params breaks + if (!$this->UseSendmailOptions or null === $params) { + $result = @mail($to, $subject, $body, $header); + } else { + $result = @mail($to, $subject, $body, $header, $params); + } + + return $result; + } + + /** + * Output debugging info via user-defined method. + * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). + * + * @see PHPMailer::$Debugoutput + * @see PHPMailer::$SMTPDebug + * + * @param string $str + */ + protected function edebug($str) + { + if ($this->SMTPDebug <= 0) { + return; + } + //Is this a PSR-3 logger? + if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, ['error_log', 'html', 'echo']) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $this->SMTPDebug); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "<br>\n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * + * @param bool $isHtml True for HTML mode + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = 'text/html'; + } else { + $this->ContentType = 'text/plain'; + } + } + + /** + * Send messages using SMTP. + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'qmail')) { + $this->Sendmail = '/var/qmail/bin/qmail-inject'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'qmail'; + } + + /** + * Add a "To" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addAddress($address, $name = '') + { + return $this->addOrEnqueueAnAddress('to', $address, $name); + } + + /** + * Add a "CC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('cc', $address, $name); + } + + /** + * Add a "BCC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addBCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('bcc', $address, $name); + } + + /** + * Add a "Reply-To" address. + * + * @param string $address The email address to reply to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addReplyTo($address, $name = '') + { + return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer + * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still + * be modified after calling this function), addition of such addresses is delayed until send(). + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + $pos = strrpos($address, '@'); + if (false === $pos) { + // At-sign is missing. + $error_message = sprintf('%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $params = [$kind, $address, $name]; + // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + if ($this->has8bitChars(substr($address, ++$pos)) and static::idnSupported()) { + if ('Reply-To' != $kind) { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + + return true; + } + } else { + if (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; + + return true; + } + } + + return false; + } + + // Immediately add standard addresses without IDN. + return call_user_func_array([$this, 'addAnAddress'], $params); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addAnAddress($kind, $address, $name = '') + { + if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) { + $error_message = sprintf('%s: %s', + $this->lang('Invalid recipient kind'), + $kind); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if (!static::validateAddress($address)) { + $error_message = sprintf('%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if ('Reply-To' != $kind) { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + $this->{$kind}[] = [$address, $name]; + $this->all_recipients[strtolower($address)] = true; + + return true; + } + } else { + if (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = [$address, $name]; + + return true; + } + } + + return false; + } + + /** + * Parse and validate a string containing one or more RFC822-style comma-separated email addresses + * of the form "display name <address>" into an array of name/address pairs. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Note that quotes in the name part are removed. + * + * @see http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + * + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * + * @return array + */ + public static function parseAddresses($addrstr, $useimap = true) + { + $addresses = []; + if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { + //Use this built-in parser if it's available + $list = imap_rfc822_parse_adrlist($addrstr, ''); + foreach ($list as $address) { + if ('.SYNTAX-ERROR.' != $address->host) { + if (static::validateAddress($address->mailbox . '@' . $address->host)) { + $addresses[] = [ + 'name' => (property_exists($address, 'personal') ? $address->personal : ''), + 'address' => $address->mailbox . '@' . $address->host, + ]; + } + } + } + } else { + //Use this simpler parser + $list = explode(',', $addrstr); + foreach ($list as $address) { + $address = trim($address); + //Is there a separate name part? + if (strpos($address, '<') === false) { + //No separate name, just use the whole thing + if (static::validateAddress($address)) { + $addresses[] = [ + 'name' => '', + 'address' => $address, + ]; + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + if (static::validateAddress($email)) { + $addresses[] = [ + 'name' => trim(str_replace(['"', "'"], '', $name)), + 'address' => $email, + ]; + } + } + } + } + + return $addresses; + } + + /** + * Set the From and FromName properties. + * + * @param string $address + * @param string $name + * @param bool $auto Whether to also set the Sender address, defaults to true + * + * @throws Exception + * + * @return bool + */ + public function setFrom($address, $name = '', $auto = true) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + // Don't validate now addresses with IDN. Will be done in send(). + $pos = strrpos($address, '@'); + if (false === $pos or + (!$this->has8bitChars(substr($address, ++$pos)) or !static::idnSupported()) and + !static::validateAddress($address)) { + $error_message = sprintf('%s (From): %s', + $this->lang('invalid_address'), + $address); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto) { + if (empty($this->Sender)) { + $this->Sender = $address; + } + } + + return true; + } + + /** + * Return the Message-ID header of the last email. + * Technically this is the value from the last time the headers were created, + * but it's also the message ID of the last sent message except in + * pathological cases. + * + * @return string + */ + public function getLastMessageID() + { + return $this->lastMessageID; + } + + /** + * Check that a string looks like an email address. + * Validation patterns supported: + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * + * ```php + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * ``` + * + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * + * @param string $address The email address to check + * @param string|callable $patternselect Which pattern to use + * + * @return bool + */ + public static function validateAddress($address, $patternselect = null) + { + if (null === $patternselect) { + $patternselect = static::$validator; + } + if (is_callable($patternselect)) { + return call_user_func($patternselect, $address); + } + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { + return false; + } + switch ($patternselect) { + case 'pcre': //Kept for BC + case 'pcre8': + /* + * A more complex and more permissive version of the RFC5322 regex on which FILTER_VALIDATE_EMAIL + * is based. + * In addition to the addresses allowed by filter_var, also permits: + * * dotless domains: `a@b` + * * comments: `1234 @ local(blah) .machine .example` + * * quoted elements: `'"test blah"@example.org'` + * * numeric TLDs: `a@b.123` + * * unbracketed IPv4 literals: `a@192.168.0.1` + * * IPv6 literals: 'first.last@[IPv6:a1::]' + * Not all of these will necessarily work for sending! + * + * @see http://squiloople.com/2009/12/20/email-address-validation/ + * @copyright 2009-2010 Michael Rushton + * Feel free to use and redistribute this code. But please keep this copyright notice. + */ + return (bool) preg_match( + '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . + '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . + '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . + '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . + '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . + '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . + '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . + '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', + $address + ); + case 'html5': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * + * @see http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + */ + return (bool) preg_match( + '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . + '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', + $address + ); + case 'php': + default: + return (bool) filter_var($address, FILTER_VALIDATE_EMAIL); + } + } + + /** + * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the + * `intl` and `mbstring` PHP extensions. + * + * @return bool `true` if required functions for IDN support are present + */ + public static function idnSupported() + { + return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding'); + } + + /** + * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. + * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. + * This function silently returns unmodified address if: + * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) + * - Conversion to punycode is impossible (e.g. required PHP functions are not available) + * or fails for any reason (e.g. domain contains characters not allowed in an IDN). + * + * @see PHPMailer::$CharSet + * + * @param string $address The email address to convert + * + * @return string The encoded address in ASCII form + */ + public function punyencodeAddress($address) + { + // Verify we have required functions, CharSet, and at-sign. + $pos = strrpos($address, '@'); + if (static::idnSupported() and + !empty($this->CharSet) and + false !== $pos + ) { + $domain = substr($address, ++$pos); + // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) { + $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + //Ignore IDE complaints about this line - method signature changed in PHP 5.4 + $errorcode = 0; + $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46); + if (false !== $punycode) { + return substr($address, 0, $pos) . $punycode; + } + } + } + + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * + * @throws Exception + * + * @return bool false on error - See the ErrorInfo property for details of the error + */ + public function send() + { + try { + if (!$this->preSend()) { + return false; + } + + return $this->postSend(); + } catch (Exception $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Prepare a message for sending. + * + * @throws Exception + * + * @return bool + */ + public function preSend() + { + if ('smtp' == $this->Mailer or + ('mail' == $this->Mailer and stripos(PHP_OS, 'WIN') === 0) + ) { + //SMTP mandates RFC-compliant line endings + //and it's also used with mail() on Windows + static::setLE("\r\n"); + } else { + //Maintain backward compatibility with legacy Linux command line mailers + static::setLE(PHP_EOL); + } + //Check for buggy PHP versions that add a header with an incorrect line break + if (ini_get('mail.add_x_header') == 1 + and 'mail' == $this->Mailer + and stripos(PHP_OS, 'WIN') === 0 + and ((version_compare(PHP_VERSION, '7.0.0', '>=') + and version_compare(PHP_VERSION, '7.0.17', '<')) + or (version_compare(PHP_VERSION, '7.1.0', '>=') + and version_compare(PHP_VERSION, '7.1.3', '<'))) + ) { + trigger_error( + 'Your version of PHP is affected by a bug that may result in corrupted messages.' . + ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . + ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', + E_USER_WARNING + ); + } + + try { + $this->error_count = 0; // Reset errors + $this->mailHeader = ''; + + // Dequeue recipient and Reply-To addresses with IDN + foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { + $params[1] = $this->punyencodeAddress($params[1]); + call_user_func_array([$this, 'addAnAddress'], $params); + } + if (count($this->to) + count($this->cc) + count($this->bcc) < 1) { + throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL); + } + + // Validate From, Sender, and ConfirmReadingTo addresses + foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) { + $this->$address_kind = trim($this->$address_kind); + if (empty($this->$address_kind)) { + continue; + } + $this->$address_kind = $this->punyencodeAddress($this->$address_kind); + if (!static::validateAddress($this->$address_kind)) { + $error_message = sprintf('%s (%s): %s', + $this->lang('invalid_address'), + $address_kind, + $this->$address_kind); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + } + + // Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = 'multipart/alternative'; + } + + $this->setMessageType(); + // Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty and empty($this->Body)) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + + //Trim subject consistently + $this->Subject = trim($this->Subject); + // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + $this->MIMEHeader = ''; + $this->MIMEBody = $this->createBody(); + // createBody may have added some headers, so retain them + $tempheaders = $this->MIMEHeader; + $this->MIMEHeader = $this->createHeader(); + $this->MIMEHeader .= $tempheaders; + + // To capture the complete message when using mail(), create + // an extra header list which createHeader() doesn't fold in + if ('mail' == $this->Mailer) { + if (count($this->to) > 0) { + $this->mailHeader .= $this->addrAppend('To', $this->to); + } else { + $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + $this->mailHeader .= $this->headerLine( + 'Subject', + $this->encodeHeader($this->secureHeader($this->Subject)) + ); + } + + // Sign with DKIM if enabled + if (!empty($this->DKIM_domain) + and !empty($this->DKIM_selector) + and (!empty($this->DKIM_private_string) + or (!empty($this->DKIM_private) and file_exists($this->DKIM_private)) + ) + ) { + $header_dkim = $this->DKIM_Add( + $this->MIMEHeader . $this->mailHeader, + $this->encodeHeader($this->secureHeader($this->Subject)), + $this->MIMEBody + ); + $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . static::$LE . + static::normalizeBreaks($header_dkim) . static::$LE; + } + + return true; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Actually send a message via the selected mechanism. + * + * @throws Exception + * + * @return bool + */ + public function postSend() + { + try { + // Choose the mailer and send through it + switch ($this->Mailer) { + case 'sendmail': + case 'qmail': + return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); + case 'smtp': + return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); + case 'mail': + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + default: + $sendMethod = $this->Mailer . 'Send'; + if (method_exists($this, $sendMethod)) { + return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); + } + + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + } + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + } + + return false; + } + + /** + * Send mail using the $Sendmail program. + * + * @see PHPMailer::$Sendmail + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function sendmailSend($header, $body) + { + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) and self::isShellSafe($this->Sender)) { + if ('qmail' == $this->Mailer) { + $sendmailFmt = '%s -f%s'; + } else { + $sendmailFmt = '%s -oi -f%s -t'; + } + } else { + if ('qmail' == $this->Mailer) { + $sendmailFmt = '%s'; + } else { + $sendmailFmt = '%s -oi -t'; + } + } + + $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, 'To: ' . $toAddr . "\n"); + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + [$toAddr], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + + return true; + } + + /** + * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * + * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report + * + * @param string $string The string to be validated + * + * @return bool + */ + protected static function isShellSafe($string) + { + // Future-proof + if (escapeshellcmd($string) !== $string + or !in_array(escapeshellarg($string), ["'$string'", "\"$string\""]) + ) { + return false; + } + + $length = strlen($string); + + for ($i = 0; $i < $length; ++$i) { + $c = $string[$i]; + + // All other characters have a special meaning in at least one common shell, including = and +. + // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + // Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** + * Send mail using the PHP mail() function. + * + * @see http://www.php.net/manual/en/book.mail.php + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function mailSend($header, $body) + { + $toArr = []; + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = implode(', ', $toArr); + + $params = null; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + if (!empty($this->Sender) and static::validateAddress($this->Sender)) { + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html + //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html + //Example problem: https://www.drupal.org/node/1057954 + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } + } + if (!empty($this->Sender) and static::validateAddress($this->Sender)) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + } + $result = false; + if ($this->SingleTo and count($toArr) > 1) { + foreach ($toArr as $toAddr) { + $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); + $this->doCallback($result, [$toAddr], $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + } else { + $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); + $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if (!$result) { + throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL); + } + + return true; + } + + /** + * Get an instance to use for SMTP operations. + * Override this function to load your own SMTP implementation, + * or set one with setSMTPInstance. + * + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP(); + } + + return $this->smtp; + } + + /** + * Provide an instance to use for SMTP operations. + * + * @param SMTP $smtp + * + * @return SMTP + */ + public function setSMTPInstance(SMTP $smtp) + { + $this->smtp = $smtp; + + return $this->smtp; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * + * @see PHPMailer::setSMTPInstance() to use a different class. + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function smtpSend($header, $body) + { + $bad_rcpt = []; + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + //Sender already validated in preSend() + if ('' == $this->Sender) { + $smtp_from = $this->From; + } else { + $smtp_from = $this->Sender; + } + if (!$this->smtp->mail($smtp_from)) { + $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); + throw new Exception($this->ErrorInfo, self::STOP_CRITICAL); + } + + $callbacks = []; + // Attempt to send to all recipients + foreach ([$this->to, $this->cc, $this->bcc] as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0])) { + $error = $this->smtp->getError(); + $bad_rcpt[] = ['to' => $to[0], 'error' => $error['detail']]; + $isSent = false; + } else { + $isSent = true; + } + + $callbacks[] = ['issent'=>$isSent, 'to'=>$to[0]]; + } + } + + // Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { + throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + + $smtp_transaction_id = $this->smtp->getLastTransactionID(); + + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + + foreach ($callbacks as $cb) { + $this->doCallback( + $cb['issent'], + [$cb['to']], + [], + [], + $this->Subject, + $body, + $this->From, + ['smtp_transaction_id' => $smtp_transaction_id] + ); + } + + //Create error message for any bad addresses + if (count($bad_rcpt) > 0) { + $errstr = ''; + foreach ($bad_rcpt as $bad) { + $errstr .= $bad['to'] . ': ' . $bad['error']; + } + throw new Exception( + $this->lang('recipients_failed') . $errstr, + self::STOP_CONTINUE + ); + } + + return true; + } + + /** + * Initiate a connection to an SMTP server. + * Returns false if the operation failed. + * + * @param array $options An array of options compatible with stream_context_create() + * + * @throws Exception + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @return bool + */ + public function smtpConnect($options = null) + { + if (null === $this->smtp) { + $this->smtp = $this->getSMTPInstance(); + } + + //If no options are provided, use whatever is set in the instance + if (null === $options) { + $options = $this->SMTPOptions; + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = []; + if (!preg_match( + '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/', + trim($hostentry), + $hostinfo + )) { + static::edebug($this->lang('connect_host') . ' ' . $hostentry); + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + + //Check the host name is a valid name or IP address before trying to use it + if (!static::isValidHost($hostinfo[3])) { + static::edebug($this->lang('connect_host') . ' ' . $hostentry); + continue; + } + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ('tls' == $this->SMTPSecure); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ('tls' == $hostinfo[2]) { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA256'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (int) $hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS and $sslext and 'ssl' != $secure and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new Exception($this->lang('connect_host')); + } + // We must resend EHLO after TLS negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->oauth + ) + ) { + throw new Exception($this->lang('authenticate')); + } + } + + return true; + } catch (Exception $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions and null !== $lastexception) { + throw $lastexception; + } + + return false; + } + + /** + * Close the active SMTP session if one exists. + */ + public function smtpClose() + { + if (null !== $this->smtp) { + if ($this->smtp->connected()) { + $this->smtp->quit(); + $this->smtp->close(); + } + } + } + + /** + * Set the language for error messages. + * Returns false if it cannot load the language file. + * The default language is English. + * + * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * + * @return bool + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + // Backwards compatibility for renamed language codes + $renamed_langcodes = [ + 'br' => 'pt_br', + 'cz' => 'cs', + 'dk' => 'da', + 'no' => 'nb', + 'se' => 'sv', + 'sr' => 'rs', + ]; + + if (isset($renamed_langcodes[$langcode])) { + $langcode = $renamed_langcodes[$langcode]; + } + + // Define full set of translatable strings in English + $PHPMAILER_LANG = [ + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'data_not_accepted' => 'SMTP Error: data not accepted.', + 'empty_message' => 'Message body empty', + 'encoding' => 'Unknown encoding: ', + 'execute' => 'Could not execute: ', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'from_failed' => 'The following From address failed: ', + 'instantiate' => 'Could not instantiate mail function.', + 'invalid_address' => 'Invalid address: ', + 'mailer_not_supported' => ' mailer is not supported.', + 'provide_address' => 'You must provide at least one recipient email address.', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'signing' => 'Signing Error: ', + 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_error' => 'SMTP server error: ', + 'variable_set' => 'Cannot set or reset variable: ', + 'extension_missing' => 'Extension missing: ', + ]; + if (empty($lang_path)) { + // Calculate an absolute path so it can work if CWD is not here + $lang_path = __DIR__ . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; + } + //Validate $langcode + if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { + $langcode = 'en'; + } + $foundlang = true; + $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; + // There is no English translation file + if ('en' != $langcode) { + // Make sure language file path is readable + if (!file_exists($lang_file)) { + $foundlang = false; + } else { + // Overwrite language-specific strings. + // This way we'll never have missing translation keys. + $foundlang = include $lang_file; + } + } + $this->language = $PHPMAILER_LANG; + + return (bool) $foundlang; // Returns false if language not found + } + + /** + * Get the array of strings for the current language. + * + * @return array + */ + public function getTranslations() + { + return $this->language; + } + + /** + * Create recipient headers. + * + * @param string $type + * @param array $addr An array of recipients, + * where each recipient is a 2-element indexed array with element 0 containing an address + * and element 1 containing a name, like: + * [['joe@example.com', 'Joe User'], ['zoe@example.com', 'Zoe User']] + * + * @return string + */ + public function addrAppend($type, $addr) + { + $addresses = []; + foreach ($addr as $address) { + $addresses[] = $this->addrFormat($address); + } + + return $type . ': ' . implode(', ', $addresses) . static::$LE; + } + + /** + * Format an address for use in a message header. + * + * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name like + * ['joe@example.com', 'Joe User'] + * + * @return string + */ + public function addrFormat($addr) + { + if (empty($addr[1])) { // No name provided + return $this->secureHeader($addr[0]); + } + + return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader( + $addr[0] + ) . '>'; + } + + /** + * Word-wrap message. + * For use with mailers that do not automatically perform wrapping + * and for quoted-printable encoded messages. + * Original written by philippe. + * + * @param string $message The message to wrap + * @param int $length The line length to wrap to + * @param bool $qp_mode Whether to run in Quoted-Printable mode + * + * @return string + */ + public function wrapText($message, $length, $qp_mode = false) + { + if ($qp_mode) { + $soft_break = sprintf(' =%s', static::$LE); + } else { + $soft_break = static::$LE; + } + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = 'utf-8' == strtolower($this->CharSet); + $lelen = strlen(static::$LE); + $crlflen = strlen(static::$LE); + + $message = static::normalizeBreaks($message); + //Remove a trailing line break + if (substr($message, -$lelen) == static::$LE) { + $message = substr($message, 0, -$lelen); + } + + //Split message into lines + $lines = explode(static::$LE, $message); + //Message will be rebuilt in here + $message = ''; + foreach ($lines as $line) { + $words = explode(' ', $line); + $buf = ''; + $firstword = true; + foreach ($words as $word) { + if ($qp_mode and (strlen($word) > $length)) { + $space_left = $length - strlen($buf) - $crlflen; + if (!$firstword) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif ('=' == substr($word, $len - 1, 1)) { + --$len; + } elseif ('=' == substr($word, $len - 2, 1)) { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf('=%s', static::$LE); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + if ($length <= 0) { + break; + } + $len = $length; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif ('=' == substr($word, $len - 1, 1)) { + --$len; + } elseif ('=' == substr($word, $len - 2, 1)) { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf('=%s', static::$LE); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + if (!$firstword) { + $buf .= ' '; + } + $buf .= $word; + + if (strlen($buf) > $length and '' != $buf_o) { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + $firstword = false; + } + $message .= $buf . static::$LE; + } + + return $message; + } + + /** + * Find the last character boundary prior to $maxLength in a utf-8 + * quoted-printable encoded string. + * Original written by Colin Brown. + * + * @param string $encodedText utf-8 QP text + * @param int $maxLength Find the last character boundary prior to this length + * + * @return int + */ + public function utf8CharBoundary($encodedText, $maxLength) + { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, '='); + if (false !== $encodedCharPos) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { + // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + if ($encodedCharPos > 0) { + $maxLength -= $lookBack - $encodedCharPos; + } + $foundSplitPos = true; + } elseif ($dec >= 192) { + // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength -= $lookBack - $encodedCharPos; + $foundSplitPos = true; + } elseif ($dec < 192) { + // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + + return $maxLength; + } + + /** + * Apply word wrapping to the message body. + * Wraps the message body to the number of chars set in the WordWrap property. + * You should only do this to plain-text bodies as wrapping HTML tags may break them. + * This is called automatically by createBody(), so you don't need to call it yourself. + */ + public function setWordWrap() + { + if ($this->WordWrap < 1) { + return; + } + + switch ($this->message_type) { + case 'alt': + case 'alt_inline': + case 'alt_attach': + case 'alt_inline_attach': + $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->wrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assemble message headers. + * + * @return string The assembled headers + */ + public function createHeader() + { + $result = ''; + + $result .= $this->headerLine('Date', '' == $this->MessageDate ? self::rfcDate() : $this->MessageDate); + + // To be created automatically by mail() + if ($this->SingleTo) { + if ('mail' != $this->Mailer) { + foreach ($this->to as $toaddr) { + $this->SingleToArray[] = $this->addrFormat($toaddr); + } + } + } else { + if (count($this->to) > 0) { + if ('mail' != $this->Mailer) { + $result .= $this->addrAppend('To', $this->to); + } + } elseif (count($this->cc) == 0) { + $result .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + } + + $result .= $this->addrAppend('From', [[trim($this->From), $this->FromName]]); + + // sendmail and mail() extract Cc from the header before sending + if (count($this->cc) > 0) { + $result .= $this->addrAppend('Cc', $this->cc); + } + + // sendmail and mail() extract Bcc from the header before sending + if (( + 'sendmail' == $this->Mailer or 'qmail' == $this->Mailer or 'mail' == $this->Mailer + ) + and count($this->bcc) > 0 + ) { + $result .= $this->addrAppend('Bcc', $this->bcc); + } + + if (count($this->ReplyTo) > 0) { + $result .= $this->addrAppend('Reply-To', $this->ReplyTo); + } + + // mail() sets the subject itself + if ('mail' != $this->Mailer) { + $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); + } + + // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 + // https://tools.ietf.org/html/rfc5322#section-3.6.4 + if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { + $this->lastMessageID = $this->MessageID; + } else { + $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); + } + $result .= $this->headerLine('Message-ID', $this->lastMessageID); + if (null !== $this->Priority) { + $result .= $this->headerLine('X-Priority', $this->Priority); + } + if ('' == $this->XMailer) { + $result .= $this->headerLine( + 'X-Mailer', + 'PHPMailer ' . self::VERSION . ' (https://github.com/PHPMailer/PHPMailer)' + ); + } else { + $myXmailer = trim($this->XMailer); + if ($myXmailer) { + $result .= $this->headerLine('X-Mailer', $myXmailer); + } + } + + if ('' != $this->ConfirmReadingTo) { + $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>'); + } + + // Add custom headers + foreach ($this->CustomHeader as $header) { + $result .= $this->headerLine( + trim($header[0]), + $this->encodeHeader(trim($header[1])) + ); + } + if (!$this->sign_key_file) { + $result .= $this->headerLine('MIME-Version', '1.0'); + $result .= $this->getMailMIME(); + } + + return $result; + } + + /** + * Get the message MIME type headers. + * + * @return string + */ + public function getMailMIME() + { + $result = ''; + $ismultipart = true; + switch ($this->message_type) { + case 'inline': + $result .= $this->headerLine('Content-Type', 'multipart/related;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'attach': + case 'inline_attach': + case 'alt_attach': + case 'alt_inline_attach': + $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'alt': + case 'alt_inline': + $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + default: + // Catches case 'plain': and case '': + $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); + $ismultipart = false; + break; + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $this->Encoding) { + // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + if ($ismultipart) { + if ('8bit' == $this->Encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', '8bit'); + } + // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible + } else { + $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); + } + } + + if ('mail' != $this->Mailer) { + $result .= static::$LE; + } + + return $result; + } + + /** + * Returns the whole MIME message. + * Includes complete headers and body. + * Only valid post preSend(). + * + * @see PHPMailer::preSend() + * + * @return string + */ + public function getSentMIMEMessage() + { + return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . static::$LE . static::$LE . $this->MIMEBody; + } + + /** + * Create a unique ID to use for boundaries. + * + * @return string + */ + protected function generateId() + { + $len = 32; //32 bytes = 256 bits + if (function_exists('random_bytes')) { + $bytes = random_bytes($len); + } elseif (function_exists('openssl_random_pseudo_bytes')) { + $bytes = openssl_random_pseudo_bytes($len); + } else { + //Use a hash to force the length to the same as the other methods + $bytes = hash('sha256', uniqid((string) mt_rand(), true), true); + } + + //We don't care about messing up base64 format here, just want a random string + return str_replace(['=', '+', '/'], '', base64_encode(hash('sha256', $bytes, true))); + } + + /** + * Assemble the message body. + * Returns an empty string on failure. + * + * @throws Exception + * + * @return string The assembled message body + */ + public function createBody() + { + $body = ''; + //Create unique IDs and preset boundaries + $this->uniqueid = $this->generateId(); + $this->boundary[1] = 'b1_' . $this->uniqueid; + $this->boundary[2] = 'b2_' . $this->uniqueid; + $this->boundary[3] = 'b3_' . $this->uniqueid; + + if ($this->sign_key_file) { + $body .= $this->getMailMIME() . static::$LE; + } + + $this->setWordWrap(); + + $bodyEncoding = $this->Encoding; + $bodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ('8bit' == $bodyEncoding and !$this->has8bitChars($this->Body)) { + $bodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $bodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the body part only + if ('base64' != $this->Encoding and static::hasLineLongerThanMax($this->Body)) { + $bodyEncoding = 'quoted-printable'; + } + + $altBodyEncoding = $this->Encoding; + $altBodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ('8bit' == $altBodyEncoding and !$this->has8bitChars($this->AltBody)) { + $altBodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $altBodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the alt body part only + if ('base64' != $altBodyEncoding and static::hasLineLongerThanMax($this->AltBody)) { + $altBodyEncoding = 'quoted-printable'; + } + //Use this as a preamble in all multipart message types + $mimepre = 'This is a multi-part message in MIME format.' . static::$LE; + switch ($this->message_type) { + case 'inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[1]); + break; + case 'attach': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + $body .= static::$LE; + } + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[2], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + } + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt_inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[2]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[3]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + default: + // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types + //Reset the `Encoding` property in case we changed it for line length reasons + $this->Encoding = $bodyEncoding; + $body .= $this->encodeString($this->Body, $this->Encoding); + break; + } + + if ($this->isError()) { + $body = ''; + if ($this->exceptions) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + } elseif ($this->sign_key_file) { + try { + if (!defined('PKCS7_TEXT')) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + // @TODO would be nice to use php://temp streams here + $file = tempnam(sys_get_temp_dir(), 'mail'); + if (false === file_put_contents($file, $body)) { + throw new Exception($this->lang('signing') . ' Could not write temp file'); + } + $signed = tempnam(sys_get_temp_dir(), 'signed'); + //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197 + if (empty($this->sign_extracerts_file)) { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [] + ); + } else { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [], + PKCS7_DETACHED, + $this->sign_extracerts_file + ); + } + @unlink($file); + if ($sign) { + $body = file_get_contents($signed); + @unlink($signed); + //The message returned by openssl contains both headers and body, so need to split them up + $parts = explode("\n\n", $body, 2); + $this->MIMEHeader .= $parts[0] . static::$LE . static::$LE; + $body = $parts[1]; + } else { + @unlink($signed); + throw new Exception($this->lang('signing') . openssl_error_string()); + } + } catch (Exception $exc) { + $body = ''; + if ($this->exceptions) { + throw $exc; + } + } + } + + return $body; + } + + /** + * Return the start of a message boundary. + * + * @param string $boundary + * @param string $charSet + * @param string $contentType + * @param string $encoding + * + * @return string + */ + protected function getBoundary($boundary, $charSet, $contentType, $encoding) + { + $result = ''; + if ('' == $charSet) { + $charSet = $this->CharSet; + } + if ('' == $contentType) { + $contentType = $this->ContentType; + } + if ('' == $encoding) { + $encoding = $this->Encoding; + } + $result .= $this->textLine('--' . $boundary); + $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); + $result .= static::$LE; + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); + } + $result .= static::$LE; + + return $result; + } + + /** + * Return the end of a message boundary. + * + * @param string $boundary + * + * @return string + */ + protected function endBoundary($boundary) + { + return static::$LE . '--' . $boundary . '--' . static::$LE; + } + + /** + * Set the message type. + * PHPMailer only supports some preset message types, not arbitrary MIME structures. + */ + protected function setMessageType() + { + $type = []; + if ($this->alternativeExists()) { + $type[] = 'alt'; + } + if ($this->inlineImageExists()) { + $type[] = 'inline'; + } + if ($this->attachmentExists()) { + $type[] = 'attach'; + } + $this->message_type = implode('_', $type); + if ('' == $this->message_type) { + //The 'plain' message_type refers to the message having a single body element, not that it is plain-text + $this->message_type = 'plain'; + } + } + + /** + * Format a header line. + * + * @param string $name + * @param string|int $value + * + * @return string + */ + public function headerLine($name, $value) + { + return $name . ': ' . $value . static::$LE; + } + + /** + * Return a formatted mail line. + * + * @param string $value + * + * @return string + */ + public function textLine($value) + { + return $value . static::$LE; + } + + /** + * Add an attachment from a path on the filesystem. + * Never use a user-supplied path to a file! + * Returns false if the file could not be found or read. + * + * @param string $path Path to the attachment + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool + */ + public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') + { + try { + if (!@is_file($path)) { + throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($path); + } + + $filename = basename($path); + if ('' == $name) { + $name = $filename; + } + + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $name, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Return the array of attachments. + * + * @return array + */ + public function getAttachments() + { + return $this->attachment; + } + + /** + * Attach all file, string, and binary attachments to the message. + * Returns an empty string on failure. + * + * @param string $disposition_type + * @param string $boundary + * + * @return string + */ + protected function attachAll($disposition_type, $boundary) + { + // Return text of body + $mime = []; + $cidUniq = []; + $incl = []; + + // Add all attachments + foreach ($this->attachment as $attachment) { + // Check if it is a valid disposition_filter + if ($attachment[6] == $disposition_type) { + // Check for string attachment + $string = ''; + $path = ''; + $bString = $attachment[5]; + if ($bString) { + $string = $attachment[0]; + } else { + $path = $attachment[0]; + } + + $inclhash = hash('sha256', serialize($attachment)); + if (in_array($inclhash, $incl)) { + continue; + } + $incl[] = $inclhash; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + if ('inline' == $disposition and array_key_exists($cid, $cidUniq)) { + continue; + } + $cidUniq[$cid] = true; + + $mime[] = sprintf('--%s%s', $boundary, static::$LE); + //Only include a filename property if we have one + if (!empty($name)) { + $mime[] = sprintf( + 'Content-Type: %s; name="%s"%s', + $type, + $this->encodeHeader($this->secureHeader($name)), + static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Type: %s%s', + $type, + static::$LE + ); + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $encoding) { + $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE); + } + + if (!empty($cid)) { + $mime[] = sprintf('Content-ID: <%s>%s', $cid, static::$LE); + } + + // If a filename contains any of these chars, it should be quoted, + // but not otherwise: RFC2183 & RFC2045 5.1 + // Fixes a warning in IETF's msglint MIME checker + // Allow for bypassing the Content-Disposition header totally + if (!(empty($disposition))) { + $encoded_name = $this->encodeHeader($this->secureHeader($name)); + if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename="%s"%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } else { + if (!empty($encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename=%s%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Disposition: %s%s', + $disposition, + static::$LE . static::$LE + ); + } + } + } else { + $mime[] = static::$LE; + } + + // Encode as string attachment + if ($bString) { + $mime[] = $this->encodeString($string, $encoding); + } else { + $mime[] = $this->encodeFile($path, $encoding); + } + if ($this->isError()) { + return ''; + } + $mime[] = static::$LE; + } + } + + $mime[] = sprintf('--%s--%s', $boundary, static::$LE); + + return implode('', $mime); + } + + /** + * Encode a file attachment in requested format. + * Returns an empty string on failure. + * + * @param string $path The full path to the file + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * + * @throws Exception + * + * @return string + */ + protected function encodeFile($path, $encoding = 'base64') + { + try { + if (!file_exists($path)) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = file_get_contents($path); + if (false === $file_buffer) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = $this->encodeString($file_buffer, $encoding); + + return $file_buffer; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + + return ''; + } + } + + /** + * Encode a string in requested format. + * Returns an empty string on failure. + * + * @param string $str The text to encode + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable + * + * @return string + */ + public function encodeString($str, $encoding = 'base64') + { + $encoded = ''; + switch (strtolower($encoding)) { + case 'base64': + $encoded = chunk_split( + base64_encode($str), + static::STD_LINE_LENGTH, + static::$LE + ); + break; + case '7bit': + case '8bit': + $encoded = static::normalizeBreaks($str); + // Make sure it ends with a line break + if (substr($encoded, -(strlen(static::$LE))) != static::$LE) { + $encoded .= static::$LE; + } + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->encodeQP($str); + break; + default: + $this->setError($this->lang('encoding') . $encoding); + break; + } + + return $encoded; + } + + /** + * Encode a header value (not including its label) optimally. + * Picks shortest of Q, B, or none. Result includes folding if needed. + * See RFC822 definitions for phrase, comment and text positions. + * + * @param string $str The header value to encode + * @param string $position What context the string will be used in + * + * @return string + */ + public function encodeHeader($str, $position = 'text') + { + $matchcount = 0; + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know the value of magic_quotes_sybase + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str == $encoded) and !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return $encoded; + } + + return "\"$encoded\""; + } + $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $matchcount = preg_match_all('/[()"]/', $str, $matches); + //fallthrough + case 'text': + default: + $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + //RFCs specify a maximum line length of 78 chars, however mail() will sometimes + //corrupt messages with headers longer than 65 chars. See #818 + $lengthsub = 'mail' == $this->Mailer ? 13 : 0; + $maxlen = static::STD_LINE_LENGTH - $lengthsub; + // Try to select the encoding which should produce the shortest output + if ($matchcount > strlen($str) / 3) { + // More than a third of the content will need encoding, so B encoding will be most efficient + $encoding = 'B'; + //This calculation is: + // max line length + // - shorten to avoid mail() corruption + // - Q/B encoding char overhead ("` =?<charset>?[QB]?<content>?=`") + // - charset name length + $maxlen = static::STD_LINE_LENGTH - $lengthsub - 8 - strlen($this->CharSet); + if ($this->hasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->base64EncodeWrapMB($str, "\n"); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + } elseif ($matchcount > 0) { + //1 or more chars need encoding, use Q-encode + $encoding = 'Q'; + //Recalc max line length for Q encoding - see comments on B encode + $maxlen = static::STD_LINE_LENGTH - $lengthsub - 8 - strlen($this->CharSet); + $encoded = $this->encodeQ($str, $position); + $encoded = $this->wrapText($encoded, $maxlen, true); + $encoded = str_replace('=' . static::$LE, "\n", trim($encoded)); + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + } elseif (strlen($str) > $maxlen) { + //No chars need encoding, but line is too long, so fold it + $encoded = trim($this->wrapText($str, $maxlen, false)); + if ($str == $encoded) { + //Wrapping nicely didn't work, wrap hard instead + $encoded = trim(chunk_split($str, static::STD_LINE_LENGTH, static::$LE)); + } + $encoded = str_replace(static::$LE, "\n", trim($encoded)); + $encoded = preg_replace('/^(.*)$/m', ' \\1', $encoded); + } else { + //No reformatting needed + return $str; + } + + return trim(static::normalizeBreaks($encoded)); + } + + /** + * Check if a string contains multi-byte characters. + * + * @param string $str multi-byte text to wrap encode + * + * @return bool + */ + public function hasMultiBytes($str) + { + if (function_exists('mb_strlen')) { + return strlen($str) > mb_strlen($str, $this->CharSet); + } + + // Assume no multibytes (we can't handle without mbstring functions anyway) + return false; + } + + /** + * Does a string contain any 8-bit chars (in any charset)? + * + * @param string $text + * + * @return bool + */ + public function has8bitChars($text) + { + return (bool) preg_match('/[\x80-\xFF]/', $text); + } + + /** + * Encode and wrap long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid. + * + * @see http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 + * + * @param string $str multi-byte text to wrap encode + * @param string $linebreak string to use as linefeed/end-of-line + * + * @return string + */ + public function base64EncodeWrapMB($str, $linebreak = null) + { + $start = '=?' . $this->CharSet . '?B?'; + $end = '?='; + $encoded = ''; + if (null === $linebreak) { + $linebreak = static::$LE; + } + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $avgLength = floor($length * $ratio * .75); + + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + ++$lookBack; + } while (strlen($chunk) > $length); + $encoded .= $chunk . $linebreak; + } + + // Chomp the last linefeed + return substr($encoded, 0, -strlen($linebreak)); + } + + /** + * Encode a string in quoted-printable format. + * According to RFC2045 section 6.7. + * + * @param string $string The text to encode + * + * @return string + */ + public function encodeQP($string) + { + return static::normalizeBreaks(quoted_printable_encode($string)); + } + + /** + * Encode a string using Q encoding. + * + * @see http://tools.ietf.org/html/rfc2047#section-4.2 + * + * @param string $str the text to encode + * @param string $position Where the text is going to be used, see the RFC for what that means + * + * @return string + */ + public function encodeQ($str, $position = 'text') + { + // There should not be any EOL in the string + $pattern = ''; + $encoded = str_replace(["\r", "\n"], '', $str); + switch (strtolower($position)) { + case 'phrase': + // RFC 2047 section 5.3 + $pattern = '^A-Za-z0-9!*+\/ -'; + break; + /* + * RFC 2047 section 5.2. + * Build $pattern without including delimiters and [] + */ + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $pattern = '\(\)"'; + /* Intentional fall through */ + case 'text': + default: + // RFC 2047 section 5.1 + // Replace every high ascii, control, =, ? and _ characters + /** @noinspection SuspiciousAssignmentsInspection */ + $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; + break; + } + $matches = []; + if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { + // If the string contains an '=', make sure it's the first thing we replace + // so as to avoid double-encoding + $eqkey = array_search('=', $matches[0]); + if (false !== $eqkey) { + unset($matches[0][$eqkey]); + array_unshift($matches[0], '='); + } + foreach (array_unique($matches[0]) as $char) { + $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); + } + } + // Replace spaces with _ (more readable than =20) + // RFC 2047 section 4.2(2) + return str_replace(' ', '_', $encoded); + } + + /** + * Add a string or binary attachment (non-filesystem). + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * + * @param string $string String attachment data + * @param string $filename Name of the attachment + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + */ + public function addStringAttachment( + $string, + $filename, + $encoding = 'base64', + $type = '', + $disposition = 'attachment' + ) { + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($filename); + } + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $filename, + 2 => basename($filename), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => 0, + ]; + } + + /** + * Add an embedded (inline) attachment from a file. + * This can include images, sounds, and just about any other document type. + * These differ from 'regular' attachments in that they are intended to be + * displayed inline with the message, not just attached for download. + * This is used in HTML messages that embed the images + * the HTML refers to using the $cid value. + * Never use a user-supplied path to a file! + * + * @param string $path Path to the attachment + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File MIME type + * @param string $disposition Disposition to use + * + * @return bool True on successfully adding an attachment + */ + public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') + { + if (!@is_file($path)) { + $this->setError($this->lang('file_access') . $path); + + return false; + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($path); + } + + $filename = basename($path); + if ('' == $name) { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + + return true; + } + + /** + * Add an embedded stringified attachment. + * This can include images, sounds, and just about any other document type. + * If your filename doesn't contain an extension, be sure to set the $type to an appropriate MIME type. + * + * @param string $string The attachment binary data + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name A filename for the attachment. If this contains an extension, + * PHPMailer will attempt to set a MIME type for the attachment. + * For example 'file.jpg' would get an 'image/jpeg' MIME type. + * @param string $encoding File encoding (see $Encoding), defaults to 'base64' + * @param string $type MIME type - will be used in preference to any automatically derived type + * @param string $disposition Disposition to use + * + * @return bool True on successfully adding an attachment + */ + public function addStringEmbeddedImage( + $string, + $cid, + $name = '', + $encoding = 'base64', + $type = '', + $disposition = 'inline' + ) { + // If a MIME type is not specified, try to work it out from the name + if ('' == $type and !empty($name)) { + $type = static::filenameToType($name); + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $name, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + + return true; + } + + /** + * Check if an embedded attachment is present with this cid. + * + * @param string $cid + * + * @return bool + */ + protected function cidExists($cid) + { + foreach ($this->attachment as $attachment) { + if ('inline' == $attachment[6] and $cid == $attachment[7]) { + return true; + } + } + + return false; + } + + /** + * Check if an inline attachment is present. + * + * @return bool + */ + public function inlineImageExists() + { + foreach ($this->attachment as $attachment) { + if ('inline' == $attachment[6]) { + return true; + } + } + + return false; + } + + /** + * Check if an attachment (non-inline) is present. + * + * @return bool + */ + public function attachmentExists() + { + foreach ($this->attachment as $attachment) { + if ('attachment' == $attachment[6]) { + return true; + } + } + + return false; + } + + /** + * Check if this message has an alternative body set. + * + * @return bool + */ + public function alternativeExists() + { + return !empty($this->AltBody); + } + + /** + * Clear queued addresses of given kind. + * + * @param string $kind 'to', 'cc', or 'bcc' + */ + public function clearQueuedAddresses($kind) + { + $this->RecipientsQueue = array_filter( + $this->RecipientsQueue, + function ($params) use ($kind) { + return $params[0] != $kind; + } + ); + } + + /** + * Clear all To recipients. + */ + public function clearAddresses() + { + foreach ($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = []; + $this->clearQueuedAddresses('to'); + } + + /** + * Clear all CC recipients. + */ + public function clearCCs() + { + foreach ($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = []; + $this->clearQueuedAddresses('cc'); + } + + /** + * Clear all BCC recipients. + */ + public function clearBCCs() + { + foreach ($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = []; + $this->clearQueuedAddresses('bcc'); + } + + /** + * Clear all ReplyTo recipients. + */ + public function clearReplyTos() + { + $this->ReplyTo = []; + $this->ReplyToQueue = []; + } + + /** + * Clear all recipient types. + */ + public function clearAllRecipients() + { + $this->to = []; + $this->cc = []; + $this->bcc = []; + $this->all_recipients = []; + $this->RecipientsQueue = []; + } + + /** + * Clear all filesystem, string, and binary attachments. + */ + public function clearAttachments() + { + $this->attachment = []; + } + + /** + * Clear all custom headers. + */ + public function clearCustomHeaders() + { + $this->CustomHeader = []; + } + + /** + * Add an error message to the error container. + * + * @param string $msg + */ + protected function setError($msg) + { + ++$this->error_count; + if ('smtp' == $this->Mailer and null !== $this->smtp) { + $lasterror = $this->smtp->getError(); + if (!empty($lasterror['error'])) { + $msg .= $this->lang('smtp_error') . $lasterror['error']; + if (!empty($lasterror['detail'])) { + $msg .= ' Detail: ' . $lasterror['detail']; + } + if (!empty($lasterror['smtp_code'])) { + $msg .= ' SMTP code: ' . $lasterror['smtp_code']; + } + if (!empty($lasterror['smtp_code_ex'])) { + $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex']; + } + } + } + $this->ErrorInfo = $msg; + } + + /** + * Return an RFC 822 formatted date. + * + * @return string + */ + public static function rfcDate() + { + // Set the time zone to whatever the default is to avoid 500 errors + // Will default to UTC if it's not set properly in php.ini + date_default_timezone_set(@date_default_timezone_get()); + + return date('D, j M Y H:i:s O'); + } + + /** + * Get the server hostname. + * Returns 'localhost.localdomain' if unknown. + * + * @return string + */ + protected function serverHostname() + { + $result = ''; + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER)) { + $result = $_SERVER['SERVER_NAME']; + } elseif (function_exists('gethostname') and gethostname() !== false) { + $result = gethostname(); + } elseif (php_uname('n') !== false) { + $result = php_uname('n'); + } + if (!static::isValidHost($result)) { + return 'localhost.localdomain'; + } + + return $result; + } + + /** + * Validate whether a string contains a valid value to use as a hostname or IP address. + * IPv6 addresses must include [], e.g. `[::1]`, not just `::1`. + * + * @param string $host The host name or IP address to check + * + * @return bool + */ + public static function isValidHost($host) + { + //Simple syntax limits + if (empty($host) + or !is_string($host) + or strlen($host) > 256 + ) { + return false; + } + //Looks like a bracketed IPv6 address + if (trim($host, '[]') != $host) { + return (bool) filter_var(trim($host, '[]'), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + } + //If removing all the dots results in a numeric string, it must be an IPv4 address. + //Need to check this first because otherwise things like `999.0.0.0` are considered valid host names + if (is_numeric(str_replace('.', '', $host))) { + //Is it a valid IPv4 address? + return (bool) filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + } + if (filter_var('http://' . $host, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)) { + //Is it a syntactically valid hostname? + return true; + } + + return false; + } + + /** + * Get an error message in the current language. + * + * @param string $key + * + * @return string + */ + protected function lang($key) + { + if (count($this->language) < 1) { + $this->setLanguage('en'); // set the default language + } + + if (array_key_exists($key, $this->language)) { + if ('smtp_connect_failed' == $key) { + //Include a link to troubleshooting docs on SMTP connection failure + //this is by far the biggest cause of support questions + //but it's usually not PHPMailer's fault. + return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting'; + } + + return $this->language[$key]; + } + + //Return the key as a fallback + return $key; + } + + /** + * Check if an error occurred. + * + * @return bool True if an error did occur + */ + public function isError() + { + return $this->error_count > 0; + } + + /** + * Add a custom header. + * $name value can be overloaded to contain + * both header name and value (name:value). + * + * @param string $name Custom header name + * @param string|null $value Header value + */ + public function addCustomHeader($name, $value = null) + { + if (null === $value) { + // Value passed in as name:value + $this->CustomHeader[] = explode(':', $name, 2); + } else { + $this->CustomHeader[] = [$name, $value]; + } + } + + /** + * Returns all custom headers. + * + * @return array + */ + public function getCustomHeaders() + { + return $this->CustomHeader; + } + + /** + * Create a message body from an HTML string. + * Automatically inlines images and creates a plain-text version by converting the HTML, + * overwriting any existing values in Body and AltBody. + * Do not source $message content from user input! + * $basedir is prepended when handling relative URLs, e.g. <img src="/images/a.png"> and must not be empty + * will look for an image file in $basedir/images/a.png and convert it to inline. + * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email) + * Converts data-uri images into embedded attachments. + * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly. + * + * @param string $message HTML message string + * @param string $basedir Absolute path to a base directory to prepend to relative paths to images + * @param bool|callable $advanced Whether to use the internal HTML to text converter + * or your own custom converter @see PHPMailer::html2text() + * + * @return string $message The transformed message Body + */ + public function msgHTML($message, $basedir = '', $advanced = false) + { + preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); + if (array_key_exists(2, $images)) { + if (strlen($basedir) > 1 && '/' != substr($basedir, -1)) { + // Ensure $basedir has a trailing / + $basedir .= '/'; + } + foreach ($images[2] as $imgindex => $url) { + // Convert data URIs into embedded images + //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) { + if (count($match) == 4 and 'base64' == $match[2]) { + $data = base64_decode($match[3]); + } elseif ('' == $match[2]) { + $data = rawurldecode($match[3]); + } else { + //Not recognised so leave it alone + continue; + } + //Hash the decoded data, not the URL so that the same data-URI image used in multiple places + //will only be embedded once, even if it used a different encoding + $cid = hash('sha256', $data) . '@phpmailer.0'; // RFC2392 S 2 + + if (!$this->cidExists($cid)) { + $this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1]); + } + $message = str_replace( + $images[0][$imgindex], + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + continue; + } + if (// Only process relative URLs if a basedir is provided (i.e. no absolute local paths) + !empty($basedir) + // Ignore URLs containing parent dir traversal (..) + and (strpos($url, '..') === false) + // Do not change urls that are already inline images + and 0 !== strpos($url, 'cid:') + // Do not change absolute URLs, including anonymous protocol + and !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url) + ) { + $filename = basename($url); + $directory = dirname($url); + if ('.' == $directory) { + $directory = ''; + } + $cid = hash('sha256', $url) . '@phpmailer.0'; // RFC2392 S 2 + if (strlen($basedir) > 1 and '/' != substr($basedir, -1)) { + $basedir .= '/'; + } + if (strlen($directory) > 1 and '/' != substr($directory, -1)) { + $directory .= '/'; + } + if ($this->addEmbeddedImage( + $basedir . $directory . $filename, + $cid, + $filename, + 'base64', + static::_mime_types((string) static::mb_pathinfo($filename, PATHINFO_EXTENSION)) + ) + ) { + $message = preg_replace( + '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } + } + } + $this->isHTML(true); + // Convert all message body line breaks to LE, makes quoted-printable encoding work much better + $this->Body = static::normalizeBreaks($message); + $this->AltBody = static::normalizeBreaks($this->html2text($message, $advanced)); + if (!$this->alternativeExists()) { + $this->AltBody = 'This is an HTML-only message. To view it, activate HTML in your email application.' + . static::$LE; + } + + return $this->Body; + } + + /** + * Convert an HTML string into plain text. + * This is used by msgHTML(). + * Note - older versions of this function used a bundled advanced converter + * which was removed for license reasons in #232. + * Example usage: + * + * ```php + * // Use default conversion + * $plain = $mail->html2text($html); + * // Use your own custom converter + * $plain = $mail->html2text($html, function($html) { + * $converter = new MyHtml2text($html); + * return $converter->get_text(); + * }); + * ``` + * + * @param string $html The HTML text to convert + * @param bool|callable $advanced Any boolean value to use the internal converter, + * or provide your own callable for custom conversion + * + * @return string + */ + public function html2text($html, $advanced = false) + { + if (is_callable($advanced)) { + return call_user_func($advanced, $html); + } + + return html_entity_decode( + trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), + ENT_QUOTES, + $this->CharSet + ); + } + + /** + * Get the MIME type for a file extension. + * + * @param string $ext File extension + * + * @return string MIME type of file + */ + public static function _mime_types($ext = '') + { + $mimes = [ + 'xl' => 'application/excel', + 'js' => 'application/javascript', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'bin' => 'application/macbinary', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'class' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'm4a' => 'audio/mp4', + 'mpga' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'wav' => 'audio/x-wav', + 'mka' => 'audio/x-matroska', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'webp' => 'image/webp', + 'heif' => 'image/heif', + 'heifs' => 'image/heif-sequence', + 'heic' => 'image/heic', + 'heics' => 'image/heic-sequence', + 'eml' => 'message/rfc822', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'log' => 'text/plain', + 'text' => 'text/plain', + 'txt' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'vcf' => 'text/vcard', + 'vcard' => 'text/vcard', + 'ics' => 'text/calendar', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'wmv' => 'video/x-ms-wmv', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mp4' => 'video/mp4', + 'm4v' => 'video/mp4', + 'mov' => 'video/quicktime', + 'qt' => 'video/quicktime', + 'rv' => 'video/vnd.rn-realvideo', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'webm' => 'video/webm', + 'mkv' => 'video/x-matroska', + ]; + $ext = strtolower($ext); + if (array_key_exists($ext, $mimes)) { + return $mimes[$ext]; + } + + return 'application/octet-stream'; + } + + /** + * Map a file name to a MIME type. + * Defaults to 'application/octet-stream', i.e.. arbitrary binary data. + * + * @param string $filename A file name or full path, does not need to exist as a file + * + * @return string + */ + public static function filenameToType($filename) + { + // In case the path is a URL, strip any query string before getting extension + $qpos = strpos($filename, '?'); + if (false !== $qpos) { + $filename = substr($filename, 0, $qpos); + } + $ext = static::mb_pathinfo($filename, PATHINFO_EXTENSION); + + return static::_mime_types($ext); + } + + /** + * Multi-byte-safe pathinfo replacement. + * Drop-in replacement for pathinfo(), but multibyte- and cross-platform-safe. + * + * @see http://www.php.net/manual/en/function.pathinfo.php#107461 + * + * @param string $path A filename or path, does not need to exist as a file + * @param int|string $options Either a PATHINFO_* constant, + * or a string name to return only the specified piece + * + * @return string|array + */ + public static function mb_pathinfo($path, $options = null) + { + $ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '']; + $pathinfo = []; + if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$#im', $path, $pathinfo)) { + if (array_key_exists(1, $pathinfo)) { + $ret['dirname'] = $pathinfo[1]; + } + if (array_key_exists(2, $pathinfo)) { + $ret['basename'] = $pathinfo[2]; + } + if (array_key_exists(5, $pathinfo)) { + $ret['extension'] = $pathinfo[5]; + } + if (array_key_exists(3, $pathinfo)) { + $ret['filename'] = $pathinfo[3]; + } + } + switch ($options) { + case PATHINFO_DIRNAME: + case 'dirname': + return $ret['dirname']; + case PATHINFO_BASENAME: + case 'basename': + return $ret['basename']; + case PATHINFO_EXTENSION: + case 'extension': + return $ret['extension']; + case PATHINFO_FILENAME: + case 'filename': + return $ret['filename']; + default: + return $ret; + } + } + + /** + * Set or reset instance properties. + * You should avoid this function - it's more verbose, less efficient, more error-prone and + * harder to debug than setting properties directly. + * Usage Example: + * `$mail->set('SMTPSecure', 'tls');` + * is the same as: + * `$mail->SMTPSecure = 'tls';`. + * + * @param string $name The property name to set + * @param mixed $value The value to set the property to + * + * @return bool + */ + public function set($name, $value = '') + { + if (property_exists($this, $name)) { + $this->$name = $value; + + return true; + } + $this->setError($this->lang('variable_set') . $name); + + return false; + } + + /** + * Strip newlines to prevent header injection. + * + * @param string $str + * + * @return string + */ + public function secureHeader($str) + { + return trim(str_replace(["\r", "\n"], '', $str)); + } + + /** + * Normalize line breaks in a string. + * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format. + * Defaults to CRLF (for message bodies) and preserves consecutive breaks. + * + * @param string $text + * @param string $breaktype What kind of line break to use; defaults to static::$LE + * + * @return string + */ + public static function normalizeBreaks($text, $breaktype = null) + { + if (null === $breaktype) { + $breaktype = static::$LE; + } + // Normalise to \n + $text = str_replace(["\r\n", "\r"], "\n", $text); + // Now convert LE as needed + if ("\n" !== $breaktype) { + $text = str_replace("\n", $breaktype, $text); + } + + return $text; + } + + /** + * Return the current line break format string. + * + * @return string + */ + public static function getLE() + { + return static::$LE; + } + + /** + * Set the line break format string, e.g. "\r\n". + * + * @param string $le + */ + protected static function setLE($le) + { + static::$LE = $le; + } + + /** + * Set the public and private key files and password for S/MIME signing. + * + * @param string $cert_filename + * @param string $key_filename + * @param string $key_pass Password for private key + * @param string $extracerts_filename Optional path to chain certificate + */ + public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '') + { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + $this->sign_extracerts_file = $extracerts_filename; + } + + /** + * Quoted-Printable-encode a DKIM header. + * + * @param string $txt + * + * @return string + */ + public function DKIM_QP($txt) + { + $line = ''; + $len = strlen($txt); + for ($i = 0; $i < $len; ++$i) { + $ord = ord($txt[$i]); + if (((0x21 <= $ord) and ($ord <= 0x3A)) or $ord == 0x3C or ((0x3E <= $ord) and ($ord <= 0x7E))) { + $line .= $txt[$i]; + } else { + $line .= '=' . sprintf('%02X', $ord); + } + } + + return $line; + } + + /** + * Generate a DKIM signature. + * + * @param string $signHeader + * + * @throws Exception + * + * @return string The DKIM signature value + */ + public function DKIM_Sign($signHeader) + { + if (!defined('PKCS7_TEXT')) { + if ($this->exceptions) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + + return ''; + } + $privKeyStr = !empty($this->DKIM_private_string) ? + $this->DKIM_private_string : + file_get_contents($this->DKIM_private); + if ('' != $this->DKIM_passphrase) { + $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); + } else { + $privKey = openssl_pkey_get_private($privKeyStr); + } + if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { + openssl_pkey_free($privKey); + + return base64_encode($signature); + } + openssl_pkey_free($privKey); + + return ''; + } + + /** + * Generate a DKIM canonicalization header. + * Uses the 'relaxed' algorithm from RFC6376 section 3.4.2. + * Canonicalized headers should *always* use CRLF, regardless of mailer setting. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.2 + * + * @param string $signHeader Header + * + * @return string + */ + public function DKIM_HeaderC($signHeader) + { + //Unfold all header continuation lines + //Also collapses folded whitespace. + //Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]` + //@see https://tools.ietf.org/html/rfc5322#section-2.2 + //That means this may break if you do something daft like put vertical tabs in your headers. + $signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader); + $lines = explode("\r\n", $signHeader); + foreach ($lines as $key => $line) { + //If the header is missing a :, skip it as it's invalid + //This is likely to happen because the explode() above will also split + //on the trailing LE, leaving an empty line + if (strpos($line, ':') === false) { + continue; + } + list($heading, $value) = explode(':', $line, 2); + //Lower-case header name + $heading = strtolower($heading); + //Collapse white space within the value + $value = preg_replace('/[ \t]{2,}/', ' ', $value); + //RFC6376 is slightly unclear here - it says to delete space at the *end* of each value + //But then says to delete space before and after the colon. + //Net result is the same as trimming both ends of the value. + //by elimination, the same applies to the field name + $lines[$key] = trim($heading, " \t") . ':' . trim($value, " \t"); + } + + return implode("\r\n", $lines); + } + + /** + * Generate a DKIM canonicalization body. + * Uses the 'simple' algorithm from RFC6376 section 3.4.3. + * Canonicalized bodies should *always* use CRLF, regardless of mailer setting. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.3 + * + * @param string $body Message Body + * + * @return string + */ + public function DKIM_BodyC($body) + { + if (empty($body)) { + return "\r\n"; + } + // Normalize line endings to CRLF + $body = static::normalizeBreaks($body, "\r\n"); + + //Reduce multiple trailing line breaks to a single one + return rtrim($body, "\r\n") . "\r\n"; + } + + /** + * Create the DKIM header and body in a new message header. + * + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + * + * @return string + */ + public function DKIM_Add($headers_line, $subject, $body) + { + $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) + $subject_header = "Subject: $subject"; + $headers = explode(static::$LE, $headers_line); + $from_header = ''; + $to_header = ''; + $date_header = ''; + $current = ''; + foreach ($headers as $header) { + if (strpos($header, 'From:') === 0) { + $from_header = $header; + $current = 'from_header'; + } elseif (strpos($header, 'To:') === 0) { + $to_header = $header; + $current = 'to_header'; + } elseif (strpos($header, 'Date:') === 0) { + $date_header = $header; + $current = 'date_header'; + } else { + if (!empty($$current) and strpos($header, ' =?') === 0) { + $$current .= $header; + } else { + $current = ''; + } + } + } + $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); + $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); + $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); + $subject = str_replace( + '|', + '=7C', + $this->DKIM_QP($subject_header) + ); // Copied header fields (dkim-quoted-printable) + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body); // Length of body + $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body + if ('' == $this->DKIM_identity) { + $ident = ''; + } else { + $ident = ' i=' . $this->DKIM_identity . ';'; + } + $dkimhdrs = 'DKIM-Signature: v=1; a=' . + $DKIMsignatureType . '; q=' . + $DKIMquery . '; l=' . + $DKIMlen . '; s=' . + $this->DKIM_selector . + ";\r\n" . + "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . + "\th=From:To:Date:Subject;\r\n" . + "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . + "\tz=$from\r\n" . + "\t|$to\r\n" . + "\t|$date\r\n" . + "\t|$subject;\r\n" . + "\tbh=" . $DKIMb64 . ";\r\n" . + "\tb="; + $toSign = $this->DKIM_HeaderC( + $from_header . "\r\n" . + $to_header . "\r\n" . + $date_header . "\r\n" . + $subject_header . "\r\n" . + $dkimhdrs + ); + $signed = $this->DKIM_Sign($toSign); + + return static::normalizeBreaks($dkimhdrs . $signed) . static::$LE; + } + + /** + * Detect if a string contains a line longer than the maximum line length + * allowed by RFC 2822 section 2.1.1. + * + * @param string $str + * + * @return bool + */ + public static function hasLineLongerThanMax($str) + { + return (bool) preg_match('/^(.{' . (self::MAX_LINE_LENGTH + strlen(static::$LE)) . ',})/m', $str); + } + + /** + * Allows for public read access to 'to' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getToAddresses() + { + return $this->to; + } + + /** + * Allows for public read access to 'cc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getCcAddresses() + { + return $this->cc; + } + + /** + * Allows for public read access to 'bcc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getBccAddresses() + { + return $this->bcc; + } + + /** + * Allows for public read access to 'ReplyTo' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getReplyToAddresses() + { + return $this->ReplyTo; + } + + /** + * Allows for public read access to 'all_recipients' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getAllRecipientAddresses() + { + return $this->all_recipients; + } + + /** + * Perform a callback. + * + * @param bool $isSent + * @param array $to + * @param array $cc + * @param array $bcc + * @param string $subject + * @param string $body + * @param string $from + * @param array $extra + */ + protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from, $extra) + { + if (!empty($this->action_function) and is_callable($this->action_function)) { + call_user_func($this->action_function, $isSent, $to, $cc, $bcc, $subject, $body, $from, $extra); + } + } + + /** + * Get the OAuth instance. + * + * @return OAuth + */ + public function getOAuth() + { + return $this->oauth; + } + + /** + * Set an OAuth instance. + * + * @param OAuth $oauth + */ + public function setOAuth(OAuth $oauth) + { + $this->oauth = $oauth; + } +} diff --git a/vas/rest/class/PHPMailer/src/POP3.php b/vas/rest/class/PHPMailer/src/POP3.php new file mode 100755 index 0000000000000000000000000000000000000000..47aa39490976000b3bcf868637a8620200cb3062 --- /dev/null +++ b/vas/rest/class/PHPMailer/src/POP3.php @@ -0,0 +1,419 @@ +<?php +/** + * PHPMailer POP-Before-SMTP Authentication Class. + * PHP Version 5.5. + * + * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer POP-Before-SMTP Authentication Class. + * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. + * 1) This class does not support APOP authentication. + * 2) Opening and closing lots of POP3 connections can be quite slow. If you need + * to send a batch of emails then just perform the authentication once at the start, + * and then loop through your mail sending script. Providing this process doesn't + * take longer than the verification period lasts on your POP3 server, you should be fine. + * 3) This is really ancient technology; you should only need to use it to talk to very old systems. + * 4) This POP3 class is deliberately lightweight and incomplete, and implements just + * enough to do authentication. + * If you want a more complete class there are other POP3 classes for PHP available. + * + * @author Richard Davey (original author) <rich@corephp.co.uk> + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + */ +class POP3 +{ + /** + * The POP3 PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.0.3'; + + /** + * Default POP3 port number. + * + * @var int + */ + const DEFAULT_PORT = 110; + + /** + * Default timeout in seconds. + * + * @var int + */ + const DEFAULT_TIMEOUT = 30; + + /** + * Debug display level. + * Options: 0 = no, 1+ = yes. + * + * @var int + */ + public $do_debug = 0; + + /** + * POP3 mail server hostname. + * + * @var string + */ + public $host; + + /** + * POP3 port number. + * + * @var int + */ + public $port; + + /** + * POP3 Timeout Value in seconds. + * + * @var int + */ + public $tval; + + /** + * POP3 username. + * + * @var string + */ + public $username; + + /** + * POP3 password. + * + * @var string + */ + public $password; + + /** + * Resource handle for the POP3 connection socket. + * + * @var resource + */ + protected $pop_conn; + + /** + * Are we connected? + * + * @var bool + */ + protected $connected = false; + + /** + * Error container. + * + * @var array + */ + protected $errors = []; + + /** + * Line break constant. + */ + const LE = "\r\n"; + + /** + * Simple static wrapper for all-in-one POP before SMTP. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public static function popBeforeSmtp( + $host, + $port = false, + $timeout = false, + $username = '', + $password = '', + $debug_level = 0 + ) { + $pop = new self(); + + return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); + } + + /** + * Authenticate with a POP3 server. + * A connect, login, disconnect sequence + * appropriate for POP-before SMTP authorisation. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) + { + $this->host = $host; + // If no port value provided, use default + if (false === $port) { + $this->port = static::DEFAULT_PORT; + } else { + $this->port = (int) $port; + } + // If no timeout value provided, use default + if (false === $timeout) { + $this->tval = static::DEFAULT_TIMEOUT; + } else { + $this->tval = (int) $timeout; + } + $this->do_debug = $debug_level; + $this->username = $username; + $this->password = $password; + // Reset the error log + $this->errors = []; + // connect + $result = $this->connect($this->host, $this->port, $this->tval); + if ($result) { + $login_result = $this->login($this->username, $this->password); + if ($login_result) { + $this->disconnect(); + + return true; + } + } + // We need to disconnect regardless of whether the login succeeded + $this->disconnect(); + + return false; + } + + /** + * Connect to a POP3 server. + * + * @param string $host + * @param int|bool $port + * @param int $tval + * + * @return bool + */ + public function connect($host, $port = false, $tval = 30) + { + // Are we already connected? + if ($this->connected) { + return true; + } + + //On Windows this will raise a PHP Warning error if the hostname doesn't exist. + //Rather than suppress it with @fsockopen, capture it cleanly instead + set_error_handler([$this, 'catchWarning']); + + if (false === $port) { + $port = static::DEFAULT_PORT; + } + + // connect to the POP3 server + $this->pop_conn = fsockopen( + $host, // POP3 Host + $port, // Port # + $errno, // Error Number + $errstr, // Error Message + $tval + ); // Timeout (seconds) + // Restore the error handler + restore_error_handler(); + + // Did we connect? + if (false === $this->pop_conn) { + // It would appear not... + $this->setError( + "Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr" + ); + + return false; + } + + // Increase the stream time-out + stream_set_timeout($this->pop_conn, $tval, 0); + + // Get the POP3 server response + $pop3_response = $this->getResponse(); + // Check for the +OK + if ($this->checkResponse($pop3_response)) { + // The connection is established and the POP3 server is talking + $this->connected = true; + + return true; + } + + return false; + } + + /** + * Log in to the POP3 server. + * Does not support APOP (RFC 2828, 4949). + * + * @param string $username + * @param string $password + * + * @return bool + */ + public function login($username = '', $password = '') + { + if (!$this->connected) { + $this->setError('Not connected to POP3 server'); + } + if (empty($username)) { + $username = $this->username; + } + if (empty($password)) { + $password = $this->password; + } + + // Send the Username + $this->sendString("USER $username" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + // Send the Password + $this->sendString("PASS $password" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + return true; + } + } + + return false; + } + + /** + * Disconnect from the POP3 server. + */ + public function disconnect() + { + $this->sendString('QUIT'); + //The QUIT command may cause the daemon to exit, which will kill our connection + //So ignore errors here + try { + @fclose($this->pop_conn); + } catch (Exception $e) { + //Do nothing + } + } + + /** + * Get a response from the POP3 server. + * + * @param int $size The maximum number of bytes to retrieve + * + * @return string + */ + protected function getResponse($size = 128) + { + $response = fgets($this->pop_conn, $size); + if ($this->do_debug >= 1) { + echo 'Server -> Client: ', $response; + } + + return $response; + } + + /** + * Send raw data to the POP3 server. + * + * @param string $string + * + * @return int + */ + protected function sendString($string) + { + if ($this->pop_conn) { + if ($this->do_debug >= 2) { //Show client messages when debug >= 2 + echo 'Client -> Server: ', $string; + } + + return fwrite($this->pop_conn, $string, strlen($string)); + } + + return 0; + } + + /** + * Checks the POP3 server response. + * Looks for for +OK or -ERR. + * + * @param string $string + * + * @return bool + */ + protected function checkResponse($string) + { + if (substr($string, 0, 3) !== '+OK') { + $this->setError("Server reported an error: $string"); + + return false; + } + + return true; + } + + /** + * Add an error to the internal error store. + * Also display debug output if it's enabled. + * + * @param string $error + */ + protected function setError($error) + { + $this->errors[] = $error; + if ($this->do_debug >= 1) { + echo '<pre>'; + foreach ($this->errors as $e) { + print_r($e); + } + echo '</pre>'; + } + } + + /** + * Get an array of error messages, if any. + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * POP3 connection error handler. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + */ + protected function catchWarning($errno, $errstr, $errfile, $errline) + { + $this->setError( + 'Connecting to the POP3 server raised a PHP warning:' . + "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline" + ); + } +} diff --git a/vas/rest/class/PHPMailer/src/SMTP.php b/vas/rest/class/PHPMailer/src/SMTP.php new file mode 100755 index 0000000000000000000000000000000000000000..27b752ec30031c8fa7ca2587e39bc4e99dbccd02 --- /dev/null +++ b/vas/rest/class/PHPMailer/src/SMTP.php @@ -0,0 +1,1325 @@ +<?php +/** + * PHPMailer RFC821 SMTP email transport class. + * PHP Version 5.5. + * + * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project + * + * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk> + * @author Jim Jagielski (jimjag) <jimjag@gmail.com> + * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net> + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer RFC821 SMTP email transport class. + * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. + * + * @author Chris Ryan + * @author Marcus Bointon <phpmailer@synchromedia.co.uk> + */ +class SMTP +{ + /** + * The PHPMailer SMTP version number. + * + * @var string + */ + const VERSION = '6.0.3'; + + /** + * SMTP line break constant. + * + * @var string + */ + const LE = "\r\n"; + + /** + * The SMTP port to use if one is not specified. + * + * @var int + */ + const DEFAULT_PORT = 25; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * Debug level for no output. + */ + const DEBUG_OFF = 0; + + /** + * Debug level to show client -> server messages. + */ + const DEBUG_CLIENT = 1; + + /** + * Debug level to show client -> server and server -> client messages. + */ + const DEBUG_SERVER = 2; + + /** + * Debug level to show connection status, client -> server and server -> client messages. + */ + const DEBUG_CONNECTION = 3; + + /** + * Debug level to show all messages. + */ + const DEBUG_LOWLEVEL = 4; + + /** + * Debug output level. + * Options: + * * self::DEBUG_OFF (`0`) No debug output, default + * * self::DEBUG_CLIENT (`1`) Client commands + * * self::DEBUG_SERVER (`2`) Client commands and server responses + * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status + * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages. + * + * @var int + */ + public $do_debug = self::DEBUG_OFF; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to use VERP. + * + * @see http://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Info on VERP + * + * @var bool + */ + public $do_verp = false; + + /** + * The timeout value for connection, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. + * + * @see http://tools.ietf.org/html/rfc2821#section-4.5.3.2 + * + * @var int + */ + public $Timeout = 300; + + /** + * How long to wait for commands to complete, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timelimit = 300; + + /** + * Patterns to extract an SMTP transaction id from reply to a DATA command. + * The first capture group in each regex will be used as the ID. + * MS ESMTP returns the message ID, which may not be correct for internal tracking. + * + * @var string[] + */ + protected $smtp_transaction_id_patterns = [ + 'exim' => '/[0-9]{3} OK id=(.*)/', + 'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/', + 'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/', + 'Microsoft_ESMTP' => '/[0-9]{3} 2.[0-9].0 (.*)@(?:.*) Queued mail for delivery/', + 'Amazon_SES' => '/[0-9]{3} Ok (.*)/', + 'SendGrid' => '/[0-9]{3} Ok: queued as (.*)/', + ]; + + /** + * The last transaction ID issued in response to a DATA command, + * if one was detected. + * + * @var string|bool|null + */ + protected $last_smtp_transaction_id; + + /** + * The socket for the server connection. + * + * @var ?resource + */ + protected $smtp_conn; + + /** + * Error information, if any, for the last SMTP command. + * + * @var array + */ + protected $error = [ + 'error' => '', + 'detail' => '', + 'smtp_code' => '', + 'smtp_code_ex' => '', + ]; + + /** + * The reply the server sent to us for HELO. + * If null, no HELO string has yet been received. + * + * @var string|null + */ + protected $helo_rply = null; + + /** + * The set of SMTP extensions sent in reply to EHLO command. + * Indexes of the array are extension names. + * Value at index 'HELO' or 'EHLO' (according to command that was sent) + * represents the server name. In case of HELO it is the only element of the array. + * Other values can be boolean TRUE or an array containing extension options. + * If null, no HELO/EHLO string has yet been received. + * + * @var array|null + */ + protected $server_caps = null; + + /** + * The most recent reply received from the server. + * + * @var string + */ + protected $last_reply = ''; + + /** + * Output debugging info via a user-selected method. + * + * @param string $str Debug string to output + * @param int $level The debug level of this message; see DEBUG_* constants + * + * @see SMTP::$Debugoutput + * @see SMTP::$do_debug + */ + protected function edebug($str, $level = 0) + { + if ($level > $this->do_debug) { + return; + } + //Is this a PSR-3 logger? + if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, ['error_log', 'html', 'echo']) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $level); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo gmdate('Y-m-d H:i:s'), ' ', htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "<br>\n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Connect to an SMTP server. + * + * @param string $host SMTP server IP or host name + * @param int $port The port number to connect to + * @param int $timeout How long to wait for the connection to open + * @param array $options An array of options for stream_context_create() + * + * @return bool + */ + public function connect($host, $port = null, $timeout = 30, $options = []) + { + static $streamok; + //This is enabled by default since 5.0.0 but some providers disable it + //Check this once and cache the result + if (null === $streamok) { + $streamok = function_exists('stream_socket_client'); + } + // Clear errors to avoid confusion + $this->setError(''); + // Make sure we are __not__ connected + if ($this->connected()) { + // Already connected, generate error + $this->setError('Already connected to a server'); + + return false; + } + if (empty($port)) { + $port = self::DEFAULT_PORT; + } + // Connect to the SMTP server + $this->edebug( + "Connection: opening to $host:$port, timeout=$timeout, options=" . + (count($options) > 0 ? var_export($options, true) : 'array()'), + self::DEBUG_CONNECTION + ); + $errno = 0; + $errstr = ''; + if ($streamok) { + $socket_context = stream_context_create($options); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = stream_socket_client( + $host . ':' . $port, + $errno, + $errstr, + $timeout, + STREAM_CLIENT_CONNECT, + $socket_context + ); + restore_error_handler(); + } else { + //Fall back to fsockopen which should work in more places, but is missing some features + $this->edebug( + 'Connection: stream_socket_client not available, falling back to fsockopen', + self::DEBUG_CONNECTION + ); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = fsockopen( + $host, + $port, + $errno, + $errstr, + $timeout + ); + restore_error_handler(); + } + // Verify we connected properly + if (!is_resource($this->smtp_conn)) { + $this->setError( + 'Failed to connect to server', + '', + (string) $errno, + (string) $errstr + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] + . ": $errstr ($errno)", + self::DEBUG_CLIENT + ); + + return false; + } + $this->edebug('Connection: opened', self::DEBUG_CONNECTION); + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if (substr(PHP_OS, 0, 3) != 'WIN') { + $max = ini_get('max_execution_time'); + // Don't bother if unlimited + if (0 != $max and $timeout > $max) { + @set_time_limit($timeout); + } + stream_set_timeout($this->smtp_conn, $timeout, 0); + } + // Get any announcement + $announce = $this->get_lines(); + $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); + + return true; + } + + /** + * Initiate a TLS (encrypted) session. + * + * @return bool + */ + public function startTLS() + { + if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { + return false; + } + + //Allow the best TLS version(s) we can + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + + //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT + //so add them back in manually if we can + if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + } + + // Begin encrypted connection + set_error_handler([$this, 'errorHandler']); + $crypto_ok = stream_socket_enable_crypto( + $this->smtp_conn, + true, + $crypto_method + ); + restore_error_handler(); + + return (bool) $crypto_ok; + } + + /** + * Perform SMTP authentication. + * Must be run after hello(). + * + * @see hello() + * + * @param string $username The user name + * @param string $password The password + * @param string $authtype The auth type (CRAM-MD5, PLAIN, LOGIN, XOAUTH2) + * @param OAuth $OAuth An optional OAuth instance for XOAUTH2 authentication + * + * @return bool True if successfully authenticated + */ + public function authenticate( + $username, + $password, + $authtype = null, + $OAuth = null + ) { + if (!$this->server_caps) { + $this->setError('Authentication is not allowed before HELO/EHLO'); + + return false; + } + + if (array_key_exists('EHLO', $this->server_caps)) { + // SMTP extensions are available; try to find a proper authentication method + if (!array_key_exists('AUTH', $this->server_caps)) { + $this->setError('Authentication is not allowed at this stage'); + // 'at this stage' means that auth may be allowed after the stage changes + // e.g. after STARTTLS + + return false; + } + + $this->edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); + $this->edebug( + 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), + self::DEBUG_LOWLEVEL + ); + + //If we have requested a specific auth type, check the server supports it before trying others + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $this->edebug('Requested auth method not available: ' . $authtype, self::DEBUG_LOWLEVEL); + $authtype = null; + } + + if (empty($authtype)) { + //If no auth mechanism is specified, attempt to use these, in this order + //Try CRAM-MD5 first as it's more secure than the others + foreach (['CRAM-MD5', 'LOGIN', 'PLAIN', 'XOAUTH2'] as $method) { + if (in_array($method, $this->server_caps['AUTH'])) { + $authtype = $method; + break; + } + } + if (empty($authtype)) { + $this->setError('No supported authentication methods found'); + + return false; + } + self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL); + } + + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); + + return false; + } + } elseif (empty($authtype)) { + $authtype = 'LOGIN'; + } + switch ($authtype) { + case 'PLAIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { + return false; + } + // Send encoded username and password + if (!$this->sendCommand( + 'User & Password', + base64_encode("\0" . $username . "\0" . $password), + 235 + ) + ) { + return false; + } + break; + case 'LOGIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { + return false; + } + if (!$this->sendCommand('Username', base64_encode($username), 334)) { + return false; + } + if (!$this->sendCommand('Password', base64_encode($password), 235)) { + return false; + } + break; + case 'CRAM-MD5': + // Start authentication + if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { + return false; + } + // Get the challenge + $challenge = base64_decode(substr($this->last_reply, 4)); + + // Build the response + $response = $username . ' ' . $this->hmac($challenge, $password); + + // send encoded credentials + return $this->sendCommand('Username', base64_encode($response), 235); + case 'XOAUTH2': + //The OAuth instance must be set up prior to requesting auth. + if (null === $OAuth) { + return false; + } + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; + default: + $this->setError("Authentication method \"$authtype\" is not supported"); + + return false; + } + + return true; + } + + /** + * Calculate an MD5 HMAC hash. + * Works like hash_hmac('md5', $data, $key) + * in case that function is not available. + * + * @param string $data The data to hash + * @param string $key The key to hash with + * + * @return string + */ + protected function hmac($data, $key) + { + if (function_exists('hash_hmac')) { + return hash_hmac('md5', $data, $key); + } + + // The following borrowed from + // http://php.net/manual/en/function.mhash.php#27225 + + // RFC 2104 HMAC implementation for php. + // Creates an md5 HMAC. + // Eliminates the need to install mhash to compute a HMAC + // by Lance Rushing + + $bytelen = 64; // byte length for md5 + if (strlen($key) > $bytelen) { + $key = pack('H*', md5($key)); + } + $key = str_pad($key, $bytelen, chr(0x00)); + $ipad = str_pad('', $bytelen, chr(0x36)); + $opad = str_pad('', $bytelen, chr(0x5c)); + $k_ipad = $key ^ $ipad; + $k_opad = $key ^ $opad; + + return md5($k_opad . pack('H*', md5($k_ipad . $data))); + } + + /** + * Check connection state. + * + * @return bool True if connected + */ + public function connected() + { + if (is_resource($this->smtp_conn)) { + $sock_status = stream_get_meta_data($this->smtp_conn); + if ($sock_status['eof']) { + // The socket is valid but we are not connected + $this->edebug( + 'SMTP NOTICE: EOF caught while checking if connected', + self::DEBUG_CLIENT + ); + $this->close(); + + return false; + } + + return true; // everything looks good + } + + return false; + } + + /** + * Close the socket and clean up the state of the class. + * Don't use this function without first trying to use QUIT. + * + * @see quit() + */ + public function close() + { + $this->setError(''); + $this->server_caps = null; + $this->helo_rply = null; + if (is_resource($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = null; //Makes for cleaner serialization + $this->edebug('Connection: closed', self::DEBUG_CONNECTION); + } + } + + /** + * Send an SMTP DATA command. + * Issues a data command and sends the msg_data to the server, + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a <CRLF> with the message headers + * and the message body being separated by an additional <CRLF>. + * Implements RFC 821: DATA <CRLF>. + * + * @param string $msg_data Message data to send + * + * @return bool + */ + public function data($msg_data) + { + //This will use the standard timelimit + if (!$this->sendCommand('DATA', 'DATA', 354)) { + return false; + } + + /* The server is ready to accept data! + * According to rfc821 we should not send more than 1000 characters on a single line (including the LE) + * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into + * smaller lines to fit within the limit. + * We will also look for lines that start with a '.' and prepend an additional '.'. + * NOTE: this does not count towards line-length limit. + */ + + // Normalize line breaks before exploding + $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data)); + + /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field + * of the first line (':' separated) does not contain a space then it _should_ be a header and we will + * process all lines before a blank line as headers. + */ + + $field = substr($lines[0], 0, strpos($lines[0], ':')); + $in_headers = false; + if (!empty($field) and strpos($field, ' ') === false) { + $in_headers = true; + } + + foreach ($lines as $line) { + $lines_out = []; + if ($in_headers and $line == '') { + $in_headers = false; + } + //Break this line up into several smaller lines if it's too long + //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), + while (isset($line[self::MAX_LINE_LENGTH])) { + //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on + //so as to avoid breaking in the middle of a word + $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); + //Deliberately matches both false and 0 + if (!$pos) { + //No nice break found, add a hard break + $pos = self::MAX_LINE_LENGTH - 1; + $lines_out[] = substr($line, 0, $pos); + $line = substr($line, $pos); + } else { + //Break at the found point + $lines_out[] = substr($line, 0, $pos); + //Move along by the amount we dealt with + $line = substr($line, $pos + 1); + } + //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 + if ($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + //Send the lines to the server + foreach ($lines_out as $line_out) { + //RFC2821 section 4.5.2 + if (!empty($line_out) and $line_out[0] == '.') { + $line_out = '.' . $line_out; + } + $this->client_send($line_out . static::LE, 'DATA'); + } + } + + //Message data has been sent, complete the command + //Increase timelimit for end of DATA command + $savetimelimit = $this->Timelimit; + $this->Timelimit = $this->Timelimit * 2; + $result = $this->sendCommand('DATA END', '.', 250); + $this->recordLastTransactionID(); + //Restore timelimit + $this->Timelimit = $savetimelimit; + + return $result; + } + + /** + * Send an SMTP HELO or EHLO command. + * Used to identify the sending server to the receiving server. + * This makes sure that client and server are in a known state. + * Implements RFC 821: HELO <SP> <domain> <CRLF> + * and RFC 2821 EHLO. + * + * @param string $host The host name or IP to connect to + * + * @return bool + */ + public function hello($host = '') + { + //Try extended hello first (RFC 2821) + return (bool) ($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); + } + + /** + * Send an SMTP HELO or EHLO command. + * Low-level implementation used by hello(). + * + * @param string $hello The HELO string + * @param string $host The hostname to say we are + * + * @return bool + * + * @see hello() + */ + protected function sendHello($hello, $host) + { + $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); + $this->helo_rply = $this->last_reply; + if ($noerror) { + $this->parseHelloFields($hello); + } else { + $this->server_caps = null; + } + + return $noerror; + } + + /** + * Parse a reply to HELO/EHLO command to discover server extensions. + * In case of HELO, the only parameter that can be discovered is a server name. + * + * @param string $type `HELO` or `EHLO` + */ + protected function parseHelloFields($type) + { + $this->server_caps = []; + $lines = explode("\n", $this->helo_rply); + + foreach ($lines as $n => $s) { + //First 4 chars contain response code followed by - or space + $s = trim(substr($s, 4)); + if (empty($s)) { + continue; + } + $fields = explode(' ', $s); + if (!empty($fields)) { + if (!$n) { + $name = $type; + $fields = $fields[0]; + } else { + $name = array_shift($fields); + switch ($name) { + case 'SIZE': + $fields = ($fields ? $fields[0] : 0); + break; + case 'AUTH': + if (!is_array($fields)) { + $fields = []; + } + break; + default: + $fields = true; + } + } + $this->server_caps[$name] = $fields; + } + } + } + + /** + * Send an SMTP MAIL command. + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. + * Implements RFC 821: MAIL <SP> FROM:<reverse-path> <CRLF>. + * + * @param string $from Source address of this message + * + * @return bool + */ + public function mail($from) + { + $useVerp = ($this->do_verp ? ' XVERP' : ''); + + return $this->sendCommand( + 'MAIL FROM', + 'MAIL FROM:<' . $from . '>' . $useVerp, + 250 + ); + } + + /** + * Send an SMTP QUIT command. + * Closes the socket if there is no error or the $close_on_error argument is true. + * Implements from RFC 821: QUIT <CRLF>. + * + * @param bool $close_on_error Should the connection close if an error occurs? + * + * @return bool + */ + public function quit($close_on_error = true) + { + $noerror = $this->sendCommand('QUIT', 'QUIT', 221); + $err = $this->error; //Save any error + if ($noerror or $close_on_error) { + $this->close(); + $this->error = $err; //Restore any error from the quit command + } + + return $noerror; + } + + /** + * Send an SMTP RCPT command. + * Sets the TO argument to $toaddr. + * Returns true if the recipient was accepted false if it was rejected. + * Implements from RFC 821: RCPT <SP> TO:<forward-path> <CRLF>. + * + * @param string $address The address the message is being sent to + * + * @return bool + */ + public function recipient($address) + { + return $this->sendCommand( + 'RCPT TO', + 'RCPT TO:<' . $address . '>', + [250, 251] + ); + } + + /** + * Send an SMTP RSET command. + * Abort any transaction that is currently in progress. + * Implements RFC 821: RSET <CRLF>. + * + * @return bool True on success + */ + public function reset() + { + return $this->sendCommand('RSET', 'RSET', 250); + } + + /** + * Send a command to an SMTP server and check its return code. + * + * @param string $command The command name - not sent to the server + * @param string $commandstring The actual command to send + * @param int|array $expect One or more expected integer success codes + * + * @return bool True on success + */ + protected function sendCommand($command, $commandstring, $expect) + { + if (!$this->connected()) { + $this->setError("Called $command without being connected"); + + return false; + } + //Reject line breaks in all commands + if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { + $this->setError("Command '$command' contained line breaks"); + + return false; + } + $this->client_send($commandstring . static::LE, $command); + + $this->last_reply = $this->get_lines(); + // Fetch SMTP code and possible error code explanation + $matches = []; + if (preg_match('/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/', $this->last_reply, $matches)) { + $code = $matches[1]; + $code_ex = (count($matches) > 2 ? $matches[2] : null); + // Cut off error code from each response line + $detail = preg_replace( + "/{$code}[ -]" . + ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . '/m', + '', + $this->last_reply + ); + } else { + // Fall back to simple parsing if regex fails + $code = substr($this->last_reply, 0, 3); + $code_ex = null; + $detail = substr($this->last_reply, 4); + } + + $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); + + if (!in_array($code, (array) $expect)) { + $this->setError( + "$command command failed", + $detail, + $code, + $code_ex + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, + self::DEBUG_CLIENT + ); + + return false; + } + + $this->setError(''); + + return true; + } + + /** + * Send an SMTP SAML command. + * Starts a mail transaction from the email address specified in $from. + * Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * Implements RFC 821: SAML <SP> FROM:<reverse-path> <CRLF>. + * + * @param string $from The address the message is from + * + * @return bool + */ + public function sendAndMail($from) + { + return $this->sendCommand('SAML', "SAML FROM:$from", 250); + } + + /** + * Send an SMTP VRFY command. + * + * @param string $name The name to verify + * + * @return bool + */ + public function verify($name) + { + return $this->sendCommand('VRFY', "VRFY $name", [250, 251]); + } + + /** + * Send an SMTP NOOP command. + * Used to keep keep-alives alive, doesn't actually do anything. + * + * @return bool + */ + public function noop() + { + return $this->sendCommand('NOOP', 'NOOP', 250); + } + + /** + * Send an SMTP TURN command. + * This is an optional command for SMTP that this class does not support. + * This method is here to make the RFC821 Definition complete for this class + * and _may_ be implemented in future. + * Implements from RFC 821: TURN <CRLF>. + * + * @return bool + */ + public function turn() + { + $this->setError('The SMTP TURN command is not implemented'); + $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); + + return false; + } + + /** + * Send raw data to the server. + * + * @param string $data The data to send + * @param string $command Optionally, the command this is part of, used only for controlling debug output + * + * @return int|bool The number of bytes sent to the server or false on error + */ + public function client_send($data, $command = '') + { + //If SMTP transcripts are left enabled, or debug output is posted online + //it can leak credentials, so hide credentials in all but lowest level + if (self::DEBUG_LOWLEVEL > $this->do_debug and + in_array($command, ['User & Password', 'Username', 'Password'], true)) { + $this->edebug('CLIENT -> SERVER: <credentials hidden>', self::DEBUG_CLIENT); + } else { + $this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT); + } + set_error_handler([$this, 'errorHandler']); + $result = fwrite($this->smtp_conn, $data); + restore_error_handler(); + + return $result; + } + + /** + * Get the latest error. + * + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * Get SMTP extensions available on the server. + * + * @return array|null + */ + public function getServerExtList() + { + return $this->server_caps; + } + + /** + * Get metadata about the SMTP server from its HELO/EHLO response. + * The method works in three ways, dependent on argument value and current state: + * 1. HELO/EHLO has not been sent - returns null and populates $this->error. + * 2. HELO has been sent - + * $name == 'HELO': returns server name + * $name == 'EHLO': returns boolean false + * $name == any other string: returns null and populates $this->error + * 3. EHLO has been sent - + * $name == 'HELO'|'EHLO': returns the server name + * $name == any other string: if extension $name exists, returns True + * or its options (e.g. AUTH mechanisms supported). Otherwise returns False. + * + * @param string $name Name of SMTP extension or 'HELO'|'EHLO' + * + * @return mixed + */ + public function getServerExt($name) + { + if (!$this->server_caps) { + $this->setError('No HELO/EHLO was sent'); + + return; + } + + if (!array_key_exists($name, $this->server_caps)) { + if ('HELO' == $name) { + return $this->server_caps['EHLO']; + } + if ('EHLO' == $name || array_key_exists('EHLO', $this->server_caps)) { + return false; + } + $this->setError('HELO handshake was used; No information about server extensions available'); + + return; + } + + return $this->server_caps[$name]; + } + + /** + * Get the last reply from the server. + * + * @return string + */ + public function getLastReply() + { + return $this->last_reply; + } + + /** + * Read the SMTP server's response. + * Either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * + * @return string + */ + protected function get_lines() + { + // If the connection is bad, give up straight away + if (!is_resource($this->smtp_conn)) { + return ''; + } + $data = ''; + $endtime = 0; + stream_set_timeout($this->smtp_conn, $this->Timeout); + if ($this->Timelimit > 0) { + $endtime = time() + $this->Timelimit; + } + $selR = [$this->smtp_conn]; + $selW = null; + while (is_resource($this->smtp_conn) and !feof($this->smtp_conn)) { + //Must pass vars in here as params are by reference + if (!stream_select($selR, $selW, $selW, $this->Timelimit)) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + //Deliberate noise suppression - errors are handled afterwards + $str = @fgets($this->smtp_conn, 515); + $this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL); + $data .= $str; + // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled), + // or 4th character is a space, we are done reading, break the loop, + // string array access is a micro-optimisation over strlen + if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) { + break; + } + // Timed-out? Log and break + $info = stream_get_meta_data($this->smtp_conn); + if ($info['timed_out']) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + // Now check if reads took too long + if ($endtime and time() > $endtime) { + $this->edebug( + 'SMTP -> get_lines(): timelimit reached (' . + $this->Timelimit . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + } + + return $data; + } + + /** + * Enable or disable VERP address generation. + * + * @param bool $enabled + */ + public function setVerp($enabled = false) + { + $this->do_verp = $enabled; + } + + /** + * Get VERP address generation mode. + * + * @return bool + */ + public function getVerp() + { + return $this->do_verp; + } + + /** + * Set error messages and codes. + * + * @param string $message The error message + * @param string $detail Further detail on the error + * @param string $smtp_code An associated SMTP error code + * @param string $smtp_code_ex Extended SMTP code + */ + protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') + { + $this->error = [ + 'error' => $message, + 'detail' => $detail, + 'smtp_code' => $smtp_code, + 'smtp_code_ex' => $smtp_code_ex, + ]; + } + + /** + * Set debug output method. + * + * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it + */ + public function setDebugOutput($method = 'echo') + { + $this->Debugoutput = $method; + } + + /** + * Get debug output method. + * + * @return string + */ + public function getDebugOutput() + { + return $this->Debugoutput; + } + + /** + * Set debug output level. + * + * @param int $level + */ + public function setDebugLevel($level = 0) + { + $this->do_debug = $level; + } + + /** + * Get debug output level. + * + * @return int + */ + public function getDebugLevel() + { + return $this->do_debug; + } + + /** + * Set SMTP timeout. + * + * @param int $timeout The timeout duration in seconds + */ + public function setTimeout($timeout = 0) + { + $this->Timeout = $timeout; + } + + /** + * Get SMTP timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->Timeout; + } + + /** + * Reports an error number and string. + * + * @param int $errno The error number returned by PHP + * @param string $errmsg The error message returned by PHP + * @param string $errfile The file the error occurred in + * @param int $errline The line number the error occurred on + */ + protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0) + { + $notice = 'Connection failed.'; + $this->setError( + $notice, + $errmsg, + (string) $errno + ); + $this->edebug( + "$notice Error #$errno: $errmsg [$errfile line $errline]", + self::DEBUG_CONNECTION + ); + } + + /** + * Extract and return the ID of the last SMTP transaction based on + * a list of patterns provided in SMTP::$smtp_transaction_id_patterns. + * Relies on the host providing the ID in response to a DATA command. + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|null|string + */ + protected function recordLastTransactionID() + { + $reply = $this->getLastReply(); + + if (empty($reply)) { + $this->last_smtp_transaction_id = null; + } else { + $this->last_smtp_transaction_id = false; + foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { + if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { + $this->last_smtp_transaction_id = trim($matches[1]); + break; + } + } + } + + return $this->last_smtp_transaction_id; + } + + /** + * Get the queue/transaction ID of the last SMTP transaction + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|null|string + * + * @see recordLastTransactionID() + */ + public function getLastTransactionID() + { + return $this->last_smtp_transaction_id; + } +} diff --git a/vas/rest/class/aws_lib/AWS_Notification/AWS_SMS.class.inc b/vas/rest/class/aws_lib/AWS_Notification/AWS_SMS.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..f1c1388506a87f7af013f81b48c334ec381b8324 --- /dev/null +++ b/vas/rest/class/aws_lib/AWS_Notification/AWS_SMS.class.inc @@ -0,0 +1,56 @@ +<?php + +require_once __DIR__ . '/AWS_notification.class.inc'; +require_once("vmlib/logUtil.inc"); + +/** + * \file AWS_SMS.php + * \brief Class to send SMS by the Veremes's service + * + * \author Anthony Borghi <anthony.borghi@veremes.com> + */ + +Class AWS_SMS extends AWS_notification{ + + const AWS_API_SMS_TYPE = "SMS"; + + //$slogFileName = $properties['log_dir'] . "/notifications/sms.log"; + + /** + * construct + * @param {string} $sAwsAccessKeyId Access key ID. + * @param {string} $sAwsSecretAccessKey Secret access key. + * @param {string} $sDeploymentName Name of the deployment for this API. + */ + function __construct ($sAwsAccessKeyId, $sAwsSecretAccessKey, $sDeploymentName, $sAppIdentifier) { + parent::__construct($sAwsAccessKeyId, $sAwsSecretAccessKey, $sDeploymentName, $sAppIdentifier); + // stockage du noeud principal de déploiement + $this->sType = self::AWS_API_SMS_TYPE; + // définition de la structure de donnée pour ce type de notification + $this->aRequiredFields = array("message", "destination"); + $this->aOptionalFields = array("sender"); + } + + + function sendSMS ($aValues){ + $bError = $this->defineNotification ($aValues); + + if (!$bError){ + //error_log("send SMS to " . $this->aRequestParams["notificationParams"]["destination"]); + $mReturn = $this->sendRequestToSendNotification(); + + if($this->aLastCurlRequestInfo["http_code"] != 200){ + $this->bError = true; + writeToErrorLog("can't send SMS to " . $this->aRequestParams["notificationParams"]["destination"] . ". The service return this message : " . $mReturn); + } else { + writeToLog("send SMS to " . $this->aRequestParams["notificationParams"]["destination"], $this->slogFileName); + } + + //error_log(print_r($this->aLastCurlRequestInfo, true)); + } else { + writeToErrorLog("can't send SMS (missing parameters)"); + } + } +} + +?> \ No newline at end of file diff --git a/vas/rest/class/aws_lib/AWS_Notification/AWS_notification.class.inc b/vas/rest/class/aws_lib/AWS_Notification/AWS_notification.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..004e9aaaae8a86368a3a93b67095ab34bae282f2 --- /dev/null +++ b/vas/rest/class/aws_lib/AWS_Notification/AWS_notification.class.inc @@ -0,0 +1,87 @@ +<?php + +require_once __DIR__ . '/../AmazonApiGateway.class.inc'; + +/** + * \file AWS_notification.php + * \brief Class to send notifications by the Veremes's service + * + * \author Anthony Borghi <anthony.borghi@veremes.com> + */ + +Class AWS_notification extends AmazonApiGateway{ + + public $sType; // Type de notification + public $aRequiredFields = array(); // Liste des champs requis pour la notification en cours + public $aOptionalFields = array(); // Liste des champs optionnels pour la notification en cours + public $oAWSGateway; // Objet de référence sur l'API gateway + public $sDeploymentName; // Main node of API Deployment + public $aRequestParams = array(); // Parameter to send the notification + public $sAppIdentifier = null; // Parameter to indentify the app + + public $bError = false; + + // Liste de constante en lien avec l'API gateway du service + const AWS_API_REGION = 'eu-west-1'; + const AWS_API_ID = '6u2e49upog'; // surement inutile si on utilise Route 53 + const AWS_API_SEND_NOTIFICATION_STAGE = '/addnotification'; + const AWS_API_SEND_NOTIFICATION_METHOD = 'POST'; + + /** + * construct + * @param {string} $sAwsAccessKeyId Access key ID. + * @param {string} $sAwsSecretAccessKey Secret access key. + * @param {string} $sDeploymentName Name of the deployment for this API. + */ + function __construct ($sAwsAccessKeyId, $sAwsSecretAccessKey, $sDeploymentName, $sAppIdentifier) { + parent::__construct($sAwsAccessKeyId, $sAwsSecretAccessKey, self::AWS_API_REGION, self::AWS_API_ID, $sDeploymentName . self::AWS_API_SEND_NOTIFICATION_STAGE); + // stockage du noeud principal de déploiement + $this->sDeploymentName = $sDeploymentName; + $this->sAppIdentifier = $sAppIdentifier; + } + + function defineNotification ($aValues){ + + $aRequiredFieldsFilled = array(); + $aParams = array(); + + foreach ($aValues as $sKey => $mValue) { + if (in_array($sKey, $this->aRequiredFields)){ + $aParams[$sKey] = $mValue; + array_push($aRequiredFieldsFilled, $sKey); + } else if (in_array($sKey, $this->aOptionalFields)){ + $aParams[$sKey] = $mValue; + } + } + + $this->aRequestParams["notificationParams"] = $aParams;// json_encode($aParams); + + $this->bError = (count($aRequiredFieldsFilled) !== count($this->aRequiredFields)); + + return $this->bError; + } + + + function sendRequestToSendNotification (){ + + if(!empty($this->sAppIdentifier)){ + $this->aRequestParams["app_id"] = $this->sAppIdentifier; + } + + $this->aRequestParams["notificationType"] = $this->sType; + + $sJsonParams = json_encode($this->aRequestParams); + //$iParamsLength = strlen($sJsonParams); + + $sUrl = "https://" . $this->sHost . "/" . $this->sStageName; + //$sFullUrl = self::AWS_API_SEND_NOTIFICATION_METHOD . ' ' . $sUrl . ' HTTP/1.1'; + + $aAddedHeaders = array('content-type: application/json'); + + $aHeaders = $this->generateGatewayRequestHeaders(self::AWS_API_SEND_NOTIFICATION_METHOD, $sUrl, $aAddedHeaders, $sJsonParams); + + return $this->curlRequest($sUrl, self::AWS_API_SEND_NOTIFICATION_METHOD, $sJsonParams, $aHeaders); + } +} + +?> \ No newline at end of file diff --git a/vas/rest/class/aws_lib/AmazonAWS.class.inc b/vas/rest/class/aws_lib/AmazonAWS.class.inc new file mode 100644 index 0000000000000000000000000000000000000000..223a0534b6262627e65631e7905eb9256825f8b9 --- /dev/null +++ b/vas/rest/class/aws_lib/AmazonAWS.class.inc @@ -0,0 +1,485 @@ +<?php +require_once("vmlib/logUtil.inc"); + +/** + * \file AmazonAWS.php + * \brief Main class to use AWS services (keyGen, CrulRequest, ...) + * + * \author Frederic Carretero <frederic.carretero@veremes.com> + */ + +Class AmazonAWS { + const HASHING_ALGORITHM = 'sha256'; + public $sAwsRegion; + public $aLastCurlRequestInfo; + public $sHost; + public $sLogFilePath; // Chemin optionnel vers le fichier de log pour Amazon S3. + private $sAwsAccessKeyId; + private $sAwsSecretAccessKey; + private $sHashingAlgorithmString; + + /** + * construct + * @param {string} $sAwsAccessKeyId Access key ID. + * @param {string} $sAwsSecretAccessKey Secret access key. + * @param {string} $sAwsRegion Region. + */ + function __construct ($sAwsAccessKeyId, $sAwsSecretAccessKey, $sAwsRegion) { + $this->sAwsAccessKeyId = $sAwsAccessKeyId; + $this->sAwsSecretAccessKey = $sAwsSecretAccessKey; + $this->sAwsRegion = $sAwsRegion; + $this->sHashingAlgorithmString = 'AWS4-HMAC-' . strtoupper(self::HASHING_ALGORITHM); + } + + /** + * Get value of inaccessible property. + * @param {string} $sPropertyName Name of the property. + * @return Paramter's value + */ + function __get($sPropertyName) { + if (isset($this->$sPropertyName)) + return $this->$sPropertyName; + } + + /** + * generate an header for AWS request + * @param {string} $sMainRequestString Requête principale: 'GET https://s3.amazonaws.com/azerty/?Action=ListUsers&Version=2010-05-08 HTTP/1.1'. + * @param {string} $sHost hostname du serveur de destination. + * @param {string} $sService Service à contacter (Constante dans les fichiers enfants). + * @param {Array} $aHeaders Liste de headers à ajouter. + * @param {string} $sRequestPayload Chaine de référence pour le calcul de la signature (dans le cas du POST passer les paramètres de la requête, S3 'UNSIGNED-PAYLOAD', sinon laisser chaine vide). + * @param {boolean} $bAddAmzContentHeader Ajoute le header x-amz-content à la liste des headers signés. + * @param {string|object} $sTimestamp objet timestamp à utiliser (le mot clef 'Now' permet à la fonction d'intancier un objet sur le timestamp courant). A n'utiliser que pour des tests + * @param {boolean} $bFromTestCase Active les débuggage de la signature (log). + * @return array request header for AWS or false if error + */ + function generateAwsSignedHeaders ($sMainRequestString, $sHost, $sService, $aHeaders = array(), $sRequestPayload = 'UNSIGNED-PAYLOAD', $bAddAmzContentHeader = false, $sTimestamp = "Now", $bFromTestCase = false){ + + $aMainRequest = explode(" ", $sMainRequestString); + + if (count($aMainRequest) < 2){ + writeToErrorLog('sMainRequestString has to be as this pattern : GET https://s3.amazonaws.com/azerty/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 and yours is ' . $sMainRequestString); + return false; + } + + if (count($aMainRequest) > 3){ + // on sauvegarde avant de trafiquer la requete + $aTempMainRequest = $aMainRequest; + $aMainRequest = array(); + $aMainRequest[] = $aTempMainRequest[0]; + // éliminer + $sTempUrl = ""; + + for($i = 1; $i <= (count($aTempMainRequest) - 2); $i++){ + $sTempUrl .= $aTempMainRequest[$i]; + + if($i != (count($aTempMainRequest) - 2)){ + $sTempUrl .= " "; + } + } + + $aMainRequest[] = $sTempUrl; + + $aMainRequest[] = end($aTempMainRequest); + } + + if ($sTimestamp == "Now"){ + $sTimestamp = time(); + } + + // Entêtes obligatoires. + $sXAmzDate = gmdate('Ymd\THis\Z', $sTimestamp); + $sDate = gmdate('Ymd', $sTimestamp); + + $sHashedPayload = $this->createHashedPayload($sRequestPayload);; + + array_push($aHeaders, 'x-amz-date: ' . $sXAmzDate); + array_push($aHeaders, 'host: ' . $sHost); + + if($bAddAmzContentHeader){ + array_push($aHeaders, 'x-amz-content-' . self::HASHING_ALGORITHM . ': ' . $sHashedPayload); + } + + $sSignedHeaders = $this->prepareQuerySignedHeaders($aHeaders); + + // 1. Création d'une demande canonique pour Signature V4. + $sCanonicalRequest = $this->mainRequestArrayToCanonicalString($aMainRequest, $sHost, $aHeaders, $sHashedPayload, $sSignedHeaders); + + if($bFromTestCase){ + writeToDebugLog("creq : \n" . $sCanonicalRequest); + } + + // 2. Création d'une chaîne à signer pour Signature V4. + $sStringToSign = $this->createStringToSignv2($sDate, $sXAmzDate, $sCanonicalRequest, $sService); + + if($bFromTestCase){ + writeToDebugLog("sts : \n" . $sStringToSign); + } + + // 3. Calcul de la signature pour AWS Signature V4. + $sSigningKey = $this->createSigningKey($sService, $sDate); + $sSignature = $this->calculateSignature($sStringToSign, $sSigningKey); + + // 4. Création de l'entête "Authorization" pour la requête. + $sCredentialScope = $this->createCredentialScope($sDate, $sService); + $sAuthorizationHeader = $this->generateAuthorizationHeader($this->sHashingAlgorithmString, $sCredentialScope, $sSignedHeaders, $sSignature); + + if($bFromTestCase){ + writeToDebugLog("authz : \n" . $sAuthorizationHeader); + } + + array_push($aHeaders, 'Authorization: ' . $sAuthorizationHeader); + + return $aHeaders; + } + + /** + * generate an canonical request for AWS request + * @param {array} $aMainRequest Main request String with this pattern: 'GET https://s3.amazonaws.com/azerty/?Action=ListUsers&Version=2010-05-08 HTTP/1.1' exploded on spaces. + * @param {string} $sHost HostName to parse url + * @param {array} $aHeaders sorted array of all the headers of this request + * @param {string} $sHashedPayload hash of the payload request + * @return array request header for AWS or false if error + */ + function mainRequestArrayToCanonicalString($aMainRequest, $sHost, $aHeaders, $sHashedPayload, $sSignedHeaders){ + $sHTTPRequestMethod = $aMainRequest[0]; + + $aFullUrl = explode("?", $aMainRequest[1]); + + $sCanonicalQueryString = ""; + if(count($aFullUrl) > 1){ + $sCanonicalQueryString = $this->prepareQueryString($aFullUrl[1]); + } + + $sCanonicalUri = $this->prepareQueryUri($aFullUrl[0], $sHost); + $sCanonicalHeaders = $this->prepareQueryHeaders($aHeaders); + $sCanonicalSignedHeaders = $sSignedHeaders; + + $sReturn = $sHTTPRequestMethod . chr(10) . + $sCanonicalUri . chr(10) . + $sCanonicalQueryString . chr(10) . + $sCanonicalHeaders . chr(10) . + $sCanonicalSignedHeaders . chr(10) . + $sHashedPayload; + + return $sReturn; + } + + /** + * Curl request + * @param {string} $sUrl Url of the Curl request. + * @param {string} $sType Type of the Curl request (GET, POST). + * @param {array} $aData Data of the Curl request. + * @param {array} $aHeaders Headers of the Curl request. + * @return Request result + */ + // + function curlRequest($sUrl, $sType, $aData = array(), $aHeaders = array(), $bMultipartFormData = false) { + // + $this->aLastCurlRequestInfo = ''; + // + $ch = curl_init(); + $sType = strtoupper($sType); + // Force la méthode de requête utilisée (GET, POST...). + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $sType); + // Url à utiliser. + if (($sType == 'GET' || $sType == 'DELETE') && !empty($aData)) + $sUrl .= '?' . http_build_query($aData); + curl_setopt($ch, CURLOPT_URL, $sUrl); + // Retour sous forme de texte. + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // Requête POST. + if ($sType == 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + // Chaîne de requête en encodage URL. + if (is_array($aData) && !$bMultipartFormData) + $aData = http_build_query($aData); + // Données de la requête. + curl_setopt($ch, CURLOPT_POSTFIELDS, $aData); + // + curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true); + // Entête pour la requête en POST. + //$aHeaders[] = 'Content-Type: application/x-www-form-urlencoded'; + } + // Entête pour la requête + //$aHeaders[] = 'Accept: application/json'; + //if (!empty($this->sToken)) + //$aHeaders[] = 'Authorization: Bearer ' . $this->sToken; // Token obligatoire pour éxécuter la requête. + // Durée max. de la requête. + //curl_setopt($ch, CURLOPT_TIMEOUT, 120); + // Exécute la session CURL. + // Log. + /* + $handle = fopen("curl_log.txt", "a"); + fwrite($handle, PHP_EOL . '-----------------------' . PHP_EOL); + curl_setopt($ch, CURLOPT_VERBOSE, true); + curl_setopt($ch, CURLOPT_STDERR , $handle); + */ + // ajout des en-tête + curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeaders); + curl_setopt($ch, CURLINFO_HEADER_OUT, true); + //curl_setopt($ch, CURLOPT_ENCODING, ""); + //curl_setopt($ch, CURLOPT_MAXREDIRS, 10); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + // Curl error: SSL certificate problem: unable to get local issuer certificate + // Curl error n°60 + curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false); + // + $output = curl_exec($ch); + // Erreur de la requête CURL. + if(curl_errno($ch)) { + writeToErrorLog('Curl error: ' . curl_error($ch)); + writeToErrorLog('Curl error n°' . curl_errno($ch)); + } + // Informations de la requête. + $aCurlInfo = curl_getinfo($ch); + $this->aLastCurlRequestInfo = $aCurlInfo; + //file_put_contents('C:/svn/gtf_cloud/gtf.engines/log/response.log', print_r($aCurlInfo, true)); + //writeToErrorLog(print_r(curl_getinfo($ch), true)); + + // Ferme la session CURL. + curl_close($ch); + // + //fclose($handle); + // + return $output; + } + + /** + * Creating a credential scope. + * @param {string} $sDate Date (YYYYMMDD). + * @param {string} $sApiComponentService Api component service. + * @return Credential scope. + */ + function createCredentialScope($sDate, $sApiComponentService) { + return $sDate . "/" . $this->sAwsRegion . '/' . $sApiComponentService . '/aws4_request'; + } + + /** + * Creating a string to sign. + * @param {string} $sDate Date (YYYYMMDD). + * @param {string} $sTimestamp Unix timestamp. + * @param {string} $sCanonicalRequest Canonical request. + * @param {string} $sApiComponentService Api component service. + * @return String to sign. + */ + function createStringToSign($sDate, $sTimestamp, $sCanonicalRequest, $sApiComponentService) { + $sRequestDateTime = $sDate . 'T' . gmdate('His', $sTimestamp) . 'Z'; + $sCredentialScope = $this->createCredentialScope($sDate, $sApiComponentService); + $sHashedCanonicalRequest = hash(self::HASHING_ALGORITHM, $sCanonicalRequest, false); + $sStringToSign = $this->sHashingAlgorithmString . chr(10) . + $sRequestDateTime . chr(10) . + $sCredentialScope . chr(10) . + $sHashedCanonicalRequest; + return $sStringToSign; + } + + /** + * Creating a string to sign. + * @param {string} $sDate Date (YYYYMMDD). + * @param {string} $sTimestamp Unix timestamp. + * @param {string} $sCanonicalRequest Canonical request. + * @param {string} $sApiComponentService Api component service. + * @return String to sign. + */ + function createStringToSignv2($sDate, $sXAmzDate, $sCanonicalRequest, $sApiComponentService) { + $sCredentialScope = $this->createCredentialScope($sDate, $sApiComponentService); + $sHashedCanonicalRequest = hash(self::HASHING_ALGORITHM, $sCanonicalRequest, false); + $sStringToSign = $this->sHashingAlgorithmString . chr(10) . + $sXAmzDate . chr(10) . + $sCredentialScope . chr(10) . + $sHashedCanonicalRequest; + return $sStringToSign; + } + + /** + * Creating a hashed payload. + * @param {string} $sPayload CurrentPayload. + * @return String hashed Payload. + */ + function createHashedPayload($sPayload){ + if($sPayload == "UNSIGNED-PAYLOAD"){ + return $sPayload; + }else{ + return hash(self::HASHING_ALGORITHM, $sPayload, false); + } + } + + /** + * Prepare a query string for signature calculation . + * @param {string} $sQueryString queryString to prepare. + * @return QueryString prepared + */ + function prepareQueryString ($sQueryString){ + $aUri = explode("?", $sQueryString); + $sParameters = $aUri[count($aUri) - 1]; + $aParameters = explode("&", $sParameters); + + $sReturn = ""; + + //order array before treatement F < a Case sensitive + sort($aParameters); + + for ($i = 0; $i < count($aParameters); $i++){ + $aParameter = explode("=",$aParameters[$i]); + if(count($aParameter) === 2){ + $sReturn .= rawurlencode($aParameter[0]); + $sReturn .= "="; + $sReturn .= rawurlencode($aParameter[1]); + if ($i < count($aParameters) - 1){ + $sReturn .= "&"; + } + } + } + return $sReturn; + } + + /** + * Prepare a Uri for signature calculation . + * @param {string} $sUriWithoutQuery queryURI to prepare. (https://s3.amazon.aws.com/toto/tata) + * @param {string} $sHost Hostname to extract the path after domain name + * @return QueryString prepared + */ + function prepareQueryUri ($sUriWithoutQuery, $sHost){ + + $sUriWithoutQuery = preg_replace('/^https?:\/\/' . $sHost . '/i', '', $sUriWithoutQuery); + + $aUrl = explode("/", $sUriWithoutQuery); + + $aUrl = array_values(array_filter($aUrl, function($value) {return ($value !== '');})); + + $i = 0; + $aUri = array(); + + while ($i < count($aUrl)){ + if ($aUrl[$i] !== '.'){ + if($aUrl[$i] !== '..'){ + array_push($aUri, $aUrl[$i]); + } else { + array_splice($aUri, -1); + } + } + $i++; + } + + $sReturn = "/" . str_replace('%2F', '/', rawurlencode(implode("/", $aUri))); + + if (substr($sUriWithoutQuery, -1) == '/' && count($aUrl) > 1){ + $sReturn .= "/"; + } + + return $sReturn; + } + + /** + * Prepare headers for signature calculation . + * @param {array} $aHeaders array of the headers for the request (array of string) + * @return QueryString prepared + */ + function prepareQueryHeaders ($aHeaders){ + $aMergedHeader = array(); + + $sReturn = ""; + + // dédoublonage + for ($i = 0; $i < count($aHeaders); $i++){ + $aHeader = explode(":", $aHeaders[$i]); + if (count($aHeader) === 2){ + $sReplacer = ' '; + if (strpos(trim($aHeader[1]), "\n") > -1) { + $sReplacer = ','; + } + $aMergedHeader[strtolower($aHeader[0])][] = preg_replace('/\s{1,}/m', $sReplacer, trim($aHeader[1])); + } + } + + ksort($aMergedHeader, SORT_STRING | SORT_FLAG_CASE); + + // calcul des header pour la requete canonique + foreach ($aMergedHeader as $sKey => $aValue) { + $sReturn .= $sKey; + $sReturn .= ":"; + $sReturn .= implode(',', $aValue); + $sReturn .= chr(10); + } + + return $sReturn; + } + + /** + * Prepare signed headers for signature calculation . + * @param {array} $aHeaders array of the headers for the request (array of string) + * @return QueryString prepared + */ + function prepareQuerySignedHeaders ($aHeaders){ + $aMergedHeader = array(); + $sReturn = ""; + + // dédoublonage + for ($i = 0; $i < count($aHeaders); $i++){ + $aHeader = explode(":", $aHeaders[$i]); + if (count($aHeader) === 2){ + $aMergedHeader[strtolower($aHeader[0])][] = trim($aHeader[1]); + } + } + + ksort($aMergedHeader, SORT_STRING | SORT_FLAG_CASE); + + // aggrégat des en-t^tes signées + foreach ($aMergedHeader as $sKey => $aValue) { + $sReturn .= $sKey; + $sReturn .= ";"; + } + + // on supprime le dernier ; + $sReturn = substr($sReturn, 0, -1); + + return $sReturn; + } + + /** + * Creating a signing Key. + * @param {string} $sApiComponentService Component service for API execution. + * @param {string} $sDate Date (YYYYMMDD). + * @return Signing key. + */ + function createSigningKey($sApiComponentService, $sDate) { + return hash_hmac(self::HASHING_ALGORITHM, 'aws4_request', hash_hmac(self::HASHING_ALGORITHM, $sApiComponentService, hash_hmac(self::HASHING_ALGORITHM, $this->sAwsRegion, hash_hmac(self::HASHING_ALGORITHM, $sDate, 'AWS4' . $this->sAwsSecretAccessKey, true), true), true), true); + } + + /** + * Calculating a Signature (Version 4 algorithm). + * @param {string} $sStringToSign String to sign. + * @param {string} $sSigningKey Signing key. + * @return Signature. + */ + function calculateSignature($sStringToSign, $sSigningKey) { + return hash_hmac(self::HASHING_ALGORITHM, $sStringToSign, $sSigningKey); + } + + /** + * Generating an authorization header. + * @param {string} $sAlgorithm String of the hashing algorithm. + * @param {string} $sCredentialScope Credential scope. + * @param {string} $sSignedHeaders Request header names. + * @param {string} $sSignature Calculated signature. + * @return Headers for request. + */ + function generateAuthorizationHeader($sAlgorithm, $sCredentialScope, $sSignedHeaders, $sSignature) { + return $sAlgorithm . ' Credential=' . $this->sAwsAccessKeyId . '/' . $sCredentialScope . ', SignedHeaders=' . $sSignedHeaders . ', Signature=' . $sSignature; + } + + /** + * Write a message to the error log file. + * @param {string} $sMessage Message to write to the log file. + */ + function writeToErrorLog($sMessage) { + $aDebugBacktrace = debug_backtrace(); + $sLogMessage = '|ERROR|' . $aDebugBacktrace[1]['class'] . '::' . $aDebugBacktrace[1]['function'] . '| ' . $sMessage; + if (empty($this->sLogFilePath)) + writeToErrorLog($sLogMessage); + else + writeToLog($sLogMessage, $this->sLogFilePath); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/aws_lib/AmazonApiGateway.class.inc b/vas/rest/class/aws_lib/AmazonApiGateway.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..3ba40545f25fb7b80dc791a6bdd188eda451cae9 --- /dev/null +++ b/vas/rest/class/aws_lib/AmazonApiGateway.class.inc @@ -0,0 +1,124 @@ +<?php +require_once __DIR__ . '/AmazonAWS.class.inc'; + +/** + * \file AmazonApiGateway.php + * \brief Class to use API Gateway FME cloud + * + * \author Frederic Carretero <frederic.carretero@veremes.com> + */ + +Class AmazonApiGateway extends AmazonAWS { + const API_COMPONENT_SERVICE = 'execute-api'; + public $sRestApiId; // Identifiant de l'API. + public $sStageName; // Nom de l'étape d'un déploiement de l'API. + + /** + * construct + * @param {string} $sAwsAccessKeyId Access key ID. + * @param {string} $sAwsSecretAccessKey Secret access key. + * @param {string} $sAwsRegion Region. + * @param {string} $sRestApiId API identifier. + * @param {string} $sStageName Stage name of an API deployment. + */ + function __construct ($sAwsAccessKeyId, $sAwsSecretAccessKey, $sAwsRegion, $sRestApiId, $sStageName) { + // Paramètres obligatoires de la classe mère AmazonAWS. + parent::__construct($sAwsAccessKeyId, $sAwsSecretAccessKey, $sAwsRegion); + // Paramètres pour l'url racine de l'API. + $this->sRestApiId = $sRestApiId; + $this->sStageName = $sStageName; + //if($sAwsRegion == 'us-east-1') + //$this->sHost = trim('' . self::API_COMPONENT_SERVICE . '.amazonaws.com'); + //else + $this->sHost = trim($sRestApiId . '.' . self::API_COMPONENT_SERVICE . '.' . $sAwsRegion . '.amazonaws.com'); + } + + /** + * Generating all the headers for the request. Deprecated. + * @return Headers for request. + */ + function generateRequestHeaders() { + $sTimestamp = time(); + // Entêtes obligatoires. + $sXAmzDate = gmdate('Ymd\THis\Z', $sTimestamp); + $sDate = gmdate('Ymd', $sTimestamp); + // Charge utile vide hachée. + $sRequestPayload = ''; + + // 1. Création d'une demande canonique pour Signature V4. + $sHttpRequestMethod = 'GET'; + $sCanonicalUri = str_replace('%2F', '/', rawurlencode('/' . $this->sStageName)); + $sCanonicalQueryString = ''; + $sCanonicalHeaders = 'host:' . $this->sHost . chr(10) . + 'x-amz-date:' . $sXAmzDate . chr(10); + $sSignedHeaders = 'host;x-amz-date'; + $sHashedPayload = hash(self::HASHING_ALGORITHM, $sRequestPayload, false); + $sCanonicalRequest = $sHttpRequestMethod . chr(10) . + $sCanonicalUri . chr(10) . + $sCanonicalQueryString . chr(10) . + $sCanonicalHeaders . chr(10) . + $sSignedHeaders . chr(10) . + $sHashedPayload; + + // 2. Création d'une chaîne à signer pour Signature V4. + $sStringToSign = $this->createStringToSign($sDate, $sTimestamp, $sCanonicalRequest, self::API_COMPONENT_SERVICE); + + // 3. Calcul de la signature pour AWS Signature V4. + $sSigningKey = $this->createSigningKey(self::API_COMPONENT_SERVICE, $sDate); + $sSignature = $this->calculateSignature($sStringToSign, $sSigningKey); + + // 4. Création de l'entête "Authorization" pour la requête. + $sCredentialScope = $this->createCredentialScope($sDate, self::API_COMPONENT_SERVICE); + $sAuthorizationHeader = $this->generateAuthorizationHeader($this->sHashingAlgorithmString, $sCredentialScope, $sSignedHeaders, $sSignature); + + // Entêtes pour la requete. + $aHeaders = array( + 'Authorization: ' . $sAuthorizationHeader, + 'X-Amz-Date: ' . $sXAmzDate + ); + /* + echo PHP_EOL . 'Canonical request:' . PHP_EOL; + print_r($sCanonicalRequest); + echo PHP_EOL . PHP_EOL . 'String To Sign:' . PHP_EOL; + print_r($sStringToSign); + */ + return $aHeaders; + } + + function generateGatewayRequestHeaders($sMethod, $sUrl, $aAddedHeaders, $mParams, $bValuesAsFormData = false) { + + $sParams = ''; + + //stringify params if it's an array of depth = 1 else value = array + if(!empty($mParams) && !$bValuesAsFormData){ + if(is_array($mParams)){ + foreach ($mParams as $sKey => $sValue) { + $sParams .= urlencode($sKey); + $sParams .= "="; + $sParams .= urlencode($sValue); + $sParams .= '&'; + } + $sParams = substr($sParams, 0, -1); + $aAddedHeaders[] = 'Content-Type: application/x-www-form-urlencoded'; + } else { + $sParams = $mParams; + } + } + + $sUrlParameter = "/"; + + if(strpos($sUrl, "/") === 1){ + $sUrlParameter = ""; + } + + // build sFullUrl + if(strpos($sUrl, $this->sHost) === -1){ + $sUrl = 'https://' . $this->sHost . $sUrlParameter . $sUrl; + } + + $sFullUrl = $sMethod . ' ' . $sUrl . ' HTTP/1.1'; + + return $this->generateAwsSignedHeaders($sFullUrl, $this->sHost, self::API_COMPONENT_SERVICE, $aAddedHeaders, $sParams); + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/aws_lib/AmazonS3.class.inc b/vas/rest/class/aws_lib/AmazonS3.class.inc new file mode 100644 index 0000000000000000000000000000000000000000..32c7ed76f933ba2499f7cfa63c4a943cb4fa6bd9 --- /dev/null +++ b/vas/rest/class/aws_lib/AmazonS3.class.inc @@ -0,0 +1,375 @@ +<?php +require_once __DIR__ . '/AmazonAWS.class.inc'; + +/** + * \file AmazonS3.php + * \brief Class to upload and get file in a bucket S3 + * + * \author Frederic Carretero <frederic.carretero@veremes.com> + * \author Anthony Borghi <anthony.borghi@veremes.com> + */ + +Class AmazonS3 extends AmazonAWS { + const API_COMPONENT_SERVICE = 's3'; + + /** + * construct + * @param {string} $sAwsAccessKeyId Access key ID. + * @param {string} $sAwsSecretAccessKey Secret access key. + * @param {string} $sAwsRegion Region. + */ + function __construct ($sAwsAccessKeyId, $sAwsSecretAccessKey, $sAwsRegion) { + // Paramètres obligatoires de la classe mère AmazonAWS. + parent::__construct($sAwsAccessKeyId, $sAwsSecretAccessKey, $sAwsRegion); + /* + if($sAwsRegion == 'us-east-1') + $this->sHost = trim('s3.amazonaws.com'); + else + $this->sHost = trim('s3-' . $sAwsRegion . '.amazonaws.com'); + */ + // Url racine de l'API. + $this->sHost = trim(self::API_COMPONENT_SERVICE . '-' . $sAwsRegion . '.amazonaws.com'); + } + + /** + * Generating all the headers for a GET request. deprecated + * @param {string} $sBucket A container for objects stored in Amazon S3. + * @param {string} $sKey The unique identifier for an object within a bucket. + * @return Headers for request. + */ + function generateRequestHeaders($sBucket, $sKey, $sQueryParameter = '', $sRequestPayload = 'UNSIGNED-PAYLOAD') { + // + $sServiceEndpoint = $sBucket . '.' . $this->sHost; + $query_string = ""; + $sTimestamp = time(); + // Entêtes obligatoires. + $sXAmzDate = gmdate('Ymd\THis\Z', $sTimestamp); + $sDate = gmdate('Ymd', $sTimestamp); + //$sRequestPayload = '$sRequestPayload '; + + // 1. Création d'une demande canonique pour Signature V4. + $sHttpRequestMethod = 'GET'; + $sCanonicalUri = str_replace('%2F', '/', rawurlencode('/' . $sKey)); + $sCanonicalQueryString = $this->prepareQueryString($sQueryParameter); + $sCanonicalHeaders = 'host:' . $sServiceEndpoint . chr(10) . + 'x-amz-content-' . self::HASHING_ALGORITHM . ':' . $sRequestPayload . chr(10) . + 'x-amz-date:' . $sXAmzDate . chr(10); + $sSignedHeaders = 'host;x-amz-content-' . self::HASHING_ALGORITHM . ';x-amz-date'; + $sHashedPayload = $this->createHashedPayload($sRequestPayload); + //$sHashedPayload = $sRequestPayload; + $sCanonicalRequest = $sHttpRequestMethod . chr(10) . + $sCanonicalUri . chr(10) . + $sCanonicalQueryString . chr(10) . + $sCanonicalHeaders . chr(10) . + $sSignedHeaders . chr(10) . + $sHashedPayload; + + // 2. Création d'une chaîne à signer pour Signature V4. + $sStringToSign = $this->createStringToSign($sDate, $sTimestamp, $sCanonicalRequest, self::API_COMPONENT_SERVICE); + + // 3. Calcul de la signature pour AWS Signature V4. + $sSigningKey = $this->createSigningKey(self::API_COMPONENT_SERVICE, $sDate); + $sSignature = $this->calculateSignature($sStringToSign, $sSigningKey); + + // 4. Création de l'entête "Authorization" pour la requête. + $sCredentialScope = $this->createCredentialScope($sDate, self::API_COMPONENT_SERVICE); + $sAuthorizationHeader = $this->generateAuthorizationHeader($this->sHashingAlgorithmString, $sCredentialScope, $sSignedHeaders, $sSignature); + + // Entêtes pour la requete. + $aHeaders = array( + 'host: ' . $sServiceEndpoint, + 'x-amz-content-' . self::HASHING_ALGORITHM . ': ' . $sHashedPayload, + 'x-amz-date: ' . $sXAmzDate, + 'Authorization: ' . $sAuthorizationHeader + ); + + return $aHeaders; + } + + function generateS3requestHeaders($sMethod, $sUrl, $sBucket, $aHeaders = array(), $sRequestPayload = 'UNSIGNED-PAYLOAD'){ + // build bucket hostname + $sBucketHost = $sBucket . "." . $this->sHost; + + $sUrlParameter = "/"; + + if(strpos($sUrl, "/") === 1){ + $sUrlParameter = ""; + } + + // build sFullUrl + if(strpos($sUrl, $sBucketHost) === -1){ + $sUrl = 'https://' . $sBucketHost . $sUrlParameter . $sUrl; + } + + $sFullUrl = $sMethod . ' ' . $sUrl . ' HTTP/1.1'; + return $this->generateAwsSignedHeaders($sFullUrl, $sBucketHost, self::API_COMPONENT_SERVICE, $aHeaders, $sRequestPayload, true, 'Now', true); + } + + /** + * Generating all the data for a POST request. + * @param {string} $sBucket A container for objects stored in Amazon S3. + * @param {string} $sKey The unique identifier for an object within a bucket. + * @return Headers for request. + */ + function generatePostData($sBucket, $sKey, $sAcl = 'public-read') { + $sTimestamp = time(); + $sXAmzDate = gmdate('Ymd\THis\Z', $sTimestamp); + $sDate = gmdate('Ymd', $sTimestamp); + //$sAcl = 'public-read'; + $sCredential = $this->sAwsAccessKeyId . '/' . $sDate . '/' . $this->sAwsRegion . '/' . self::API_COMPONENT_SERVICE . '/aws4_request'; + // 1. Création d'une chaîne à signer pour Signature V4 + $aPolicy = array( + 'expiration' => gmdate('Y-m-d\TH:i:s.000\Z', $sTimestamp + 86400), + 'conditions' => array( + array('acl' => $sAcl), + array('bucket' => $sBucket), + array('starts-with', '$Content-Type', ''), + array('starts-with', '$key', ''), + array('x-amz-algorithm' => $this->sHashingAlgorithmString), + array('x-amz-credential' => $sCredential), + array('x-amz-date' => $sXAmzDate) + ) + ); + $sStringToSign = base64_encode(json_encode($aPolicy)); + + // 2. Calcul de la signature pour AWS Signature V4. + $sSigningKey = hash_hmac(self::HASHING_ALGORITHM, 'aws4_request', hash_hmac(self::HASHING_ALGORITHM, self::API_COMPONENT_SERVICE, hash_hmac(self::HASHING_ALGORITHM, $this->sAwsRegion, hash_hmac(self::HASHING_ALGORITHM, $sDate, 'AWS4' . $this->sAwsSecretAccessKey, true), true), true), true); + $sSignature = hash_hmac(self::HASHING_ALGORITHM, $sStringToSign, $sSigningKey); + + // 3. Données (post). + $aPostData = array( + 'key' => $sKey, + 'acl' => $sAcl, + 'Content-Type' => '', + 'X-Amz-Credential' => $sCredential, + 'X-Amz-Algorithm' => $this->sHashingAlgorithmString, + 'X-Amz-Date' => $sXAmzDate, + 'Policy' => $sStringToSign, + 'X-Amz-Signature' => $sSignature + ); + return $aPostData; + } + + /** + * Downloads a file. + * @param {string} $sBucket Name of a container for objects. + * @param {string} $sKey Name of a unique identifier for an object within a bucket. + * @param {string} $sFilePath Path of the file to save. + * @return File content + */ + function downloadFile($sBucket, $sKey, $sFilePath = null) { + // Url vers le fichier. + $sUrl = 'https://' . $sBucket . '.' . $this->sHost . '/' . $sKey; + $sMethod = 'GET'; + // Génération des entêtes pour la requete. + $aHeaders = $this->generateS3requestHeaders($sMethod, $sUrl, $sBucket); + + $aHeaders[] = 'Accept: application/octet-stream'; + // Transfert cURL. + $sRequestResult = $this->curlRequest($sUrl, $sMethod, null, $aHeaders); + // + if ($this->aLastCurlRequestInfo['http_code'] != 200) { + $this->writeToErrorLog($this->formatS3ErrorMessage($sRequestResult)); + return false; + } + else { + if (!empty($sFilePath)) + file_put_contents($sFilePath, $sRequestResult); + else + return $sRequestResult; + } + } + + /** + * Upload a file. + * @param {string} $sBucket Name of a container for objects. + * @param {string} $sKey Name of a unique identifier for an object within a bucket. + * @param {string} $sFilePath Path of the file to save. + * @return File content + */ + function uploadFile($sBucket, $sKey, $sFilePath) { + if (file_exists($sFilePath)) { + $sFileName = pathinfo($sFilePath, PATHINFO_BASENAME); + // Url vers le fichier. + $sUrl = 'https://' . $sBucket . '.' . $this->sHost; + // Génération des entêtes pour la requete. + $aPostData = $this->generatePostData($sBucket, $sKey); + $aPostData['Content-Type'] = mime_content_type($sFilePath); + $aPostData['file'] = new CurlFile(realpath($sFilePath), $aPostData['Content-Type'], $sFileName); + $aHeaders = array( + 'Content-Type: multipart/form-data', + ); + $sRequestResult = $this->curlRequest($sUrl, 'post', $aPostData, $aHeaders, true); + if ($this->aLastCurlRequestInfo['http_code'] != 204) { + $this->writeToErrorLog($this->formatS3ErrorMessage($sRequestResult)); + return false; + } + } + else + return false; + } + + /** + * ScanDir in a bucket + * @param {string} $sBucket Name of a container for objects. + * @param {string} $sPrefix Path of the folder to scan + * @param {boolean} $bWithFileInfos boolean to add fileInfo with filename + * @return Array associative array describing directory scanned + */ + function scanDir($sBucket, $sPrefix, $bWithFileInfos = false){ + $oFiles = false; + $sQueryString = '?list-type=2&prefix=' . $sPrefix; + //URL to send request + $sUrl = 'https://' . $sBucket . '.' . $this->sHost . "/" . $sQueryString; + $sMethod = 'GET'; + + // Génération des entêtes pour la requete. + $aHeaders = $this->generateS3requestHeaders($sMethod, $sUrl, $sBucket, array('Content-Type: application/x-www-form-urlencoded'), ''); + // Transfert cURL. + $sRequestResult = $this->curlRequest($sUrl, $sMethod, null, $aHeaders); + if ($this->aLastCurlRequestInfo['http_code'] != 200) { + $this->writeToErrorLog("ERROR: ScanDir can't scan this prefix or this bucket"); + $this->writeToErrorLog($this->formatS3ErrorMessage($sRequestResult)); + return false; + } + else { + $oXMLContent= json_decode(json_encode(simplexml_load_string($sRequestResult)), true); + $oFiles = $this->awsObjectListXmlToTree($oXMLContent, $bWithFileInfos); + } + + return $oFiles; + } + + /** + * ScanDir in a bucket + * @param {object} $oXMLObject Result of the list object request AWS + * @param {boolean} $bWithFileInfos boolean to add fileInfo with filename + * @return Array associative array describing directory scanned + */ + function awsObjectListXmlToTree ($oXMLObject, $bWithFileInfos){ + + $aSave = array(); + + $sPrefix = (count($oXMLObject["Prefix"]) === 0) ? "" : $oXMLObject["Prefix"]; + + if(substr($sPrefix, -1) !== "/"){ + $sPrefix .= "/"; + } + + $oFiles = array( + "bucket" => $oXMLObject["Name"], + "sPath"=> $sPrefix, + "aContent" => array() + ); + + if($oXMLObject["KeyCount"] == 1){ + $sFinalKey = $oXMLObject["Contents"]["Key"]; + if($sPrefix !== "/"){ + $sFinalKey = str_replace($sPrefix, "", $sFinalKey); + } + $aPath = explode("/", $sFinalKey); + $sObjectName = $aPath[0]; + + $oFile = $sObjectName; + + if($bWithFileInfos){ + $oFile = array( + "name"=> $sObjectName, + "isDirectory"=> (count($aPath) > 1)? 1 : 0, + "size" => $oXMLObject["Contents"]["Size"], + "lastModification" => $oXMLObject["Contents"]["LastModified"], + "storageType" => $oXMLObject["Contents"]["StorageClass"] + ); + } + + array_push($oFiles["aContent"], $oFile); + array_push($aSave, $sObjectName); + }else{ + for($i = 0; $i < count($oXMLObject["Contents"]); $i++){ + $sFinalKey = $oXMLObject["Contents"][$i]["Key"]; + if($sPrefix !== "/"){ + $sFinalKey = str_replace($sPrefix, "", $sFinalKey); + } + $aPath = explode("/", $sFinalKey); + $sObjectName = $aPath[0]; + + $oFile = $sObjectName; + // check si existe déja + if(!in_array($sObjectName, $aSave) && $sObjectName !== ""){ + if($bWithFileInfos){ + $oFile = array( + "name"=> $sObjectName, + "isDirectory"=> (count($aPath) > 1)? 1 : 0, + "size" => $oXMLObject["Contents"][$i]["Size"], + "lastModification" => $oXMLObject["Contents"][$i]["LastModified"], + "storageType" => $oXMLObject["Contents"][$i]["StorageClass"] + ); + } + + array_push($oFiles["aContent"], $oFile); + array_push($aSave, $sObjectName); + } + } + } + return $oFiles; + } + + /** + * Delete a file. + * @param {string} $sBucket Name of the container for remove an objects. + * @param {string} $sKey Object's identifier to delete it. + * @return boolean true if removed false else + */ + function deleteFile($sBucket, $sKey){ + $bReturn = false; + //URL to send request + $sUrl = 'https://' . $sBucket . '.' . $this->sHost . "/" . $sKey; + $sMethod = 'DELETE'; + + // Génération des entêtes pour la requete. + $aHeaders = $this->generateS3requestHeaders($sMethod, $sUrl, $sBucket, array(''), ''); + + // Transfert cURL. + $sRequestResult = $this->curlRequest($sUrl, $sMethod, null, $aHeaders); + + if ($this->aLastCurlRequestInfo['http_code'] != 200) { + $this->writeToErrorLog("ERROR: it's impossible to delete this key in this bucket"); + $this->writeToErrorLog($this->formatS3ErrorMessage($sRequestResult)); + } else + $bReturn = true; + + return $bReturn; + } + + /** + * Convert an error message returned by s3 (xml to object). + * @param {string} $sXmlErrorMessage Error message returned by s3 (xml format). + * @return object S3 Error + */ + function getS3ErrorObject($sXmlErrorMessage) { + $oSimpleXmlElement = simplexml_load_string($sXmlErrorMessage); + if (is_object($oSimpleXmlElement)) { + $oErrorMessage = new stdClass(); + foreach ($oSimpleXmlElement as $sProperty => $oValue) { + $oErrorMessage->$sProperty = $oValue->__toString(); + } + return $oErrorMessage; + } + else + return false; + } + + /** + * Format an error message returned by s3. + * @param {string} $sXmlErrorMessage Error message returned by s3 (xml format). + * @return string Error message + */ + function formatS3ErrorMessage($sXmlErrorMessage) { + $oErrorMessage = $this->getS3ErrorObject($sXmlErrorMessage); + if ($oErrorMessage !== false) + return ($oErrorMessage->Code . ' : ' . $oErrorMessage->Message); + else + return $sXmlErrorMessage; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/treeview/LdapTree.php b/vas/rest/class/treeview/LdapTree.php new file mode 100755 index 0000000000000000000000000000000000000000..035579d9bc45d834c303bfe20c7e8d7d42d50f52 --- /dev/null +++ b/vas/rest/class/treeview/LdapTree.php @@ -0,0 +1,46 @@ +<?php +/* +require_once("../../properties.inc"); +require_once("vmlib/phpUtil.inc"); +require_once("vmlib/logUtil.inc"); +*/ +// a class to show OU LDAP based aciTree + +class LdapTree extends Tree { + private $oLdap = null; + public function __construct(Ldap $oLdap) { + $this->Ldap = $oLdap; + } + + public function branch($sParentId = null) { + $aBranch = array(); + $sLdapConn = $this->Ldap->connectLdap(); + if($sLdapConn){ + $aOUList = $this->Ldap->getOU($sLdapConn, $sParentId); + // R�cup�ration du nom de dossier + foreach ($aOUList as $sOU) { + if(substr($sOU, 0, 3)!="DC=") + { + $aOU = explode(",",$sOU); + $aBranch[$sOU] = "<a href=\"javascript: document.getElementById('stat_import_ad').style.display='none'; loadDirectoryUsers ('".$sOU."', document.getElementById('sLdap').value); \">".$aOU[0]."</a>"; + } + else + $aBranch[$sOU] = $sOU; + } + $this->Ldap->closeLdap($sLdapConn); + return $aBranch; + } + } + + /* + * $itemId will be the path to the file/folder. + */ + public function itemProps($itemId) { + return array_merge(parent::itemProps($itemId), array( + 'isFolder' => true, + 'icon' => 'folder', + 'random' => mt_rand(0, 99) // just a random property + )); + return parent::itemProps($itemId); + } +} \ No newline at end of file diff --git a/vas/rest/class/treeview/Tree.php b/vas/rest/class/treeview/Tree.php new file mode 100755 index 0000000000000000000000000000000000000000..6e15c25dae1f1a9528cbccef48b2e4914e4ed5ff --- /dev/null +++ b/vas/rest/class/treeview/Tree.php @@ -0,0 +1,60 @@ +<?php + +// the base class to return data in JSON for aciTree +// as you can see, keep it simple it's the best way to do things :D +// note: you'll need PHP >= 5.2 to run this + +abstract class Tree { + + /** + * Get tree branch as KEY => ITEM. + * @param string $parentId - if NULL then it's the root + * @return array + */ + abstract public function branch($parentId = null); + + /** + * Get item properties (all default properties must be defined). + * @param string $itemId + * @return array + */ + public function itemProps($itemId) { + return array( + 'isFolder' => null, // NULL = maybe a folder, TRUE - is a folder, FALSE - it's not a folder + 'open' => false, // should open folder? + 'icon' => null // icon CSS class name (if any) can be ARRAY [name, background X, background Y] (in this order) + ); + } + + private function _json($parentId, Array &$json, $children) { + $branch = $this->branch($parentId); + foreach ($branch as $id => $item) { + $props = $this->itemProps($id); + $items = array(); + if ($children) { + $this->_json($id, $items, $children); + if (count($items) == 0) { + $props['isFolder'] = false; + } + } + $json[] = array( + 'id' => $id, + 'item' => $item, + 'props' => $props, + 'items' => $items + ); + } + } + + /** + * Output tree JSON (array of id/item/props/items with props.isFolder depending if it's a TREE folder or not). + * @param string $parentId + * @param bool $children - include children? + */ + public function json($parentId, $children = false) { + $json = array(); + $this->_json($parentId, $json, $children); + return $json; + } + +} diff --git a/vas/rest/class/treeview/aciTree.php b/vas/rest/class/treeview/aciTree.php new file mode 100755 index 0000000000000000000000000000000000000000..1c45eddce99ac6d48f4a9d1c0f5b310e1d705ace --- /dev/null +++ b/vas/rest/class/treeview/aciTree.php @@ -0,0 +1,56 @@ +<?php +require_once("../../properties.inc"); +//require_once("vmlib/phpUtil.inc"); +//require_once("vmlib/logUtil.inc"); + +// get the tree JSON data for the file system listing +$path = dirname(__FILE__); + +require_once("Tree.php"); +require_once("FsTree.php"); +require_once("LdapTree.php"); +require_once("../Ldap.class.inc"); + +// we limit the access to "$path/tree" +if($_GET[sLdap]!=""){ + $fsTree = new LdapTree(new Ldap($_GET['sLdap'])); +} +else + $fsTree = new FsTree(new Fs($_GET['sLogFile'])); + +// what branch was requested? +$branch = isset($_GET['branch']) ? $_GET['branch'] : null; + +// special case for 1k test from the demo (skip the 'sleep' thing and return faster) +if ((strpos($branch, 'a_new_File_ID') !== false) || (strpos($branch, 'a_new_Folder_ID') !== false)) { + // burn your CPU not the server with the 1k entries ... ;)) + if (preg_match('@[0-9]+$@', $branch, $match) == 1) { + if ((int) $match[0] > 20) { + die('[]'); + } + } + sleep(1); + die('[]'); +} + +if (strpos($branch, '..') !== false) { + // path should not have a [..] inside ;-) + $branch = 'undefined'; +} + +// a small delay so we can see the loading animation +// (comment it for faster return) +// sleep(1); + +// no cache so we can see the loading animation :) +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +// get the branch (1 level) +// $fsTree->json($branch); + +// this will get the entire tree (comment above and uncomment this) +$fsTree->json($branch, true); diff --git a/vas/rest/class/vitis_lib/Connection.class.inc b/vas/rest/class/vitis_lib/Connection.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..fa801dc5b0a03ce775b11fdb3f91faa739b9791e --- /dev/null +++ b/vas/rest/class/vitis_lib/Connection.class.inc @@ -0,0 +1,292 @@ +<?php + +require_once(__DIR__ . "/../vmlib/Vm.class.inc"); +require_once(__DIR__ . "/../vmlib/dbUtil.inc"); +require_once(__DIR__ . "/../vmlib/logUtil.inc"); +require_once(__DIR__ . "/../vmlib/error.inc"); +require_once(__DIR__ . "/../vmlib/cryptUtil.inc"); +require_once(__DIR__ . "/../vitis_lib/VitisError.class.inc"); + +/** + * \file Connection.class.inc + * \class Connection + * + * \author Yoann Perollet <yoann.perollet@veremes.com>. + * + * \brief This file contains the class Connection + * + * This class defines methods to connect to the database, get groups and privilges of the connected user. + * + * + */ +class Connection { + + /** + * bd object (the connection itself) + */ + public $oBd; + + /** + * parameters sent to the class + */ + public $aValues; + + /** + * error object if the connection encounters an error + */ + public $oError; + + /** + * properties + */ + public $aProperties; + + /** + * list of the user groups + */ + public $sesGroup; + + /** + * list of the user privileges + */ + public $aPrivileges = Array(); + public $sFolderLib = "vitis_lib"; + + /** + * user date settings + */ + public $sFormatDate; + public $sTimeZone; + + /** + * + * @param type $aValues paramters to the object + * @param type $aProperties properties + */ + function __construct($aValues, $aProperties) { + $this->aProperties = $aProperties; + $this->aValues = $aValues; + session_id($aValues['token']); + if (session_status() == PHP_SESSION_NONE) + session_start(); + $bIsconnected = true; + // Variable de session vide et token privée : erreur. + if (empty($_SESSION) && $aValues['token'] != $this->aProperties['public_token']) { + $this->oError = new VitisError(16, 'invalid token'); + $bIsconnected = false; + } + else if ($aValues['token'] == $this->aProperties['public_token']) { + $_SESSION["ses_Login"] = $this->aProperties['public_login']; + $ciphertext = des($this->aProperties['public_login'], $this->aProperties['public_password'], 1, 0); + $_SESSION["ses_Password"] = stringToHex($ciphertext); + if (empty($this->aValues['duration'])) + $this->aValues['duration'] = $this->aProperties['cookie_lifetime']; + $_SESSION["ses_Date"] = date('Y-m-d H:i:s', time() + ($this->aValues['duration'] * 60)); + } + if ($bIsconnected) { + $this->connect(); + } + + if (empty($this->oError)) { + // Paramètres de l'utilisateur (fuseau horaire, format des dates). + if (!empty($_SESSION['ses_user_id'])) { + $this->getUserDateInformations(); + } + } + } + + function connect() { + $bIsValidDate = false; + //verify validity date + if (isset($_SESSION['ses_Date'])) { + $now = date('Y-m-d H:i:s'); + $now = new DateTime($now); + $now = $now->format('YmdHis'); + $next = $_SESSION['ses_Date']; + $next = new DateTime($next); + $next = $next->format('YmdHis'); + if ($now < $next) + $bIsValidDate = true; + else if ($this->aValues['token'] == $this->aProperties['public_token']) { + // Régénère un token public qui a expiré. + if (empty($this->aValues['duration'])) + $this->aValues['duration'] = 10; + $_SESSION["ses_Date"] = date('Y-m-d H:i:s', time() + ($this->aValues['duration'] * 60)); + $this->aValues['validity_date'] = $_SESSION["ses_Date"]; + $bIsValidDate = true; + } + } else { + $this->oError = new VitisError(15, "Token validity outpassed"); + } + //if valid date + if ($bIsValidDate == true) { + //conenction to the database with the token + if (isset($properties["language"])) + $lang = $properties["language"]; + else + $lang = null; + loadLang('vmlib', $lang, 'vmlib/'); + if (!empty($this->aValues['module']) && isset($this->aProperties['database_' . $this->aValues['module']])) { + $sDataBase = $this->aProperties['database_' . $this->aValues['module']]; + } else { + $sDataBase = $this->aProperties['database']; + } + if (!empty($this->aValues['module']) && isset($this->aProperties['server_' . $this->aValues['module']])) { + $sServer = $this->aProperties['server_' . $this->aValues['module']]; + } else { + $sServer = $this->aProperties['server']; + } + if (!empty($this->aValues['module']) && isset($this->aProperties['port_' . $this->aValues['module']])) { + $iPort = $this->aProperties['port_' . $this->aValues['module']]; + } else { + $iPort = $this->aProperties['port']; + } + if (!empty($this->aValues['module']) && isset($this->aProperties['sgbd_' . $this->aValues['module']])) { + $sSgbd = $this->aProperties['sgbd_' . $this->aValues['module']]; + } else { + $sSgbd = $this->aProperties['sgbd']; + } + if (isset($this->aValues['sEncoding'])) + $sEncoding = $this->aValues['sEncoding']; + else + $sEncoding = null; + $this->oBd = new Vm($_SESSION["ses_Login"], trim(des(rtrim(utf8_decode($_SESSION["ses_Login"])), hexToString(rtrim($_SESSION["ses_Password"])), 0, 0, null)), $sDataBase, $sServer, $iPort, $sSgbd, $sEncoding); + if ($this->oBd->erreurRencontree) { + writeToErrorLog(ERROR_CONNECTION_PROBLEM); + writeToErrorLog($this->oBd->getBDMessage()); + } + + if ($this->oBd->erreurRencontree) { + $this->oError = new VitisError(1, $this->oBd->sMessage); + } else { + $this->aValues['login'] = $_SESSION["ses_Login"]; + $this->aValues['validity_date'] = $_SESSION["ses_Date"]; + //get the groups of the user + if (isset($this->aValues['getGroup']) && !$this->aValues['getGroup'] == false) { + $this->sesGroup = getUserGroups($_SESSION["ses_Login"], $this->oBd, $_SESSION["ses_Password"], $this->aProperties["mixed_rights_management"], $this->aProperties["schema_framework"]); + } + + // Get the privileges of the user + $this->getUserPrivileges(); + // Update the user last connection + $this->updateLastConnection(); + } + } else { + $this->oError = new VitisError(15, "Token validity outpassed"); + } + } + + /** + * function wich get user privileges + */ + function getUserPrivileges() { + $sSql = "SELECT * FROM pg_user s LEFT OUTER JOIN pg_group g on (s.usesysid = any(g.grolist) ) where usename = '" . $_SESSION["ses_Login"] . "'"; + $oResult = $this->oBd->execute($sSql); + if (empty($this->oBd->enErreur) && $this->oBd->nombreLigne($oResult) > 0) { + while ($aPrivilege = $this->oBd->ligneSuivante($oResult)) { + array_push($this->aPrivileges, $aPrivilege['groname']); + } + } + } + + /** + * Get the rights of a user on a given table + * @param string $sSchema + * @param string $sTable + * @return array array of rights ex: ["SELECT", "TRUNCATE", "UPDATE"] + */ + function getTableRights($sSchema, $sTable) { + + if (!isset($sSchema) || empty($sSchema)) { + return []; + } + if (!isset($sTable) || empty($sTable)) { + return []; + } + // Version 1 + // $aProperties = $this->aProperties; + // $aPrivileges = $this->aPrivileges; + // + // // Ajoute PUBLIC dans les privilèges + // array_push($aPrivileges, 'PUBLIC'); + // + // // connexion avec u_vitis + // $oSchedulerBd = new BD('u_vitis', '', $aProperties["database"], $aProperties["server"], $aProperties["port"], $aProperties["sgbd"], $aProperties["page_encoding"]); + // + // $sSql = "SELECT * FROM information_schema.role_table_grants WHERE table_schema = '" . $sSchema . "' AND table_name = '" . $sTable . "'"; + // $oResult = $oSchedulerBd->execute($sSql); + // + // $aRights = array(); + // + // // Récupère les droits en fonction des privilèges + // if (!$oSchedulerBd->enErreur()) { + // if ($oSchedulerBd->nombreLigne($oResult) > 0) { + // while ($aLigne = $oSchedulerBd->ligneSuivante($oResult)) { + // if (in_array($aLigne['grantee'], $aPrivileges)) { + // if (!in_array($aLigne['privilege_type'], $aRights)) { + // array_push($aRights, $aLigne['privilege_type']); + // } + // } + // } + // } + // } + // Version 2 (Armand 02/09/2016) + $aSqlParams = array( + 'sSchema' => array('value' => $sSchema, 'type' => 'column_name'), + 'sTable' => array('value' => $sTable, 'type' => 'column_name') + ); + $sSql = "SELECT + has_table_privilege('\"[sSchema]\".\"[sTable]\"','insert') AS \"INSERT\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','select') AS \"SELECT\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','update') AS \"UPDATE\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','delete') AS \"DELETE\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','truncate') AS \"TRUNCATE\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','references') AS \"REFERENCES\", + has_table_privilege('\"[sSchema]\".\"[sTable]\"','trigger') AS \"TRIGGER\""; + + $oResult = $this->oBd->executeWithParams($sSql, $aSqlParams); + + $aRights = array(); + + if (!$this->oBd->enErreur()) { + if ($this->oBd->nombreLigne($oResult) > 0) { + while ($aLigne = $this->oBd->ligneSuivante($oResult)) { + foreach ($aLigne as $key => $value) { + if ($value === true) { + array_push($aRights, $key); + } + } + } + } + } + return $aRights; + } + + /** + * Update the last connexion column + */ + function updateLastConnection() { + $sSql = "update [sSchemaFramework].v_user set last_connection = [date] where login = [login]"; + $aParams = array(); + $aParams['sSchemaFramework'] = array('value' => $this->aProperties['schema_framework'], 'type' => 'schema_name'); + $aParams['login'] = array('value' => $_SESSION["ses_Login"], 'type' => 'string'); + $aParams['date'] = array('value' => gmdate('Y-m-d H:i:s'), 'type' => 'string'); + $oPDOresult = $this->oBd->executeWithParams($sSql, $aParams, false); + } + + /** + * get user date parameters (time zone, date format) + */ + function getUserDateInformations() { + $sSql = "SELECT timezone_id, formatdate_id FROM [sSchemaFramework].v_user WHERE user_id = [user_id]"; + $aParams = array(); + $aParams['sSchemaFramework'] = array('value' => $this->aProperties['schema_framework'], 'type' => 'schema_name'); + $aParams['user_id'] = array('value' => $_SESSION['ses_user_id'], 'type' => 'string'); + $oPDOresult = $this->oBd->executeWithParams($sSql, $aParams); + if (empty($this->oBd->enErreur) && $this->oBd->nombreLigne($oPDOresult) > 0) { + $aDateParameters = $this->oBd->ligneSuivante($oPDOresult); + $this->sFormatDate = $aDateParameters['formatdate_id']; + $this->sTimeZone = $aDateParameters['timezone_id']; + } + } +} diff --git a/vas/rest/class/vitis_lib/DbClass.class.inc b/vas/rest/class/vitis_lib/DbClass.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..7c253c8b0ad9e8403652693e9cfa83d42fafd833 --- /dev/null +++ b/vas/rest/class/vitis_lib/DbClass.class.inc @@ -0,0 +1,158 @@ +<?php + +require_once (__DIR__ . "/XmlAbstract.class.inc"); +require_once(__DIR__ . "/../vmlib/Vm.class.inc"); +require_once(__DIR__ . "/../vmlib/dbUtil.inc"); +require_once(__DIR__ . "/../vmlib/logUtil.inc"); +require_once(__DIR__ . "/../vmlib/error.inc"); + +class DbClass extends XmlAbstract { + + //Champ clé de la table + var $sPkField; + //Valeur du champ clé de la table + var $iPkValue; + // Tableau de Properties + var $aProperties; + var $sTable; + //Chemin du fichier de ressources contenant les requêtes SQL + var $sRessourcesFile; + //Séquence utilisé pour l'obtention d'un nouvel identifiant + var $sSequence = "s_gtf.seq_order"; + //Variable stockant les messages d'erreur des requêtes + var $sMessage; + // Connexion à la base de données + var $oBd; + // est vrai si l'objet correspondant n'existe pas dans la base ou en cas d'erreur d'initialisation + var $bEnErreur; + // code d'erreur. different de 0 si bEnErreur=True + var $iErrorCode = 0; + + function setFields($aValues) { + foreach ($aValues as $sCle => $sValeur) { + $this->aFields[$sCle] = $sValeur; + } + } + + /* + * Méthode de classe : Insert + * Cette méthode permet d'insérer un nouvel enregistrement dans la table du shéma passé en pararmètre + */ + + function insert() { + $iId = $this->oBd->insert($this->aProperties['schema_gtf'], $this->sTable, $this->aFields, $this->sSequence, $this->sPkField, $bGetSql = false); + if ($iId != "") { + writeToDebugLog("La demande " . $iId . " a bien été insérée dans la base."); + $this->sMessage = "La demande " . $iId . " a bien été insérée dans la base."; + return $iId; + } else { + writeToErrorLog(ERROR_0002 . $this->oBd->getBDMessage()); + $this->sMessage = "La création de la demande a échouée."; + return -1; + } + } + + /* + * Méthode de classe : Update + * Cette méthode permet de mettre à jour un enregistrement dans la table du shéma passé en pararmètre + */ + + function update() { + if (!$this->oBd->update($this->aProperties['schema_gtf'], $this->sTable, $this->aFields, $this->sPkField, $this->iPkValue, $sIdType = "")) { + writeToDebugLog("La demande " . $this->iPkValue . " a bien été mise à jour dans la base."); + $this->sMessage = "La demande " . $this->iPkValue . " a bien été mise à jour dans la base."; + //Rajouté par Laurent + return $this->aFields["order_id"]; + } else { + writeToErrorLog(str_replace('[order_id]', $this->iPkValue, ERROR_0003) . $this->oBd->getBDMessage()); + $this->sMessage = "La mise à jour de la demande " . $this->iPkValue . " a échouée. -- " . $this->oBd->getBDMessage(); + //Rajouté par Laurent + return -1; + } + return $this->sMessage; + } + + /* + * Méthode de classe : Delete + * Cette méthode permet de supprimer un enregistrement dans la table du shéma passé en pararmètre + */ + + function delete() { + if ($iDemandeId == "") + $iDemandeId = $this->iPkValue; + + if (!$this->oBd->delete($this->aProperties['schema_gtf'], $this->sTable, $this->sPkField, $iDemandeId, $sIdType = "")) { + writeToDebugLog("La demande " . $iDemandeId . " a bien été supprimée de la base."); + $this->sMessage = "La demande " . $iDemandeId . " a bien été supprimée de la base."; + return $iDemandeId; + } else { + writeToErrorLog(str_replace('[order_id]', $iDemandeId, ERROR_0004) . $this->oBd->getBDMessage()); + $this->sMessage = "La demande " . $iDemandeId . " n'a pas pu être supprimée de la base."; + return -1; + } + } + + function setPkValue($iId) { + $this->iPkValue = $iId; + } + + /* + * Méthode de classe : getSourceEncoding + * Cette méthode permet de retourner l'encodage de la base de données + */ + + function getSourceEncoding() { + return $this->oBd->getSourceEncoding(); + } + + function isPostGISInstalled(){ + +// // Version 1 +// $sSql = "SELECT PostGIS_version()"; +// +// $oResult = $this->oConnection->oBd->execute($sSql); +// if (!$this->oConnection->oBd->enErreur() && $this->oConnection->oBd->nombreLigne($oResult) > 0) { +// return true; +// }else{ +// return false; +// } + // Version 2 + $isPostGISInstalled = false; + $sSql = "select name from pg_available_extensions where installed_version != ''"; + $oResult = $this->oConnection->oBd->execute($sSql); + if (!$this->oConnection->oBd->enErreur() && $this->oConnection->oBd->nombreLigne($oResult) > 0) { + while ($aLigne = $this->oConnection->oBd->ligneSuivante($oResult)) { + if($aLigne['name'] === 'postgis'){ + $isPostGISInstalled = true; + } + } + } + return $isPostGISInstalled; + } + + /** + * Return the geom columns infos from a table + * @param string $sSchema + * @param string $sTable + * @return array + */ + function getTableGeomColumnsInfos($sSchema, $sTable) { + + if(!$this->isPostGISInstalled()){ + return array(); + } + + $aGeomColumnsInfos = array(); + $sSql = "SELECT f_geometry_column, coord_dimension, srid, type from geometry_columns WHERE f_table_schema='" . $sSchema . "' AND f_table_name='" . $sTable . "'"; + + $oResult = $this->oConnection->oBd->execute($sSql); + if (!$this->oConnection->oBd->enErreur() && $this->oConnection->oBd->nombreLigne($oResult) > 0) { + while ($aObject = $this->oConnection->oBd->ligneSuivante($oResult)) { + array_push($aGeomColumnsInfos, $aObject); + } + } + return $aGeomColumnsInfos; + } +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vitis_lib/Form.class.inc b/vas/rest/class/vitis_lib/Form.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..d971183d87b60cc3439f76e569913c12c694c28c --- /dev/null +++ b/vas/rest/class/vitis_lib/Form.class.inc @@ -0,0 +1,151 @@ +<?php + +/** + * \class Form + * \brief Form Class + * + * Class about form operations + * + * \author Armand Bahi <armand.bahi@veremes.com> + */ +class Form { + + /** + * construct + * @param type $properties properties + * @param type $oConnection connection object + */ + function __construct($properties, $oConnection) { + $this->aProperties = $properties; + $this->oConnection = $oConnection; + } + + /** + * Get the table columns description array + * @param string $sSchema + * @param string $sTable + * @return array + */ + function getTableColumns($sSchema, $sTable) { + + // Effectue une requête pour avoir les colonnes de la table + $sSql = "SELECT column_name, is_nullable, data_type, is_updatable "; + $sSql .= "FROM information_schema.columns "; + $sSql .= "WHERE table_schema = '" . $sSchema . "' AND table_name = '" . $sTable . "'"; + + $aColumns = array(); + + // Crée le formulaire + $oResult = $this->oConnection->oBd->execute($sSql); + if ($this->oConnection->oBd->enErreur()) { + $aXmlRacineAttribute['status'] = 0; + $oError = new VitisError(2, $this->oConnection->oBd->getBDMessage()); + } else { + if (!$this->oConnection->oBd->enErreur()) { + while ($aLigne = $this->oConnection->oBd->ligneSuivante($oResult)) { + array_push($aColumns, $aLigne); + } + } + } + return $aColumns; + } + + /** + * Generate the form rows by the table columns description array + * @param type $aColumns + * @param type $aUnusedColumnNames names of the columns witch you dont want to use + * @param type $aUnupdatableColumnNames names of the columns witch you dont want to bu updatable + * @return array + */ + function generateRowsByTableColumns($aColumns, $aUnusedColumnNames = array(), $aUnupdatableColumnNames = array(), $aLabel = array()) { + + $aRows = array(); + $aTypes = array(); + $aTypes["character varying"] = "text"; + $aTypes["integer"] = "integer"; + + foreach ($aColumns as $aLigne) { + + // Re-crée la ligne + $aField = array(); + $aField['fields'] = array(); + $aField['fields'][0] = array(); + + if (in_array($aLigne['column_name'], $aUnupdatableColumnNames)) { + + $aField['fields'][0]['type'] = "label"; + } else if (in_array($aLigne['column_name'], $aUnusedColumnNames)) { + + continue; + } else if (isset($aTypes[$aLigne['data_type']])) { + + $aField['fields'][0]['type'] = $aTypes[$aLigne['data_type']]; + } else if ($aLigne['data_type'] === "tinyint" || $aLigne['data_type'] === "bigint" || $aLigne['data_type'] === "smallint" || $aLigne['data_type'] === "numeric") { + + $aField['fields'][0]['type'] = "text"; + $aField['fields'][0]['pattern'] = "[-+]?(\d*[.])?\d+"; + } else if ($aLigne['data_type'] === "boolean") { + + $aField['fields'][0]['type'] = "radio"; + $aField['fields'][0]['options'] = array(); + $aField['fields'][0]['options']['choices'] = array(); + $aField['fields'][0]['options']['choices'][0]['label'] = "oui"; + $aField['fields'][0]['options']['choices'][0]['value'] = true; + $aField['fields'][0]['options']['choices'][1]['label'] = "non"; + $aField['fields'][0]['options']['choices'][1]['value'] = false; + } else { + + $aField['fields'][0]['type'] = "text"; + } + + $aField['fields'][0]['name'] = $aLigne['column_name']; + if (array_key_exists($aLigne['column_name'], $aLabel)) { + $aField['fields'][0]['label'] = $aLabel[$aLigne['column_name']]; + } else { + $aField['fields'][0]['label'] = $aLigne['column_name']; + } + + $aField['fields'][0]['disabled'] = !$aLigne['is_updatable']; + $aField['fields'][0]['required'] = !$aLigne['is_nullable']; + $aField['fields'][0]['nb_cols'] = 12; + + array_push($aRows, $aField); + } + + return $aRows; + } + + /** + * Generate the Form + * @param string $aRows + * @param string $sFormName + * @param string $sFormTitle + * @return array + */ + function generateFormByRows($aRows, $sFormTitle = "Generated Form", $sFormName = "generated") { + + // Crée les modes diplay/update/insert + $aForm = array(); + $aForm['display'] = array(); + $aForm['display']['name'] = $sFormName . '-form'; + $aForm['display']['title'] = $sFormTitle; + $aForm['display']['input_size'] = "xxs"; + $aForm['display']['nb_cols'] = 12; + $aForm['display']['javascript'] = false; + $aForm['display']['rows'] = $aRows; + $aForm['search'] = $aForm['display']; + $aForm['search']['rows'] = []; + $aForm['insert'] = $aForm['display']; + $aForm['update'] = $aForm['display']; + + // Met les champs du mode insert en mode label + for ($index = 0; $index < count($aForm['display']['rows']); $index++) { + $aForm['display']['rows'][$index]['fields'][0]['type'] = 'label'; + } + + return $aForm; + } + +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vitis_lib/VitisError.class.inc b/vas/rest/class/vitis_lib/VitisError.class.inc new file mode 100644 index 0000000000000000000000000000000000000000..1c52cfaa95a3a0479a910281e35cde8f25376703 --- /dev/null +++ b/vas/rest/class/vitis_lib/VitisError.class.inc @@ -0,0 +1,73 @@ +<?php + +require_once(__DIR__."/DbClass.class.inc"); + +class VitisError extends DbClass { + + function __construct($iErrorId, $sErrorMessage="", $sMessage = ''){ + $this->aFields['errorCode']=$iErrorId; + switch ($iErrorId){ + case 1 : + $this->aFields['errorType']="Low-level error on database"; + break; + case 2 : + $this->aFields['errorType']="Missing parameter(s)"; + break; + case 3 : + $this->aFields['errorType']="Order not found"; + break; + case 4 : + $this->aFields['errorType']="Empty parameter(s)"; + break; + case 5 : + $this->aFields['errorType']="Empty service"; + break; + case 6 : + $this->aFields['errorType']="Unknown operation"; + break; + case 7 : + $this->aFields['errorType']="Invalid output format"; + break; + case 8 : + $this->aFields['errorType']="Error upload"; + break; + case 9 : + $this->aFields['errorType']="Error creating folder"; + break; + case 10 : + $this->aFields['errorType']="The application requested is not responding. Use UTF-8 to generate an XML result."; + break; + case 11 : + $this->aFields['errorType']="Connection to the database forbidden"; + break; + case 12 : + $this->aFields['errorType']="Rights problem"; + break; + case 13 : + $this->aFields['errorType']="Workspace not found"; + break; + case 14 : + $this->aFields['errorType']="Missing operation"; + break; + case 15 : + $this->aFields['errorType']="Expired token"; + break; + case 16 : + $this->aFields['errorType']="Invalid token"; + break; + case 18 : + $this->aFields['errorType']="Missing privileges"; + case 17 : + $this->aFields['errorType']="The request returned an error"; + break; + case 19 : + $this->aFields['errorType']="The database is unreachable"; + break; + } + $this->aFields['errorMessage']=$sErrorMessage; //Message renvoyé par la base de donnée + // Message d'erreur additionnel. + if (!empty($sMessage)) + $this->aFields['message'] = $sMessage; + } +} +?> \ No newline at end of file diff --git a/vas/rest/class/vitis_lib/XmlAbstract.class.inc b/vas/rest/class/vitis_lib/XmlAbstract.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..eec22c875b2c218ff1a54cd5acd64417eae024dc --- /dev/null +++ b/vas/rest/class/vitis_lib/XmlAbstract.class.inc @@ -0,0 +1,256 @@ +<?php + +/** + * \file XmlAbstract.class.inc + * \brief XmlAbstract.class.inc \n \n Ce fichier contient la classe php XmlAbstract. + * + * Cette classe est une classe abstraite qui peut être appelé par les autres classes par héritage afin de construire un fichier XML. + * + * \author Nicolas Chazeau + */ + +/** + * \class XmlAbstract + * \brief XmlAbstract Class \n \n XmlAbstract est une classe PHP. + * + * Cette classe permet de retourner un objet de sélection dans un fichier XML. + * + * \author Olivier Gayte <olivier.gayte@veremes.com> + * \author Nicolas Chazeau + */ +class XmlAbstract { + /* + * Tableau associatif contenant les attributs de l'objet. + */ + + var $aFields = array(); + /* + * Tableau d'objets + */ + var $aObjects = array(); + + /** + * Cette méthode permet d'afficher l'objet de sélection sous la forme d'un tableau HTML. + * \return Retourne plusieurs chaînes de caractères ou une chaine de caractères vide si le tableau est vide. + */ + function asTable() { + if ($this->isEmpty()) { + $sResult = ""; + } else { + $sResult = "<table border=3 rules=all>\n"; + foreach ($this->aExportFields as $sAttribut => $sValue) { + $sResult .= "<td>" . $sAttribut . "</td>\n"; + } + $sResult .= "\t<tr>\n"; + foreach ($this->aExportFields as $sAttribut => $sValue) { + $sResult .= "<td>" . $sValue . "</td>\n"; + } + $sResult .= "</table>\n"; + } + return $sResult; + } + + /** + * Cette méthode permet de déterminer si le tableau $this->aFields est vide ou non. + * \return Retourne false si $this->aFields est non vide. + */ + function isEmpty() { + return empty($this->aFields); + } + + /** + * Cette méthode permet de créer un tableau identique au tableau $this->aFields. + * \return Retourne un tableau. + */ + function getExportFields() { + return $this->aFields; + } + + /** + * Cette méthode permet de générer un document XML sous la forme d'une chaîne de caractères encodé en UTF-8 + * \param $sXSLUrl Nom du fichier de style XSL utilisé. + * \param $sXmlRacine Nom de l'élément racine du fichier XML. + * \param $sEncodageXML Encodage. UTF-8 par défaut. + * \param $sSourceEncoding Encodage de la base de données : ISO-8859-1 par défaut. + * \return Retourne un objet DomDocument. + */ + function asXML($sXSLUrl, $sXmlRacine, $sEncodageXML = 'UTF-8', $bAttributAsElement = False, $aXmlRacineAttribute = Array(), $sSourceEncoding = "ISO-8859-1") { + $oDomDocument = new DOMDocument('1.0', $sEncodageXML); + if (!Empty($sXSLUrl)) { + $oDomDocument->appendChild($oDomDocument->createProcessingInstruction('xml-stylesheet', 'href="' . $sXSLUrl . '" type="text/xsl"')); + } + $oObject = $oDomDocument->appendChild(new DOMElement($sXmlRacine)); + foreach ($aXmlRacineAttribute as $sXmlAttribute => $sValue) { + $oObject->setAttribute($sXmlAttribute, $this->sourceEncoding_targetEncoding($sSourceEncoding, $sEncodageXML, $sValue)); + } + $oObject->appendChild($this->asDOMElement($oDomDocument, $bAttributAsElement, $sSourceEncoding, $sEncodageXML)); + return $oDomDocument->saveXML(); + } + + /** + * Cette méthode permet de générer un document JSON sous la forme d'une chaîne de caractères encodé en UTF-8 + * \param $sXSLUrl Nom du fichier de style XSL utilisé. + * \param $sXmlRacine Nom de l'élément racine du fichier XML. + * \param $sEncodageXML Encodage. UTF-8 par défaut. + * \param $sSourceEncoding Encodage de la base de données : ISO-8859-1 par défaut. + * \return Retourne un objet DomDocument. + */ + function asJSON($sXSLUrl, $sXmlRacine, $sEncodageXML = 'UTF-8', $bAttributAsElement = False, $aXmlRacineAttribute = Array(), $sSourceEncoding = "ISO-8859-1",$sEncodageJSONXML) { + $oObject = $this->getObjects($this, $sEncodageJSONXML); + foreach ($aXmlRacineAttribute as $sXmlAttribute => $sValue) { + $oObject->$sXmlAttribute = $sValue; + } + $data = json_encode($oObject); + return ($data); + } + + function getJSON() { + $aObjClass = array(); + foreach ($aObjClass->aObjects as $oObj) { + if (get_class($oObj) == $sClasse) { + array_push($aObjClass, $oObj); + } + } + return $aObjClass; + } + + function asHTML($aExportFields) { + //Base case: an empty array produces no list + if (empty($aExportFields)) + return ''; + + //Recursive Step: make a list with child lists + $output = '<ul>'; + if (is_array($aExportFields) == false) { + $output .= '<li>' . $aExportFields . '</li>'; + } else { + foreach ($aExportFields as $key => $subArray) { + $output .= '<li>' . $key . $this->asHTML($subArray) . '</li>'; + } + } + + $output .= '</ul>'; + + return $output; + } + + /** + * Cette méthode permet de générer un document XML ou JSON sous la forme d'une chaîne de caractères encodé en UTF-8 + * \param $sXSLUrl Nom du fichier de style XSL utilisé. + * \param $sXmlRacine Nom de l'élément racine du fichier XML. + * \param $sEncodageXML Encodage. UTF-8 par défaut. + * \param $sSourceEncoding Encodage de la base de données : ISO-8859-1 par défaut. + * \param $sEncodageJSONXML Encodage XML par défaut, JSON sur demande + * \return Retourne un objet DomDocument. + */ + function asDocument($sXSLUrl, $sXmlRacine, $sEncodageXML = 'UTF-8', $bAttributAsElement = False, $aXmlRacineAttribute = Array(), $sSourceEncoding = "UTF-8", $sEncodageJSONXML = "xml") { + if (strpos($sEncodageJSONXML, "xml") != false) + return $this->asXML($sXSLUrl, $sXmlRacine, $sEncodageXML, $bAttributAsElement, $aXmlRacineAttribute, $sSourceEncoding); + else if (strpos($sEncodageJSONXML, "json") != false) + return $this->asJSON($sXSLUrl, $sXmlRacine, $sEncodageXML, $bAttributAsElement, $aXmlRacineAttribute, $sSourceEncoding, $sEncodageJSONXML); + else if (strpos($sEncodageJSONXML, "html") != false) { + $aExportFields = $this->getExportFields(); + return $this->asHTML($aExportFields); + } + } + + /** + * Cette méthode permet de générer un document XML sous la forme d'un fichier téléchargeable. + * \param $sXSLUrl Nom du Fichier de style XSL utilisé. + * \param $sFileName Nom du fichier XML à générer. + * \param $sXmlRacine Nom de l'élément racine du fichier XML. + * \param $sEncodageXML Encodage. UTF-8 par défaut. + * \param $sSourceEncoding Encodage de la base de données : ISO-8859-1 par défaut. + */ + function asXMLFile($sXSLUrl, $sFileName, $sXmlRacine = "Mj", $sEncodageXML = 'UTF-8', $sSourceEncoding = "ISO-8859-1") { + $sXML = $this->asXML($sXSLUrl, $sXmlRacine, $sEncodageXML, False, Array(), $sSourceEncoding); + return file_put_contents($sFileName, $sXML); + } + + /** + * Cette méthode permet de créer un élément DomElement. + * \param $oDomDocument : DOMDocument pere + * \param $sSourceEncoding Encodage de la base de données : ISO-8859-1 par défaut. + * \param $sEncodageXML Encodage. UTF-8 par défaut. + * \return Retourne un objet DomElement. + */ + function asDOMElement($oDomDocument, $bAttributAsElement = False, $sSourceEncoding = "ISO-8859-1", $sEncodageXML = 'UTF-8') { + $oDomElement = $oDomDocument->appendChild(new DOMElement(get_class($this))); + $aExportFields = $this->getExportFields(); + //si aExportFields n'est pas vide + if ($aExportFields != "" && count($aExportFields) > 0) { + foreach ($aExportFields as $sAttribut => $sValue) { + if (is_array($sValue)) { + + } else { + if ($bAttributAsElement) { + //nouveau fils , attribut : $sAttribut, valeur : sValue UTF-8 + $oDomElement->appendChild(new DOMElement($sAttribut, $this->sourceEncoding_targetEncoding($sSourceEncoding, $sEncodageXML, $sValue))); + } else { + //nouvel attribut , attribut : $sAttribut, valeur : sValue UTF-8 + $oDomElement->setAttribute($sAttribut, $this->sourceEncoding_targetEncoding($sSourceEncoding, $sEncodageXML, $sValue)); + } + } + } + //si le Fields est vide + } elseif (!$this->isEmpty()) { + foreach ($aExportFields as $sAttribut => $sValue) { + //nouvel attribut , attribut : $sAttribut, valeur : sValue UTF-8 + $oDomElement->setAttribute($sAttribut, $this->sourceEncoding_targetEncoding($sSourceEncoding, $sEncodageXML, $sValue)); + } + } + foreach ($this->aObjects as $s => $oMj) { + if (get_class($oMj) != "") { + $oDomElement->appendChild($oMj->asDOMElement($oDomDocument, $bAttributAsElement, $sSourceEncoding, $sEncodageXML)); + } + } + return $oDomElement; + } + + /** + * Cette méthode renvoie un tableau contenant les objets de la classe $sClasse composant l'objet. + * \return Retourne un tableau. + */ + function getObjects($sClasse, $jsonFormat) { + $aObjClass = new stdClass(); + if (strpos($jsonFormat, "x-vm-json") != false) { + $sClassName = "data"; + $aObjClass->$sClassName = array(); + } else { + $sClassName = strtolower(get_class($sClasse)); + } + if (!empty($sClasse->aObjects)) { + $aObjClass->$sClassName = array(); + foreach ($sClasse->aObjects as $oObj) { + array_push($aObjClass->$sClassName, $this->getObjects($oObj, $jsonFormat)); + } + } + if (!empty($sClasse->aFields)) { + foreach ($sClasse->aFields as $key => $value) { + $aObjClass->$key = $value; + } + } + if (empty($aObjClass->$sClassName) && isset($aObjClass->$sClassName)){ + unset($aObjClass->$sClassName); + } + return $aObjClass; + } + + /** + * Cette méthode permet d'encoder une chaine dans un encodage prédéfini "sTargetEncoding". + * \param $sSourceEncoding Encodage de la donnée source + * \param $sTargetEncoding Encodage dans lequel la donnée source source être encodée + * \param $sString Chaine à encoder + * \return Retourne un objet DomElement. + */ + function sourceEncoding_targetEncoding($sSourceEncoding, $sTargetEncoding, $sString) { + if ($sSourceEncoding != $sTargetEncoding) { + return iconv($sSourceEncoding, $sTargetEncoding, $sString); + } else { + return $sString; + } + } + +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/BD.class.inc b/vas/rest/class/vmlib/BD.class.inc new file mode 100644 index 0000000000000000000000000000000000000000..54e90c8491213949d92f094a2950f6f620fda336 --- /dev/null +++ b/vas/rest/class/vmlib/BD.class.inc @@ -0,0 +1,1873 @@ +<?php + +/** + * \file BD.class.inc + * \brief BD.class.inc \n \n Ce fichier contient la classe php BD. + * + * Elle est basée sur un classe élaborée par Philippe Rigaux qui permet d'utiliser les fonctions natives de php pour l'exploitation du SGBD + * MySQL en français. Toutes les manipulations les plus courantes de MySQL sont implémentées dans cette classe. + * Elle a été reprise pour pouvoir fonctionner aussi bien avec une base MySQL que PostgreSQL. + * + * Les sessions php permettent de conserver les données nécessaires pour générer un objet BD récurrent. + * + * \author Philippe Rigaux <rigaux@lamsade.dauphine.fr>. + * \author Olivier Gayte <olivier.gayte@veremes.com>. + * \author Fabien Marty <fabien.marty@veremes.com>. + * \author Armand Bahi <armand.bahi@veremes.com>. + */ +/** + * \class BD + * \brief BD Class \n \n Cette classe totalement générique permet de manipuler des données + * contenues dans une base MySQL, Oracle ou PostgreSQL. + * + * Elle est basée sur un classe élaborée par Philippe Rigaux qui permet d'utiliser les fonctions natives de php pour l'exploitation du SGBD + * MySQL en français. Toutes les manipulations les plus courantes de MySQL sont implémentées dans cette classe. + * Elle a été reprise pour pouvoir fonctionner aussi bien avec une base MySQL que PostgreSQL. + * + * Les sessions php permettent de conserver les données nécessaires pour générer un objet BD récurrent. + * + * \author Philippe Rigaux <rigaux@lamsade.dauphine.fr>. + * \author Olivier Gayte <olivier.gayte@veremes.com>. + * \author Fabien Marty <fabien.marty@veremes.com>. + * \author Armand Bahi <armand.bahi@veremes.com>. + */ +require_once ("logUtil.inc"); +require_once ("stringUtil.inc"); +require_once ("phpUtil.inc"); + +class BD { + + /** + * Dossier contenant le fichier lib. + */ + var $sFolderLib = "vmlib"; + + /** + * Objet connexion en cours. + */ + var $connexion; + + /** + * Booléen, permet de savoir si une erreur à été rencontrée. + */ + var $erreurRencontree = 0; + + /** + * Identifiant de l'utilisateur. + */ + var $login; + + /** + * Mot de passe de l'utilisateur. + */ + var $mdp; + + /** + * Nom de la base de données utilisée. + */ + var $base; + + /** + * Nom ou IP du serveur utilisé. + */ + var $serveur; + + /** + * Port de connexion. + */ + var $port; + + /** + * Message à afficher. + */ + var $sMessage = ""; + + /** + * Message à afficher dans les logs. + */ + var $sMessageLog = ""; + + /** + * Commande DSN de connexion. + */ + var $sDsn; + + /** + * Casse des attributs renvoyées par la fonction LigneSuite ("min", "maj" ou ""). + */ + var $sAttributeCase = ""; //"min", "maj" + /** + * nom du SGBD dans la syntaxe du dsn ("mysql", "pgsql", "oci") + */ + var $sgbd; + + /** + * langue de l'application par défaut fr + */ + var $lang; + + /** + * Connexion à la base + * \param $login Identifiant de l'utilisateur. + * \param $motDePasse Mot de passe de l'utilisateur. + * \param $base Nom de la base de données utilisée. + * \param $serveur Nom ou IP du serveur utilisé. + * \param $port Port de connexion utilisé : 5432 pour postgresql + * \param $sgbd SGBD utilisé : "pgsql" - "mysql" - "oci" (Oracle) + */ + function __construct($login, $motDePasse, $base, $serveur, $port, $sgbd, $sPageEncoding = "ISO-8859-1", $lang = "fr") { + $this->login = $login; + $this->mdp = $motDePasse; + $this->base = $base; + $this->serveur = $serveur; + $this->sgbd = $sgbd; + $this->port = $port; + $this->sPageEncoding = $sPageEncoding; + $this->lang = $lang; + loadLang($this->sFolderLib, $this->lang); + if ($this->sgbd != "") { + try { + $this->connectSGBD(); + } catch (PDOException $e) { + /** + * En cas d'utilisation de l'AD, le mot de passe doit respecter + * certaines règles de codage, le code situé ci-dessous + * correspond à ce type de cas + */ + // $this->mdp = utf8_decode($motDePasse); + $this->mdp = iconv("UTF-8", "CP1252", $motDePasse); + try { + $this->connectSGBD(); + } catch (PDOException $e) { + $this->erreurRencontree = 1; + writeToErrorLog($this->stringMessageEncode(ERROR_ACCESS_SERVER . $this->base . ", " . $this->serveur . " , " . $this->login . " , ip: " . $_SERVER['REMOTE_ADDR'] . " ** " . $e->getMessage())); + $this->setStringMessage(ERROR_CONNECT_SERVER); + $this->setStringMessage($e->getMessage()); + } + } + } else { + $this->erreurRencontree = 1; + $this->setStringMessage(ERROR_SGBD_UNDEFINED); + writeToErrorLog($this->stringMessageEncode(ERROR_SGBD_UNDEFINED)); + } + } + + // ---- Partie privée : les méthodes + + /** + * Connexion à PDO + */ + function connectSGBD() { + switch ($this->sgbd) { + case "sqlite": + $this->connexion = new PDO($this->sgbd . ':' . $this->serveur . '/' . $this->base); + break; + case "mysql" : + $this->sDsn = $this->sgbd . ':host=' . $this->serveur . ';dbname=' . $this->base; + $this->connexion = new PDO($this->sDsn, $this->login, $this->mdp); + break; + case "pgsql" : + $this->connexion = new PDO($this->sgbd . ':host=\'' . $this->serveur . '\' port=' . $this->port . ' dbname=\'' . $this->base . '\'', $this->login, $this->mdp); + $oPDOresult = $this->connexion->query("SET CLIENT_ENCODING TO '" . $this->sPageEncoding . "'"); + break; + case "oci" : + if ($this->serveur != "") { + // $this->sDsn= $this->sgbd.':dbname=//'.$this->serveur.':'.$this->port.'/'.$this->base.';charset='.$this->sPageEncoding; + $this->sDsn = $this->sgbd . ':dbname=//' . $this->serveur . ':' . $this->port . '/' . $this->base . ';charset=' . $this->sPageEncoding; + } else { + //Pour oracle, la variable $this->sPageEncoding est "AL32UTF8" et non "UTF8" + $this->sDsn = $this->sgbd . ':dbname=' . $this->base . ';charset=' . $this->sPageEncoding; + } + + $this->connexion = new PDO($this->sDsn, $this->login, $this->mdp); + break; + default: + $this->erreurRencontree = 1; + $this->setStringMessage(ERROR_INCORRECT_SGBD); + writeToErrorLog($this->stringMessageEncode(ERROR_INCORRECT_SGBD)); + break; + } + } + + /** + * Méthodes getSourceEncoding + * \return Cette méthode permet de retourner l'encodage de la base de données selon le type de BD. + */ + function getSourceEncoding() { + if ($this->sgbd != "") { + try { + switch ($this->sgbd) { + case "sqlite": + // Requête qui va permettre de récupérer l'encodage de la base + break; + case "pgsql" : + $sSql = "SELECT datname,encoding FROM pg_database where datname=[sDataBase]"; + $oPDOresult = $this->executeWithParams($sSql, array('sDataBase' => array('type' => 'string', 'value' => $this->base))); + $this->aSourceEncoding = $this->ligneSuivante($oPDOresult); + switch ($this->aSourceEncoding["encoding"]) { + case 6: + $sSourceEncoding = "UTF-8"; + break; + case 8: + $sSourceEncoding = "ISO-8859-1"; + break; + case 24: + $sSourceEncoding = "WIN1252"; + break; + default: + $sSourceEncoding = "ISO-8859-1"; + break; + } + break; + case "oci" : + $sSql = "select * from NLS_DATABASE_PARAMETERS where parameter='NLS_CHARACTERSET'"; +// $sSql = str_replace('sDataBase', $this->base, $sSql); + $oPDOresult = $this->executeWithParams($sSql, array()); + $this->aSourceEncoding = $this->ligneSuivante($oPDOresult); + switch ($this->aSourceEncoding["NLS_CHARACTERSET"]) { + /* case 6: + $sSourceEncoding="UTF-8"; + break; + case 8: + $sSourceEncoding="ISO-8859-1"; + break; */ + case "WE8MSWIN1252": + $sSourceEncoding = "WIN1252"; + break; + default: + $sSourceEncoding = "WIN1252"; + break; + } + + break; + default: + $this->erreurRencontree = 1; + $this->setStringMessage(ERROR_INCORRECT_SGBD); + writeToErrorLog($this->stringMessageEncode(ERROR_INCORRECT_SGBD)); + break; + } + } catch (PDOException $e) { + $this->erreurRencontree = 1; + writeToErrorLog($this->stringMessageEncode(ERROR_ACCESS_SERVER . $this->base . ", " . $this->serveur . " , " . $this->login . " ** " . $e->getMessage())); + $this->setStringMessage(ERROR_CONNECT_SERVER); + $this->setStringMessage($e->getMessage()); + } + } else { + $this->erreurRencontree = 1; + $this->setStringMessage(ERROR_SGBD_UNDEFINED); + writeToErrorLog($this->stringMessageEncode(ERROR_SGBD_UNDEFINED)); + } + return $sSourceEncoding; + } + + /** + * Méthodes pour afficher le message en HTML. + * \param $message Message à afficher. + * \private + */ + function setBDMessage($message) { + $this->sMessage .= $message . "<br>"; + } + + /** + * Méthodes pour afficher le message écrit en log en HTML. + * \param $message Message à afficher. + * \private + */ + function setBDMessageLog($message) { + $this->sMessageLog .= $message . "<br>"; + } + + /** + * Méthodes pour afficher le message en HTML encodé en UTF-8. + * ATTENTION : A utiliser seulement pour des chaines écrites à la main. Ne pas utiliser pour des chaines ou il y a concaténation entre "chaine écrite à la main" et chaine venant de la Base de données + * \param $message Message à afficher. + * \private + */ + function setStringMessage($message) { + $this->sMessage .= iconv("ISO-8859-1", $this->sPageEncoding, $message) . "<br>"; + } + + /** + * Méthodes qui permet d'encoder une chaine en UTF-8 pour que celle-ci soit correctement écrite dans les fichier de log. + * \param $sMessageEncode Message à afficher. + * \return La chaine à écrire dans le fichier de log. + */ + function stringMessageEncode($sMessageEncode) { + $sMessageEncode = iconv("ISO-8859-1", $this->sPageEncoding, $sMessageEncode); + return $sMessageEncode; + } + + /** + * \private + * \return Le message à afficher. + */ + function getBDMessage() { + if ($this->sMessage != "") + $sResult = USER_LABEL . $this->login . ERROR_LABEL . $this->sMessage; + else + $sResult = ""; + return $sResult; + } + + /** + * \private + * \return Le message à afficher. + */ + function getBDMessageLog() { + if ($this->sMessageLog != "") + $sResult = USER_LABEL . $this->login . ERROR_LABEL . $this->sMessageLog; + else + $sResult = ""; + return $sResult; + } + + /** + * Supprime le message à afficher. + * \private + */ + function cleanMessage() { + $this->sMessage = ""; + } + + // ---- Partie publique ------------------------- + + /** + * DEPRECATED + * Méthode indiquant la liste des tables contenues dans la base de données. + * \return Le jeu d'enregistrement de la liste des tables. + */ + function listeDesTables() { + $sSql = "SHOW TABLES FROM " . $this->base; + $oPDOresult = $this->execute($sSql); + return $oPDOresult; + } + + /** + * Méthode d'exécution d'une requête. + * Si la requête SQL est variable en fonction d'un ou plusieurs paramètres + * il faut ABSOLUMENT utiliser executeWithParams au lieu de execute + * afin d'éviter les injections SQL + * \param $sRequete Requête à exécuter. + * \return Le jeu d'enregistrement généré par l'exécution. + */ + function execute($sRequete) { + writeToDebugLog($sRequete); + if (is_null($this->connexion)) { + $this->erreurRencontree = 1; + $this->setBDMessage(ERROR_REQUEST_ERROR); + writeToErrorLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sRequete)); + writeToSqlErrorLog($sRequete); + return false; + } + $oPDOresult = $this->connexion->query($sRequete); + if ($this->connexion->errorCode() === "00000") { + $this->erreurRencontree = 0; + if (strtolower(substr($sRequete, 0, 6)) != "select") { + writeToSqlLog($sRequete); + } + return $oPDOresult; + } else { + $aPDOError = $this->connexion->errorInfo(); + $this->erreurRencontree = 1; + $this->setBDMessage(ERROR_REQUEST_ERROR); + writeToErrorLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sRequete . "." . RETURN_BD_LABEL . "'" . $aPDOError[2] . "'")); + $this->setBDMessageLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sRequete . "." . RETURN_BD_LABEL . "'" . $aPDOError[2] . "'")); + writeToSqlErrorLog($sRequete); + return false; + } + } + + /** + * Méthode sure d'exécution d'une requête avec paramètres. + * Si la requête SQL est variable en fonction d'un ou plusieurs paramètres + * il faut ABSOLUMENT utiliser executeWithParams au lieu de execute + * afin d'éviter les injections SQL + * \param $sRequete Requête à exécuter. + * \param $aParams Paramètres à ajouter dans la requête. + * \param $bLogSQL true si on veut logger les requêtes autre que SELECT dans sql.log + * \return Le jeu d'enregistrement généré par l'exécution. + */ + function executeWithParams($sRequete, $aParams, $bLogSQL = true) { + + $this->connexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); + + // Supprime les paramètres non présents dans la requête + foreach ($aParams as $key => $value) { + if (strpos($sRequete, $key) === false) { + unset($aParams[$key]); + } + } + + $aSqlParams = array(); + $aParamsCpy = $aParams; + $sRequeteToLog2 = $sRequete . ' | ' . json_encode($aParams, true); + + // Pré-traitement des paramètres + foreach ($aParamsCpy as $key => $value) { + switch ($aParamsCpy[$key]['type']) { + case 'group': + $aGroupValues = explode('|', $aParamsCpy[$key]['value']); + $sInFilter = ''; + for ($i = 0; $i < count($aGroupValues); $i++) { + $aGroupValues[$i] = trim($aGroupValues[$i]); + if (strlen($sInFilter) > 0) { + $sInFilter .= ', '; + } + $sValueKey = 'value_' . vitisUniqId(); + $aParams[$sValueKey] = array('value' => $aGroupValues[$i], 'type' => 'string'); + $sInFilter .= '[' . $sValueKey . ']'; + } + unset($aParams[$key]); + $sRequete = str_replace('[' . $key . ']', $sInFilter, $sRequete); + break; + default: + break; + } + } + + $sRequeteToLog1 = $sRequete; + + // Traitement des paramètres + foreach ($aParams as $key => $value) { + + // Requête à logger + switch ($aParams[$key]['type']) { + case 'integer': + case 'column_name': + case 'schema_name': + case 'table_name': + $sRequeteToLog1 = str_replace('[' . $key . ']', $aParams[$key]['value'], $sRequeteToLog1); + break; + default: + $sRequeteToLog1 = str_replace('[' . $key . ']', "'" . $aParams[$key]['value'] . "'", $sRequeteToLog1); + break; + } + + // Requête à executer + switch ($aParams[$key]['type']) { + case 'integer': + case 'number': + case 'string': + case 'boolean': + // Valeur de type booléen et vide. + if ($aParams[$key]['type'] == 'boolean' && $aParams[$key]['value'] == '') + $aParams[$key]['value'] = null; + // Configuration du pramètre à utiliser lors de l'execution + $aSqlParams[':' . $key] = $aParams[$key]['value']; + $sRequete = str_replace('[' . $key . ']', ':' . $key, $sRequete); + break; + // Configuration du pramètre à utiliser lors de l'execution + $aSqlParams[':' . $key] = $aParams[$key]['value']; + $sRequete = str_replace('[' . $key . ']', ':' . $key, $sRequete); + break; + case 'geometry': + case 'quoted_string': + // Protège contre les quotes + $aParams[$key]['value'] = $this->protegeChaine($aParams[$key]['value']); + // Remplacement dans la reaqête + $sRequete = str_replace('[' . $key . ']', $aParams[$key]['value'], $sRequete); + break; + case 'column_name': + case 'schema_name': + case 'table_name': + // Vérification de la syntaxe pour qu'elle corresponde à une colonne, table, schema + if (preg_match('/^[\p{L}\p{N}@$#_]{0,127}$/', $aParams[$key]['value'])) { + // Remplacement dans la reaqête + $sRequete = str_replace('[' . $key . ']', $aParams[$key]['value'], $sRequete); + } else { + writeToSqlErrorLog($sRequeteToLog2 . ' | ' . $sRequeteToLog1 . ' | ' . $aParams[$key]['value'] . ' not match with column_name, schema_name, table_name'); + } + break; + case 'double_quote': + $aParams[$key]['value'] = '"' . $this->protegeSpecialChar($aParams[$key]['value']) . '"'; + $sRequete = str_replace('[' . $key . ']', $aParams[$key]['value'], $sRequete); + break; + default: + break; + } + } + + $oPDOresult = $this->connexion->prepare($sRequete); + if ($oPDOresult) { + foreach ($aParams as $key => $value) { + $bBindOk = true; + switch ($aParams[$key]['type']) { + case 'integer': + $bBindOk = $oPDOresult->bindValue(':' . $key, $aParams[$key]['value'], PDO::PARAM_INT); + break; + case 'number': + // Vérifications + if (is_string($aParams[$key]['value'])) { + // Valeur vide ? + if (strlen(trim($aParams[$key]['value'])) == 0) { + $aParams[$key]['value'] = null; + } + // Valeur non numérique ? + elseif (!is_numeric($aParams[$key]['value'])) { + writeToErrorLog('Error when trying to insert a textual value into a numeric attribute' . json_encode($aParams[$key], true)); + writeToSqlErrorLog($sRequeteToLog2 . ' | ' . $sRequeteToLog1); + $this->setBDMessage(ERROR_REQUEST_ERROR); + $this->erreurRencontree = 1; + return false; + } + // Valeur numérique entre côtes + else { + $aParams[$key]['value'] = floatval($aParams[$key]['value']); + } + } + $bBindOk = $oPDOresult->bindValue(':' . $key, $aParams[$key]['value']); + break; + case 'string': + $bBindOk = $oPDOresult->bindValue(':' . $key, $aParams[$key]['value'], PDO::PARAM_STR); + break; + case 'boolean': + $bBindOk = $oPDOresult->bindValue(':' . $key, $aParams[$key]['value'], PDO::PARAM_BOOL); + break; + default: + break; + } + if (!$bBindOk) { + writeToErrorLog('Error when binding ' . print_r($aParams[$key], true)); + $this->setBDMessage(ERROR_REQUEST_ERROR); + writeToErrorLog(print_r($this->connexion->errorInfo(), true)); + return false; + } + } + + $oPDOresult->execute(); + if ($bLogSQL) { + writeToDebugLog($sRequeteToLog2 . ' | ' . $sRequeteToLog1); + } + + if ($oPDOresult->errorCode() === "00000") { + $this->erreurRencontree = 0; + if (strtolower(substr($sRequete, 0, 6)) != "select" && $bLogSQL) { + writeToSqlLog($sRequeteToLog1); + } + return $oPDOresult; + } else { + $aPDOError = $oPDOresult->errorInfo(); + $this->erreurRencontree = 1; + $this->setBDMessage(ERROR_REQUEST_ERROR); + writeToErrorLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sRequete . "." . RETURN_BD_LABEL . "'" . $aPDOError[2] . "'")); + writeToSqlErrorLog($sRequeteToLog2 . ' | ' . $sRequeteToLog1); + return false; + } + } + } + + /** + * Execute un bloc de multiples requêtes SQL + * @param string $sSql + * @return Le jeu d'enregistrement généré par l'exécution. + */ + function executeBlock($sSql) { + + $this->connexion->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1); + $this->connexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + try { + $oPDOresult = $this->connexion->prepare($sSql); + if ($oPDOresult) { + $oPDOresult->execute(); + writeToDebugLog($sSql); + if ($this->connexion->errorCode() === "00000") { + $this->erreurRencontree = 0; + writeToSqlLog($sSql); + return $oPDOresult; + } else { + $aPDOError = $this->connexion->errorInfo(); + $this->erreurRencontree = 1; + $this->setBDMessage(ERROR_REQUEST_ERROR); + $this->setBDMessageLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sRequete . "." . RETURN_BD_LABEL . "'" . $aPDOError[2] . "'")); + writeToErrorLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sSql . "." . RETURN_BD_LABEL . "'" . $aPDOError[2] . "'")); + writeToSqlErrorLog($sSql); + return false; + } + } + } catch (PDOException $e) { + $sPDOErrorMessage = $e->getMessage(); + $this->erreurRencontree = 1; + $this->setBDMessage(ERROR_REQUEST_ERROR); + writeToErrorLog(html_entity_decode(ERROR_REQUEST_IMPOSSIBLE . $sSql . "." . RETURN_BD_LABEL . "'" . $sPDOErrorMessage . "'")); + writeToSqlErrorLog($sSql); + die(); + return false; + } + } + + /** + * Méthode permettant de démarrer une transaction. + */ + function demarreTransaction() { + $this->connexion->beginTransaction(); + } + + /** + * Méthode permettant de terminer une transaction. + */ + function termineTransaction() { + $this->connexion->commit(); + } + + /** + * Méthode permettant d'annuler une transaction. + */ + function annuleTransaction() { + $this->connexion->rollBack(); + } + + /** + * Méthode de suppression d'un objet PDO::Statement (nécessaire pour l'exécution + * de requêtes successives). + * \return Null. + */ + function fermeResultat() { + return null; + } + + /** + * Accès à la ligne suivante, sous forme d'objet + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \return La ligne suivante dans le jeu d'enregistrement. + */ + function objetSuivant($oPDOresult) { + return $oPDOresult->fetch(PDO::FETCH_OBJ); + } + + /** + * Accès à la ligne suivante, sous forme de tableau associatif + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \return La ligne suivante dans le jeu d'enregistrement. + */ + function ligneSuivante($oPDOresult) { + return $oPDOresult->fetch(PDO::FETCH_ASSOC); + } + + /** + * Accès au résultat sous forme de tableau associatif + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \return un tableau contenant les enregistrements sous forme de tableau associatif (champs=>valeur). + */ + function getResultTableAssoc($oPDOresult) { + return $oPDOresult->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * Accès à la ligne suivante, sous forme de tableau indicé + * \param $oDBresultat Jeu d'enregistrement. + * \return La ligne suivante dans le jeu d'enregistrement. + */ + function tableauSuivant($oPDOresult) { + return $oPDOresult->fetch(PDO::FETCH_NUM); + } + + /** + * Méthode indiquant si une erreur a été rencontrée + * \return L'erreur rencontrée. + */ + function enErreur() { + return $this->erreurRencontree; + } + + /** + * DEPRECATED + * Méthode donnant l'id de la dernière ligne insérée. + * \return L'id de la dernière ligne insérée. + */ + function idDerniereLigne() { + return mysql_insert_id(); + } + + /** + * Méthode permettant de protéger les caractéres spéciaux d'une chaine de caractère + * dans une requête. + * \param $chaine Chaine de caractère à protéger. + */ + function protegeChaine($chaine) { + return $this->connexion->quote($chaine); + } + + /** + * Merthode permettant de remplacer les caractères critiques. + * Ces caractères sont les guillemets simples ('), guillemets doubles ("), antislash (\) et NULLE (le caractère NULL). + * @param string $chaine + * @return string + */ + function protegeSpecialChar($chaine) { + return addslashes($chaine); + } + + /** + * Méthode indiquant le nombre d'attributs dans le résultat. + * \param $res Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \return Le nombre d'attributs dans le résultat. + */ + function getFieldsNumber($oPDOresult) { + return $oPDOresult->columnCount(); + } + + /** + * Méthode donnant le nom d'un attribut. + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \param $iFieldCount Nombre d'attributs. + * \param $iPosition Position de l'attribut. + * \return Le nom d'un attribut. + */ + function getFieldName($oPDOresult, $iFieldCount, $iPosition, $sTable) { + // Test sur la position + if ($iPosition < 0 or $iPosition >= $iFieldCount) { + $this->setStringMessage(ATTRIBUT_POSITION_BD_LABEL); + return UNKNOWN_BD_LABEL; + } else { + if ($this->sgbd == 'oci') { +// $resultat = $this->execute('SELECT * FROM COLS WHERE name = \'' . strtoupper($sTable) . '\''); + $resultat = $this->executeWithParams('SELECT * FROM COLS WHERE name = \'[sTable]\'', array('sTable' => array('type' => 'column_name', 'value' => $sTable))); + for ($i = 0; $aLigne = $this->ligneSuivante($resultat); $i++) { + if ($i == $iPosition) { + return $aLigne['COLUMN_NAME']; + } + } + } else { + $aMeta = $oPDOresult->getColumnMeta($iPosition); + return $aMeta['name']; + //if ($this->sgbd=='pgsql') + //else return $aMeta['name']; + } + } + } + + /** + * Méthode indiquant le nombre de lignes dans le résultat. Utilisez PHP> 5.1 + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \return Le nombre de lignes dans le résultat. + */ + function nombreLigne($oPDOresult) { + return $oPDOresult->rowCount(); + } + + /** + * Méthode de déconnexion. + */ + function quitter() { + $this->connexion->null; + } + + /** + * Méthode permettant de récupérer le type d'une attribut. + * \param $oPDOresult Jeu d'enregistrement résultant de l'éxécution d'une requête. + * \param $iNumFields Nombres d'attributs. + * \param $sFieldName Nom de l'attribut. + * \return Le type d'une attribut (-1 si l'attribut passé en paramètre n'est pas trouvé, 'VAR_STRING' texte, 'DATE' date, ... ). + */ + function getType($oPDOresult, $iNumFields, $sFieldName, $sTable) { + $sType = -1; + if ($this->sgbd == 'oci') { +// $resultat = $this->execute('SELECT * FROM COLS WHERE name = \'' . strtoupper($sTable) . '\''); + $resultat = $this->executeWithParams('SELECT * FROM COLS WHERE name = \'[sTable]\'', array('sTable' => array('type' => 'column_name', 'value' => $sTable))); + for ($i = 0; $aLigne = $this->ligneSuivante($resultat); $i++) { + if ($aLigne['COLUMN_NAME'] == $sFieldName) { + return $aLigne['DATA_TYPE']; + } + } + } else { + for ($i = 0; $i < $iNumFields; $i++) { + $aMeta = $oPDOresult->getColumnMeta($i); + if ($aMeta['name'] == $sFieldName) + $sType = $aMeta['native_type']; + } + } + // si le champ n'a pas été trouvé, il s'agit d'une erreur + return $sType; + } + + /** + * DEPRECATED + * Méthode permettant de construire une clause WHERE SQL à partir d'une liste de valeur passées en requête. + * La table cible est spécifiée en paramètre de la méthode. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on recherche. + * \param $aValues Valeurs contenues dans la requête. + * \param $bListQuery Liste des champs filtrés. + * \param $bUpper Modification de la casse. Facultatif, false par défaut. + * \param $bClause Type de clause : AND ou OR. Facultatif, AND par défaut. + * \return La clause WHERE de la requête SQL de recherche. + */ + function getWhereClause($sSchema, $sTable, $aValues, $bListQuery, $bLower = false, $sClause = "AND") { + // LIKE gère tous les types de champs. + switch ($this->sgbd) { + case 'mysql' : + $sProtectField = '`'; + $sSql = $this->AddLimite(0, 1, "SELECT * FROM " . $sTable); + break; + case 'pgsql' : + $sTable = $sSchema . "." . $sTable; + $sProtectField = '"'; + $sSql = $this->AddLimite(0, 1, "SELECT * FROM " . $sTable); + break; + case 'oci' : + $sProtectField = ''; + $sSql = $this->AddLimite(0, 1, "SELECT " . $sTable . ".* FROM " . $sTable); + break; + } + $resultat = $this->execute($sSql); + + $iNumFields = $this->getFieldsNumber($resultat); + for ($i = 0; $i < $iNumFields; $i++) { + $aField["name"][$i] = $this->getFieldName($resultat, $iNumFields, $i, $sTable); + $aField["type"][$i] = $this->getType($resultat, $iNumFields, $aField["name"][$i], $sTable); + } + $sWhereClause = ""; + $sQueryList = ""; + foreach ($aValues as $sKey => $sValue) { + $i = 0; + + while ($aField["name"][$i]) { + if ($aField["name"][$i] == $sKey && $sValue != "") { + $sChamp = $sKey; + $sKey = addDelimitedAttribute("", $sKey, "", $sProtectField); + switch ($aField["type"][$i]) { + case (ereg("LONG|int4|int|NUMBER|float4|float8", $aField["type"][$i]) > 0) : + $sCondition = "="; + if (isset($aValues["condition_" . $sChamp])) { + if ($aValues["condition_" . $sChamp] != "") { + $sCondition = $aValues["condition_" . $sChamp]; + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . " " . $sCondition . " " . $sValue . " "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " " . $sValue . " & "; + } + }else { + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . "::varchar LIKE '" . $sValue . "' "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " " . $sValue . " & "; + } + if (isset($aValues["condition_interval_sup_" . $sChamp]) && $aValues["condition_interval_sup_" . $sChamp] != "") { + $sCondition = $aValues["condition_interval_sup_" . $sChamp]; + if ($aValues["interval_sup_" . $sChamp] != "") { + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . " " . $sCondition . " " . $aValues["interval_sup_" . $sChamp] . " "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " " . $aValues["interval_sup_" . $sChamp] . " & "; + } + } + break; + case 'bool' : + if ($sValue == '1') + $sValue = 'TRUE'; + if ($sValue == '0') + $sValue = 'FALSE'; + if ($sWhereClause == "") + $sWhereClause .= " WHERE " . $sTable . "." . $sKey . " = " . $sValue . " "; + else + $sWhereClause .= " " . $sClause . " " . $sTable . "." . $sKey . " = " . $sValue . " "; + if ($bListQuery) + $sQueryList .= $sKey . "=" . $sValue . " & "; + break; + //case "datetime" || "timestamp" : + + case (ereg("DATE|date|timestamp", $aField["type"][$i]) > 0) : + $sCondition = "="; + $DateUneFr = $aValues[$sChamp]; + $DateDeuxFr = $aValues["interval_sup_" . $sChamp]; + $sValue = substr($this->formatForSql($aValues[$sChamp], $aField["type"][$i]), 1, -1); + $aValues["interval_sup_" . $sChamp] = substr($this->formatForSql($aValues["interval_sup_" . $sChamp], $aField["type"][$i]), 1, -1); + if (isset($aValues["condition_" . $sChamp])) { + if ($aValues["condition_" . $sChamp] != "") { + $sCondition = $aValues["condition_" . $sChamp]; + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . " " . $sCondition . " '" . $sValue . "' "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " '" . $DateUneFr . "' & "; + } + } else { + //if($this->sgbd === "oci") $sFunction = "TO_CHAR(".$sTable.".".$sKey.", 'DD/MM/YYYY')"; + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . "::varchar LIKE '%" . $sValue . "%' "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " " . $DateUneFr . " & "; + } + if (isset($aValues["condition_interval_sup_" . $sChamp]) && $aValues["condition_interval_sup_" . $sChamp] != "") { + $sCondition = $aValues["condition_interval_sup_" . $sChamp]; + if ($aValues["interval_sup_" . $sChamp] != "") { + ($sWhereClause == "") ? $sWhereClause .= " WHERE " : $sWhereClause .= " " . $sClause . " "; + $sWhereClause .= $sTable . "." . $sKey . " " . $sCondition . " '" . $aValues["interval_sup_" . $sChamp] . "' "; + if ($bListQuery) + $sQueryList .= $sChamp . " " . $sCondition . " '" . $DateDeuxFr . "' & "; + } + } + break; + default : + $sValue = str_replace("'", "''", $sValue); + if ($bLower) { + $sValue = strtolower($sValue); + if ($sWhereClause == "") + $sWhereClause .= " WHERE lower(" . $sTable . "." . $sKey . ") LIKE '%" . $sValue . "%' "; + else + $sWhereClause .= " " . $sClause . " lower(" . $sTable . "." . $sKey . ") LIKE '%" . $sValue . "%' "; + }else { + if ($sWhereClause == "") + $sWhereClause .= " WHERE " . $sTable . "." . $sKey . " LIKE '%" . $sValue . "%' "; + else + $sWhereClause .= " " . $sClause . " " . $sTable . "." . $sKey . " LIKE '%" . $sValue . "%' "; + } + if ($bListQuery) + $sQueryList .= $sKey . "='" . $sValue . "' & "; + break; + } + } + $i++; + } + } + $resultat = $this->fermeResultat(); + if ($sQueryList != "") + $sQueryList = substr($sQueryList, 0, -3); + return array("WhereClause" => $sWhereClause, "QueryList" => $sQueryList); + } + + /** + * Méthode permettant d'ajouter des enregistrements. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on ajoute. + * \param $aValues Valeurs à ajouter. + * \param $sSequence Nom de la séquence à utiliser. + * \param $iIdField Nom de l'attribut identifiant. + * \param $bGetSql Booléen : doit on renvoyer le code sql ou exécuter la requête? Vaut 'false' par défaut. + * \return L'id de la dernière ligne insérée. + */ + function insert($sSchema, $sTable, $aValues, $sSequence, $iIdField, $bGetSql = false) { + + $aSQLParams = array( + 'sSchema' => array('type' => 'column_name', 'value' => $sSchema), + 'sTable' => array('type' => 'column_name', 'value' => $sTable) + ); + + // Insére les éléments du tableau $aValues dans $sTable et renvoie l'identifiant de l'enregistrement correspondant (en fait le dernier) + switch ($this->sgbd) { +// case 'mysql' : +// $sSql = "INSERT INTO `$sTable` ("; +// $sSqlList = $this->AddLimite(0, 0, "SELECT * FROM " . $sTable); +// $sProtectField = "`"; +// break; + case 'pgsql' : + $sSql = 'INSERT INTO "[sSchema]"."[sTable]" ('; +// $sSqlList = $this->AddLimite(0, 0, 'SELECT * FROM ' . $sSchema . '.' . $sTable); + + $aSqlList = $this->AddLimiteWithParams(0, 0, 'SELECT * FROM "[sSchema]"."[sTable]"'); + $sSqlList = $aSqlList['sql']; + $aSQLListParams = array_merge($aSQLParams, $aSqlList['params']); + + $sProtectField = '"'; + // Utilisation de la sequence pour récupérer un identifiant + if ($sSequence) { +// $oPDOresult = $this->execute('SELECT nextval(\'' . $sSequence . '\')'); + $oPDOresult = $this->executeWithParams('SELECT nextval([sSequence])', array('sSequence' => array('type' => 'string', 'value' => $sSequence))); + if ($oPDOresult !== false) + $aIdValue = $this->ligneSuivante($oPDOresult); + $iIdValue = $aIdValue['nextval']; + $aValues[$iIdField] = $iIdValue; + $oPDOresult = $this->fermeResultat(); + } + break; +// case 'oci' : +// $sSql = 'INSERT INTO ' . $sTable . '('; +// $sSqlList = 'SELECT ' . $sTable . '.* FROM ' . $sTable . ' WHERE ROWNUM <=1 AND ROWNUM >=0'; +// $sProtectField = '"'; +// // Utilisation de la sequence pour récupérer un identifiant +// if ($sSequence) { +// $oPDOresult = $this->execute('SELECT ' . $sSequence . '.nextval FROM dual'); +// if ($oPDOresult !== false) +// $aIdValue = $this->ligneSuivante($oPDOresult); +// $iIdValue = $aIdValue['NEXTVAL']; +// $aValues[$iIdField] = $iIdValue; +// $oPDOresult->closeCursor(); +// } +// break; + } + $sFields = ""; + $sValues = ""; + +// $resultat = $this->execute($sSqlList); + $resultat = $this->executeWithParams($sSqlList, $aSQLListParams); + $iNumFields = $this->getFieldsNumber($resultat); + + foreach ($aValues as $sField => $sValue) { + if ($iIdField == $sField) + $iIdValue = $sValue; + if (substr_count($sField, '.') == 1) + $sField = substr($sField, strlen($sTable) + 1); + $sType = $this->getType($resultat, $iNumFields, $sField, $sTable); + if ($sType != -1) { + + $sFields = addDelimitedAttribute($sFields, $sField, ",", $sProtectField); + $aFormatedField = $this->formatForSqlWithParams($sValue, $sField, $sType, $sSchema, $sTable); + $sValues = addDelimitedString($sValues, $aFormatedField['field'], ","); + + switch ($this->parseType($sType)) { + case 'int': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'number', 'value' => $aFormatedField['value']); + break; + case 'float': + case 'decimal': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'number', 'value' => $aFormatedField['value']); + break; + case 'bool': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'boolean', 'value' => $aFormatedField['value']); + break; + case 'geometry': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'geometry', 'value' => $aFormatedField['value']); + break; + default: + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'string', 'value' => $aFormatedField['value']); + break; + } + } + } + + if (empty($iIdValue)) { + $sSql = $sSql . $sFields . ") VALUES (" . $sValues . ") RETURNING \"" . $iIdField . "\""; + } else { + $sSql = $sSql . $sFields . ") VALUES (" . $sValues . ")"; + } + + $resultat = $this->fermeResultat(); + if ($bGetSql) { + return $sSql; + } else { + + $iResult = $this->executeWithParams($sSql, $aSQLParams); + if ($iResult === false) { + return $iResult; + } + + // Valeur retour au cas où $iIdValue soit vide + if (empty($iIdValue)) { + $iIdValue = $iResult->fetchColumn(); + } + if ($iResult !== false) { + $iResult = $this->fermeResultat(); + } + + if ($this->sgbd == 'mysql') + $iIdValue = $this->connexion->lastInsertId(); + return $iIdValue; + } + } + + /** + * DEPRECATED + * Méthode permettant d'ajouter des enregistrements par le biais de la commande SQL 'COPY'. + * Methode implémentée pour PostgreSQL. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on ajoute. + * \param $aValues Valeurs à ajouter. + * \param $sSequence Nom de la séquence à utiliser. + * \param $sIdField Nom de l'attribut identifiant. + */ + function copy($sSchema, $sTable, $aValues, $sSequence, $sIdField) { + //$iIdValue = $aIdValue['nextval']; + $sSqlField = $this->AddLimite(0, 0, "SELECT * FROM " . $sSchema . "." . $sTable); + $iFieldResult = $this->execute($sSqlField); + $iNumField = $this->getFieldsNumber($iFieldResult); + + $sCopy = ""; + $aType = array(); + foreach ($aValues as $i => $aRow) { + if ($i == 0) { + $sCopy .= "COPY " . $sSchema . "." . $sTable . " ("; + foreach ($aRow as $sField => $sValue) { + if (substr_count($sField, '.') == 1) + $sField = substr($sField, strlen($sTable) + 1); + $aType[$sField] = $this->getType($iFieldResult, $iNumField, $sField, $sTable); + $sFields = addDelimitedAttribute($sFields, $sField, ",", "\""); + } + $sCopy .= $sFields . ") FROM stdin;\n"; + } + $iSeqResult = $this->execute("SELECT nextval('" . $sSequence . "')"); + if ($iSeqResult !== false) + $aIdValue = $this->ligneSuivante($iSeqResult); + $iSeqResult = $this->fermeResultat(); + foreach ($aRow as $sField => $sValue) { + if ($sIdField === $sField) + $sValue = $aIdValue["nextval"]; + if ($sValue === "null") + $sValue = "\\N"; + $sValues = addDelimitedString($sValues, $sValue, "\t"); + } + $sCopy .= $sValues . "\n"; + } + $sCopy .= "\\."; + $iNumField = $this->fermeResultat(); + + $iResult = $this->execute($sCopy); + if ($iResult !== false) { + $iResult = $this->fermeResultat(); + return true; + } else { + return false; + } + } + + /** + * Méthode permettant de mettre à jour des enregistrements. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on met à jour. + * \param $aValues Valeurs à mettre à jour. + * \param $sAttribute Attribut de la clause "WHERE". + * \param $sId Valeur de l'attribut. + * \param $sIdType Type de l'attribut. + */ + function update($sSchema, $sTable, $aValues, $sAttribute, $sId, $sIdType = "") { + + $aSQLParams = array( + 'sSchema' => array('type' => 'column_name', 'value' => $sSchema), + 'sTable' => array('type' => 'column_name', 'value' => $sTable) + ); + + // Modifie la table $sTable à partir du contenu du tableau $aValues + // Le nom des éléments de $aValues doit être le même que les nom de champs + // Le type de chaque champ est pris en compte de manière dynamque + switch ($this->sgbd) { +// case 'mysql' : +// $sSql = "UPDATE `$sTable` set "; +// $sSqlList = $this->AddLimite(0, 0, "SELECT * FROM " . $sTable); +// $sProtectField = "`"; +// break; + case 'pgsql' : + $sSql = 'UPDATE "' . $sSchema . '"."' . $sTable . '" set '; +// $sSqlList = $this->AddLimite(0, 0, 'SELECT * FROM ' . $sSchema . '.' . $sTable); + $aSqlList = $this->AddLimiteWithParams(0, 0, 'SELECT * FROM "[sSchema]"."[sTable]"'); + $sSqlList = $aSqlList['sql']; + $aSQLListParams = array_merge($aSQLParams, $aSqlList['params']); + $sProtectField = '"'; + break; +// case 'oci' : +// $sSql = 'UPDATE ' . $sTable . ' set '; +// $sSqlList = $this->AddLimite(0, 1, 'SELECT * FROM ' . $sTable); +// $sProtectField = ''; +// break; + } + $sPaires = ""; + $sFields = ""; + $sValues = ""; + + $resultat = $this->executeWithParams($sSqlList, $aSQLListParams); + $iNumFields = $this->getFieldsNumber($resultat); + + foreach ($aValues as $sField => $sValue) { + if (substr_count($sField, '.') == 1) + $sField = substr($sField, strlen($sTable) + 1); + $sType = $this->getType($resultat, $iNumFields, $sField, $sTable); + + if ($sType != -1) { + + $aFormatedField = $this->formatForSqlWithParams($sValue, $sField, $sType, $sSchema, $sTable); + $sPaire = addDelimitedAttribute("", $sField, "", $sProtectField) . '=' . $aFormatedField['field']; + $sPaires = addDelimitedString($sPaires, $sPaire, ", "); + + switch ($this->parseType($sType)) { + case 'int': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'number', 'value' => $aFormatedField['value']); + break; + case 'float': + case 'decimal': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'number', 'value' => $aFormatedField['value']); + break; + case 'bool': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'boolean', 'value' => $aFormatedField['value']); + break; + case 'geometry': + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'geometry', 'value' => $aFormatedField['value']); + break; + default: + $aSQLParams[$aFormatedField['fieldKey']] = array('type' => 'string', 'value' => $aFormatedField['value']); + break; + } + } + } + + if ($sPaires != "") { + $sSql = $sSql . $sPaires; + if ($sAttribute != "") { + + if (!is_array($sId)) { + $aWhereClause = $this->AddWhereClauseWithParams($sAttribute, $sId, 'string'); + $aSQLParams = array_merge($aSQLParams, $aWhereClause['params']); + $sSql = $sSql . $aWhereClause['sql']; + } else { + $sId = implode(",", $sId); + $aInClause = $this->AddInClauseWithParams($sSchema, $sAttribute, $sId); + $aSQLParams = array_merge($aSQLParams, $aInClause['params']); + $sSql = $sSql . ' WHERE ' . $aInClause['sql']; + } + } + $resultat = $this->fermeResultat(); + $iResult = $this->executeWithParams($sSql, $aSQLParams); + + if ($iResult !== false) { + $iResult = $this->fermeResultat(); + } + } + } + + /** + * Récupère un type de colonne Postgres (int8, varchar(255) etc..) et renvoie le type simple (int, varchar, float) + * @param string $str + * @return string + */ + function parseType($str) { + + $sType = ''; + $arr = str_split($str); + $pattern = '/^[a-z]/'; + + for ($i = 0; $i < count($arr); $i++) { + if (!preg_match($pattern, $arr[$i])) { + break; + } else { + $sType .= $arr[$i]; + } + } + + return $sType; + } + + /** + * Méthode permettant de supprimer des enregistrements de la table passée en paramètre conformément à la clause spécifiée. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on supprime. + * \param $sAttribute Attribut de la clause "WHERE". + * \param $sId Valeur de l'attribut. + * \param $sIdType Types de l'attribut. + */ + function delete($sSchema, $sTable, $sAttribute, $sId, $sIdType = "") { + + $aSQLParams = array( + 'sSchema' => array('type' => 'column_name', 'value' => $sSchema), + 'sTable' => array('type' => 'column_name', 'value' => $sTable) + ); + + switch ($this->sgbd) { +// case 'mysql' : +// $sSql = "DELETE FROM `$sTable` WHERE " . $sAttribute; +// break; + case 'pgsql' : + + $aAttributs = explode('.', $sAttribute); + + // Si le schema est ou pas défini dans sAttribute + if (count($aAttributs) === 1) { + $sColumnKey = 'column_' . vitisUniqId(); + $sSql = 'DELETE FROM "[sSchema]"."[sTable]" WHERE "[' . $sColumnKey . ']"'; + $aSQLParams[$sColumnKey] = array('type' => 'column_name', 'value' => $aAttributs[0]); + } else if (count($aAttributs) === 2) { + $sSchemaKey = 'schema_' . vitisUniqId(); + $sColumnKey = 'column_' . vitisUniqId(); + $sSql = 'DELETE FROM "[sSchema]"."[sTable]" WHERE "[' . $sSchemaKey . ']"."[' . $sColumnKey . ']"'; + $aSQLParams[$sSchemaKey] = array('type' => 'column_name', 'value' => $aAttributs[0]); + $aSQLParams[$sColumnKey] = array('type' => 'column_name', 'value' => $aAttributs[1]); + } + + break; +// case 'oci' : +// $sSql = "DELETE FROM $sTable WHERE " . $sAttribute; +// break; + } + $sSql .= ' IN ([sIds])'; + $aSQLParams['sIds'] = array('type' => 'group', 'value' => $sId); + $iResult = $this->executeWithParams($sSql, $aSQLParams); + if ($iResult !== false) { + $iResult = $this->fermeResultat(); + } + } + + /** + * DEPRECATED + * Méthode permettant d'ajouter des enregistrements dans une table liée. + * \param $sTableName Table dans laquelle on ajoute. + * \param $sAttributePK Attribut PK. + * \param $sPKValue Valeur de l'attribut PK. + * \param $aAttributeList Tableau contenant les attributs et leurs valeurs. + * \param $sSequence Séquence. + * \param $sSchema Schéma. + */ + function insertLinkedTable($sTableName, $sAttributePK, $sPKValue, $aAttributeList, $sSequence, $sSchema) { + switch ($this->sgbd) { + case 'mysql' : + //méthode non implémenté pour mysql + break; + case 'pgsql' : + break; + case 'oci' : + $sSql = "SELECT " . $sAttributeFK . " FROM " . $sTableName . " WHERE " . $sAttributePK . "=" . $sPKValue; + $sSqlDel = "DELETE FROM " . $sTableName . " WHERE " . $sAttributePK . "=" . $sPKValue . " AND " . $sAttributeFK . "='"; + break; + } + + $aValues = Array(); + foreach ($aAttributeList as $aValue) { + $aValues[$aValue[0]] = $aValue[1]; + } + $this->insert($sSchema, $sTableName, $aValues, $sSequence, $sAttributePK); + } + + /** + * DEPRECATED + * Méthode permettant d'ajouter des enregistrements sans ajout de nouvel Id dans une table liée. + * \param $sSchema Schéma. + * \param $sTable Table dans laquelle on ajoute. + * \param $aAttributeFK Tableau contenant les attributs. + * \param $aValueList Tableau contenant les valeurs. + */ + function insertWithoutIdLinkedTable($sSchema, $sTable, $aAttributeList, $aValueList) { + //Méthode implémenté uniquement pour postgresql + if ($sSchema != "") { + $sTable = $sSchema . "." . $sTable; + } + foreach ($aValueList as $iKey => $sValue) { + if (gettype($sValue) == "string") { + $aValueList[$iKey] = "'" . $sValue . "'"; + } + } + $sSql = "INSERT INTO " . $sTable . ' ("' . implode('","', $aAttributeList) . '") VALUES (' . implode(',', $aValueList) . ')'; + $this->execute($sSql); + } + + /** + * DEPRECATED + * Méthode permettant de mettre à jour des enregistrements dans une table liée. + * \param $sTableName Table dans laquelle on met un enregistrement à jour. + * \param $sAttributePK Attribut PK. + * \param $sAttributeFK Attribut FK. + * \param $sFKList Liste des valeurs de l'attribut FK. + * \param $sPKValue Valeur de l'attribut PK. + */ + function updateLinkedTable($sTableName, $sAttributePK, $sAttributeFK, $sFKList, $sPKValue) { + switch ($this->sgbd) { + case 'mysql' : + //méthode non implémenté pour mysql + break; + case 'pgsql' : + $sSql = "UPDATE " . $sTableName . " SET " . $sAttributePK . "=" . $sPKValue . " WHERE " . $sAttributeFK . "="; + break; + case 'oci' : + //méthode non implémenté pour oci + break; + } + $aFKList = explode("@", $sFKList); + //Met à jour les enregistrements de $aFKList + foreach ($aFKList as $sFKValue) { + writeToDebugLog($sSql . $sFKValue); + writeToSqlLog($sSql); + $this->connexion->query($sSql . $sFKValue); + } + } + + /** + * DEPRECATED + * Méthode permettant de générer une clause SQL simple de type "LIMIT" selon le sgbd. + * \param $iMinRowValue Valeur minimale du limit. + * \param $iRowPage Nombre d'enregistrements sélectionnés. + */ + function AddLimite($iMinRowValue, $iRowPage, $sSql) { + switch ($this->sgbd) { + case 'mysql' : + $sSql .= " LIMIT " . $iMinRowValue . "," . $iRowPage; + break; + case 'pgsql' : + $sSql .= " LIMIT " . $iRowPage . " OFFSET " . $iMinRowValue; + break; + case 'oci' : + $iRowPage = $iRowPage + $iMinRowValue; + $sSql1 = "SELECT * FROM ( SELECT * FROM (" . $sSql . ") WHERE ROWNUM <= " . $iRowPage . ") MINUS ( SELECT * FROM (" . $sSql . ") WHERE ROWNUM <= " . $iMinRowValue . ")"; + if (substr_count($sSql, "ORDER BY") >= 1) { + $sSql = "SELECT * FROM ( " . $sSql1 . ")" . stristr($sSql, "ORDER BY"); + } else { + $sSql = $sSql1; + } + break; + } + return $sSql; + } + + /** + * Méthode permettant de générer une clause SQL simple de type "LIMIT" selon le sgbd. + * \param $iMinRowValue Valeur minimale du limit. + * \param $iRowPage Nombre d'enregistrements sélectionnés. + */ + function AddLimiteWithParams($iMinRowValue, $iRowPage, $sSql) { + switch ($this->sgbd) { +// case 'mysql' : +// $sSql .= " LIMIT " . $iMinRowValue . "," . $iRowPage; +// break; + case 'pgsql' : + $sSql .= " LIMIT [iRowPage] OFFSET [iMinRowValue]"; + $aSQLParams = array( + 'iRowPage' => array('type' => 'string', 'value' => $iRowPage), + 'iMinRowValue' => array('type' => 'string', 'value' => $iMinRowValue) + ); + break; +// case 'oci' : +// $iRowPage = $iRowPage + $iMinRowValue; +// $sSql1 = "SELECT * FROM ( SELECT * FROM (" . $sSql . ") WHERE ROWNUM <= " . $iRowPage . ") MINUS ( SELECT * FROM (" . $sSql . ") WHERE ROWNUM <= " . $iMinRowValue . ")"; +// if (substr_count($sSql, "ORDER BY") >= 1) { +// $sSql = "SELECT * FROM ( " . $sSql1 . ")" . stristr($sSql, "ORDER BY"); +// } else { +// $sSql = $sSql1; +// } +// break; + } + return array( + 'sql' => $sSql, + 'params' => $aSQLParams + ); + } + + /** + * DEPRECATED + * Méthode permettant de générer une clause SQL simple de type "ORDER BY" selon le sgbd. + * \param $sAttribute Attribut. + * \param $sOrder Ordre dans lequel doivent étre triées les données "ASC" ou "DESC". + */ + function AddOrder($sAttibute, $sOrder) { + if (is_null($sOrder)) + $sOrder = 'ASC'; + switch ($this->sgbd) { + case 'mysql' : + $sSql = " ORDER BY '" . $sAttibute . "' " . $sOrder; + break; + case 'pgsql' : + $sSql = ' ORDER BY "' . $sAttibute . '" ' . $sOrder; + break; + case 'oci' : + $sSql = ' ORDER BY "' . $sAttibute . '" ' . $sOrder; + break; + } + return $sSql; + } + + /** + * DEPRECATED + * Méthode permettant de générer une clause SQL simple de type "WHERE" selon le sgbd. + * \param $sAttribute Attribut. + * \param $sId Valeur de l'attribut. + * \param $sType Type de l'attribut. + */ + function AddWhereClause($sAttribute, $sId, $sType = "") { + switch ($this->sgbd) { + case 'mysql' : + $sSql = " WHERE " . $sAttribute . "=" . $sId; + break; + case 'pgsql' : + if (substr_count($sAttribute, '.') != 1) { + $sAttribute = '"' . $sAttribute . '"'; + } + if ($sType == "text") + $sId = "'" . $sId . "'"; + $sSql = ' WHERE ' . $sAttribute . '= ' . $sId; + break; + case 'oci' : + $sId = "'" . $sId . "'"; + $sSql = ' WHERE ' . $sAttribute . '= ' . $sId; + break; + } + return $sSql; + } + + /** + * Selon executeWithParams + * Méthode permettant de générer une clause SQL simple de type "WHERE" selon le sgbd. + * \param $sAttribute Attribut. + * \param $sId Valeur de l'attribut. + * \param $sType Type de l'attribut. + */ + function AddWhereClauseWithParams($sAttribute, $sId, $sType = "string") { + switch ($this->sgbd) { +// case 'mysql' : +// $sSql = " WHERE " . $sAttribute . "=" . $sId; +// break; + case 'pgsql' : + + $aAttributs = explode('.', $sAttribute); + + // Si le schema est ou pas défini dans sAttribute + if (count($aAttributs) === 1) { + + $sColumnKey = 'column_' . vitisUniqId(); + $sValueKey = 'value_' . vitisUniqId(); + + $sSql = ' WHERE "[' . $sColumnKey . ']" = [' . $sValueKey . ']'; + $aSQLParams = array( + $sColumnKey => array('type' => 'column_name', 'value' => $aAttributs[0]), + $sValueKey => array('type' => $sType, 'value' => $sId) + ); + } else if (count($aAttributs) === 2) { + + $sSchemaKey = 'schema_' . vitisUniqId(); + $sColumnKey = 'column_' . vitisUniqId(); + $sValueKey = 'value_' . vitisUniqId(); + + $sSql = ' WHERE "[' . $sSchemaKey . ']"."[' . $sColumnKey . ']" = [' . $sValueKey . ']'; + $aSQLParams = array( + $sSchemaKey => array('type' => 'column_name', 'value' => $aAttributs[0]), + $sColumnKey => array('type' => 'column_name', 'value' => $aAttributs[1]), + $sValueKey => array('type' => $sType, 'value' => $sId) + ); + } + + break; +// case 'oci' : +// $sId = "'" . $sId . "'"; +// $sSql = ' WHERE ' . $sAttribute . '= ' . $sId; +// break; + } + return array( + 'sql' => $sSql, + 'params' => $aSQLParams + ); + } + + /** + * DEPRECATED + * Méthode permettant de générer une clause SQL simple de type "AND" selon le sgbd. + * \param $sSchema Schema de la base de données + * \param $sAttribute Attribut. + * \param $sId Valeur de l'attribut. + */ + function AddAndClause($sSchema, $sAttribute, $sId, $sType = "") { + switch ($this->sgbd) { + case 'mysql' : + $sSql = " AND " . $sAttribute . "=" . $sId; + break; + case 'pgsql' : + if (substr_count($sAttribute, '.') != 1) { + $sAttribute = '"' . $sAttribute . '"'; + } else { + if (substr_count($sAttribute, '."') != 1) { + $sAttribute = str_replace('.', '."', $sAttribute . '"'); + } + if (strcmp($sSchema, "") != 0) { + $sAttribute = $sSchema . '.' . $sAttribute; + } + } + $sId = "'" . $sId . "'"; + $sSql = ' AND ' . $sAttribute . '= ' . $sId; + break; + case 'oci' : + if ($sType == "text") + $sId = "'" . $sId . "'"; + $sSql = " AND " . $sAttribute . "=" . $sId; + break; + } + return $sSql; + } + + /** + * DEPRECATED + * Méthode permettant de générer une clause SQL simple de type "IN" selon le sgbd. + * \param $sSchema Schema de la base de données + * \param $sAttribute Attribut. + * \param $sId Valeurs de l'attribut. + */ + function AddInClause($sSchema, $sAttribute, $sId) { + switch ($this->sgbd) { + case 'mysql' : + // Vide + break; + case 'pgsql' : + if (substr_count($sAttribute, '.') != 1) { + $sAttribute = '"' . $sAttribute . '"'; + } else { + $sSchema = "\"" . $sSchema . "\""; + $sAttribute = $sSchema . ".\"" . str_replace(".", "\".\"", $sAttribute) . "\""; + } + break; + case 'oci' : + // Vide + break; + } + $sSql = $sAttribute . " IN (" . $sId . ")"; + return $sSql; + } + + /** + * Selon executeWithParams + * Méthode permettant de générer une clause SQL simple de type "IN" selon le sgbd. + * \param $sSchema Schema de la base de données + * \param $sAttribute Attribut. + * \param $sId Valeurs de l'attribut. + */ + function AddInClauseWithParams($sSchema, $sAttribute, $sId) { + switch ($this->sgbd) { +// case 'mysql' : +// // Vide +// break; + case 'pgsql' : + + $aAttributs = explode('.', $sAttribute); + + // Si le schema est ou pas défini dans sAttribute + if (count($aAttributs) === 1) { + + $sColumnKey = 'column_' . vitisUniqId(); + $sValueKey = 'value_' . vitisUniqId(); + + $sSql = '"[' . $sColumnKey . ']" IN ([' . $sValueKey . '])'; + $aSQLParams = array( + $sColumnKey => array('type' => 'column_name', 'value' => $aAttributs[0]), + $sValueKey => array('type' => 'group', 'value' => $sId) + ); + } else if (count($aAttributs) === 2) { + + $sSchemaKey = 'schema_' . vitisUniqId(); + $sColumnKey = 'column_' . vitisUniqId(); + $sValueKey = 'value_' . vitisUniqId(); + + $sSql = '"[' . $sSchemaKey . ']"."[' . $sColumnKey . ']" IN ([' . $sValueKey . '])'; + $aSQLParams = array( + $sSchemaKey => array('type' => 'column_name', 'value' => $aAttributs[0]), + $sColumnKey => array('type' => 'column_name', 'value' => $aAttributs[1]), + $sValueKey => array('type' => 'group', 'value' => $sId) + ); + } + break; +// case 'oci' : +// // Vide +// break; + } + return array( + 'sql' => $sSql, + 'params' => $aSQLParams + ); + } + + /** + * DEPRECATED + * Méthode qui renvoie une chaine formatée pour pouvoir étre utilisé dans un requête insert, update ou select. + * \param $sValue Chaine qui va doit être formatée. + * \param $sType Type de l'attribut. + * \param $sSchema Schema contenant la table dont est issu le champ à traiter (vide par défaut). + * \param $sTable Table dont est issu le champ à traiter (vide par défaut). + */ + function formatForSql($sValue, $sType, $sSchema = "", $sTable = "") { + + // Gestion du type spatiale + switch ($this->sgbd) { + case "pgsql" : + if (($sType === "geometry") && ($sValue !== "")) { + $iTableDimension = $this->getTableDimension($sTable, $sSchema); + $sForce3DDebut = ""; + $sForce3DFin = ""; + if ($iTableDimension == 3) { + $sForce3DDebut = "st_force_3d("; + $sForce3DFin = ")"; + } + $sOriginTable = $this->ifTableIsAView($sTable, $sSchema); + if ($sOriginTable != $sTable) { + $sTable = $sOriginTable; + $sOriginSchema = $this->getTableSchema($sTable); + if ($sOriginSchema != $sSchema) + $sSchema = $sOriginSchema; + } + // Si il s'agit de format EWKT, alors on connait la projection de la géométrie. On peut alors procéder à une reprojection automatique des données + if ($this->isEWKTFormat($sValue)) { + $sValue = $sForce3DDebut . "ST_transform(ST_GeomFromEWKT('" . $sValue . "'), " . $this->getTableSRID($sTable, $sSchema) . ")" . $sForce3DFin; + } else { + $sValue = $sForce3DDebut . "st_geometryFromText('" . $sValue . "'," . $this->getTableSRID($sTable, $sSchema) . ") " . $sForce3DFin; + } + } else { + $sValue = str_replace("'", "''", $sValue); + //$sValue = str_replace("\\", "\\\\", $sValue); + //$sValue = str_replace("\\\\\\''", "\\\\\\\\\\\\'", $sValue); + } + + break; + } + // Gestion des types alphanumériques + if ($sValue === "") { + $sValue = "null"; + } else { + switch ($sType) { + case ($sType == "BLOB" || $sType == "bool"): + if ($sValue == "") + $sValue = 0; + case ($sType == "bpchar" || $sType == "DATE" || $sType == "varchar" || $sType == "VARCHAR2" || $sType == "VAR_STRING" || $sType == "text" || $sType == "timestamp"): + if ((empty($sValue) && $sValue != 0) || $sValue == "") { + $sValue = "null"; + } else { + $sValue = "'" . $sValue . "'"; + } + break; + case ($sType == "date" || $sType == "DATETIME" || $sType == "timestamptz"): + $sValue = "'" . implode("-", array_reverse(explode("/", $sValue))) . "'"; + break; + default: + if ($sValue == "") + $sValue = "null"; + break; + } + } + // Cas particulier : le booléen 'faux' dans PostgreSQL + if ($sType == "bool" && $this->sgbd == "pgsql" && $sValue == "null") + $sValue = "false"; + return $sValue; + } + + /** + * Méthode qui renvoie une chaine formatée pour pouvoir étre utilisé dans un requête insert, update ou select. + * \param $sValue Chaine qui va doit être formatée. + * \param $sType Type de l'attribut. + * \param $sSchema Schema contenant la table dont est issu le champ à traiter (vide par défaut). + * \param $sTable Table dont est issu le champ à traiter (vide par défaut). + */ + function formatForSqlWithParams($sValue, $sField, $sType, $sSchema = "", $sTable = "") { + + $sFieldKey = $sField . '_' . vitisUniqId(); + + switch ($this->sgbd) { + case "pgsql" : + if (($sType === "geometry") && ($sValue !== "")) { + $iColumnDimension = $this->getColumnDimension($sSchema, $sTable, $sField); + $sForce3DDebut = ""; + $sForce3DFin = ""; + // Projection + $sSRID = $this->getColumnSRID($sSchema, $sTable, $sField); + if ($sSRID == "0") { + $sSRID = "2154"; + } + // Dimention + if ($iColumnDimension == 3) { + $sForce3DDebut = "st_force_3d("; + $sForce3DFin = ")"; + } + $sOriginTable = $this->ifTableIsAView($sTable, $sSchema); + if ($sOriginTable != $sTable) { + $sTable = $sOriginTable; + $sOriginSchema = $this->getTableSchema($sTable); + if ($sOriginSchema != $sSchema) + $sSchema = $sOriginSchema; + } + // Si il s'agit de format EWKT, alors on connait la projection de la géométrie. On peut alors procéder à une reprojection automatique des données + if ($this->isEWKTFormat($sValue)) { + $sField = $sForce3DDebut . "ST_Transform(ST_GeomFromEWKT([" . $sFieldKey . "]), " . $sSRID . ")" . $sForce3DFin; + } else { + $sField = $sForce3DDebut . "ST_GeometryFromText([" . $sFieldKey . "]," . $sSRID . ") " . $sForce3DFin; + } + } else { + $sField = '[' . $sFieldKey . ']'; + } + break; + } + + return array( + 'field' => $sField, + 'fieldKey' => $sFieldKey, + 'value' => $sValue + ); + } + + /** + * DEPRECATED + * Méthode permettant de construire une clause WHERE SQL é partir d'une liste de valeur passées en requête et avec une jointure sur une autre table. + * La table cible est spécifiée en paramètre de la méthode. + * \param $sSchema Schema de la base de données + * \param $sTable Table dans laquelle on recherche. + * \param $aValues Valeurs contenues dans la requête. + * \param $bListQuery. + * \param $sTable_sql + * \param $pKey + * \param $isWhereExist + * \return La clause WHERE de la requête SQL de recherche. + */ + function getWhereAndClause($sSchema, $sTable, $aValues, $bListQuery, $sTable_sql, $pKey, $isWhereExist = false) { + // LIKE gère tous les types de champs. + switch ($this->sgbd) { + case 'mysql' : + $sProtectField = '`'; + $sSql = $this->AddLimite(0, 1, "SELECT * FROM " . $sTable); + break; + case 'pgsql' : + $sTable = $sSchema . "." . $sTable; + $sProtectField = '"'; + $sSql = $this->AddLimite(0, 1, "SELECT * FROM " . $sTable); + break; + case 'oci' : + $sProtectField = ''; + $sSql = $this->AddLimite(0, 1, "SELECT " . $sTable . ".* FROM " . $sTable); + break; + } + $resultat = $this->execute($sSql); + + $iNumFields = $this->getFieldsNumber($resultat); + for ($i = 0; $i < $iNumFields; $i++) { + $aField["name"][$i] = $this->getFieldName($resultat, $iNumFields, $i, $sTable); + $aField["type"][$i] = $this->getType($resultat, $iNumFields, $aField["name"][$i], $sTable); + } + $sWhereClause = ""; + $sQueryList = ""; + foreach ($aValues as $sKey => $sValue) { + $i = 0; + + while ($aField["name"][$i]) { + //echo $aField["name"][$i]." ".$aField["type"][$i]."<BR>"; + if ($aField["name"][$i] == $sKey && $sValue != "") { + $sKey = addDelimitedAttribute("", $sKey, "", $sProtectField); + switch ($aField["type"][$i]) { + case (ereg("LONG|int4|NUMBER", $aField["type"][$i]) > 0) : + if ($sWhereClause == "" & !$isWhereExist) + $sWhereClause .= " WHERE " . $sTable . "." . $sKey . "::varchar LIKE '" . $sValue . "' "; + else + $sWhereClause .= " AND " . $sTable . "." . $sKey . "::varchar LIKE '" . $sValue . "' "; + if ($bListQuery) + $sQueryList .= $sKey . "=" . $sValue . " & "; + break; + case 'bool' : + if ($sValue == '1') + $sValue = 'TRUE'; + if ($sValue == '0') + $sValue = 'FALSE'; + if ($sWhereClause == "" & !$isWhereExist) + $sWhereClause .= " WHERE " . $sTable . "." . $sKey . " = " . $sValue . " "; + else + $sWhereClause .= " AND " . $sTable . "." . $sKey . " = " . $sValue . " "; + if ($bListQuery) + $sQueryList .= $sKey . "=" . $sValue . " & "; + break; + //case "datetime" || "timestamp" : + case (ereg("DATE|date", $aField["type"][$i]) > 0) : + $sValue = substr($this->formatForSql($sValue, $aField["type"][$i]), 1, -1); + if ($this->sgbd === "oci") + $sFunction = "TO_CHAR(" . $sTable . "." . $sKey . ", 'DD/MM/YYYY')"; + default : + if (!empty($sFunction)) { + if ($sWhereClause == "" & !$isWhereExist) + $sWhereClause .= " WHERE " . $sFunction . " LIKE '%" . $sValue . "%' "; + else + $sWhereClause .= " AND " . $sFunction . " LIKE '%" . $sValue . "%' "; + }else { + if ($sWhereClause == "" & !$isWhereExist) + $sWhereClause .= " WHERE " . $sTable . "." . $sKey . " LIKE '%" . $sValue . "%' "; + else + $sWhereClause .= " AND " . $sTable . "." . $sKey . " LIKE '%" . $sValue . "%' "; + } + if ($bListQuery) + $sQueryList .= $sKey . "='" . $sValue . "' & "; + break; + } + $sWhereClause .= " AND " . $sTable . "." . $pKey . " = " . $sTable_sql . "." . $pKey; + } + + $i++; + } + } + $resultat = $this->fermeResultat(); + if ($sQueryList != "") + $sQueryList = substr($sQueryList, 0, -3); + return array("WhereClause" => $sWhereClause, "QueryList" => $sQueryList); + } + +// Fin de la classe +} + +?> diff --git a/vas/rest/class/vmlib/BdDataAccess.inc b/vas/rest/class/vmlib/BdDataAccess.inc new file mode 100755 index 0000000000000000000000000000000000000000..c719389b38d80d77ee63d0f302648e0fc53124e3 --- /dev/null +++ b/vas/rest/class/vmlib/BdDataAccess.inc @@ -0,0 +1,20 @@ +<?php + +/* + * + * BdDataAccess.inc : + * + */ + +switch ($properties["sgbd"]) { + case "mysql" : + require_once("vmlib/MysqlDataAccess.class.inc"); + break; + case "pgsql" : + require_once(__DIR__ . "/PgsqlDataAccess.class.inc"); + break; + case "oci" : + //require_once("vmlib/OciDataAccess.class.inc"); + break; +} +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/Email.class.inc b/vas/rest/class/vmlib/Email.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..509b60691830e6382bdddb1c7dee04aaff7cb9a0 --- /dev/null +++ b/vas/rest/class/vmlib/Email.class.inc @@ -0,0 +1,328 @@ +<?php + +require_once ("vmlib/logUtil.inc"); +//require_once ("PEAR/Mail.php"); +//require_once ("PEAR/Mail/mime.php"); +require_once ("vmlib/EmailTemplate.class.inc"); + +require_once 'vmlib/error.inc'; + +use PHPMailer\PHPMailer\PHPMailer; +use PHPMailer\PHPMailer\Exception; + +require_once 'PHPMailer/src/Exception.php'; +require_once 'PHPMailer/src/PHPMailer.php'; +require_once 'PHPMailer/src/SMTP.php'; + +class Email { + + protected $to; + protected $cc; + protected $cci; + protected $subject; + protected $body; + protected $bUseHTML; + protected $aAttachments; + protected $mimeVersion = '1.0'; + protected $contentType = 'text/html; charset=utf-8'; + protected $from; + protected $replyTo; + protected $xMailer; + protected $date; + protected $aObjects; + protected $aProperties; + protected $oBd; + public $oEmailTemplate; + public $aValues; + protected $logFileName; + + /* * **************************************************** + + * **************************************************** */ + /** + *@construct + *@param $oBd Database access object + *@param $iEmailTemplateId ID of the template + *@param $aProperties Properties of the application + *@param aObjects Object that initialyze the sending + *@todo Si vous utilisez cette classe avec chargement par mailStruct : $oBd = null, $iEmailTemaplteId = null, $aObjects = null + */ + function __construct($oBd, $iEmailTemplateId, $aProperties, $aObjects) { + //error_log("contructor start"); + $this->oBd = $oBd; + $this->aProperties = $aProperties; + $this->aObjects = $aObjects; + $this->xMailer = array('PHP/' => phpversion()); + //$this->from = $this->aProperties['nickname_sender'] . '<' . $this->aProperties['mail_sender'] . '>'; + //$this->replyTo = '<>'; + //$this->date = date("D, j M Y H:i:s "); + $this->aValues = array(); + $this->bUseHTML = true; + //error_log("before if"); + if(isset($this->aProperties['mail_log_file'])){ + //error_log("if1.1"); + $this->logFileName = $this->aProperties['mail_log_file']; + } else if (!isset($this->aProperties['mail_log_file']) && isset($this->aProperties['error_log_file'])){ + //error_log("if1.2"); + $this->logFileName = $this->aProperties['error_log_file']; + } else { + //error_log("if1.3"); + $this->logFileName = $properties['log_dir'] . "/mail.log"; + } + //error_log("before if 2"); + if (!empty($iEmailTemplateId)) { + //error_log("if2"); + $this->loadFromMailTemplate($iEmailTemplateId); + } + //error_log("contructor end"); + } + + /* * **************************************************** + Envoi un email. + /Retour : message + * **************************************************** */ + + /* function send() { + $sErrorMessage = ''; + $crlf = ""; // \n + // + $oMime = new Mail_mime(array('eol' => $crlf)); + // Pièce jointe ? + if (is_array($this->aAttachments) && !empty($this->aAttachments)) { + foreach ($this->aAttachments as $sAttachment) { + if (file_exists($sAttachment)) + $oMime->addAttachment($sAttachment, 'application/octet-stream'); + } + } + // + $oMime->setHTMLBody('<html><body>' . $this->body . '</body></html>'); + $aMimeParams = array( + 'text_encoding' => '7bit', + 'text_charset' => 'UTF-8', + 'html_charset' => 'UTF-8', + 'head_charset' => 'UTF-8' + ); + $sBody = $oMime->get($aMimeParams); + // + $aHeaders = array( + 'From' => $this->from, + 'Date' => $this->date, + 'To' => $this->to, + 'Subject' => $this->subject, + 'cc' => $this->cc, + ); + $aHeaders = $oMime->headers($aHeaders); + // + $oMail = new Mail(); + $aSmtp = $oMail->factory('smtp', array( + 'host' => $this->aProperties["smtp_host"], + 'port' => $this->aProperties["smtp_port"], + 'auth' => $this->aProperties["smtp_authentification"], + 'username' => $this->aProperties["smtp_login"], + 'password' => $this->aProperties["smtp_password"])); + // + if ($this->to != '') { + $sDestinataire = $this->to; + if (!empty($this->cc)) + $sDestinataire .= ',' . $this->cc; + if (!empty($this->cci)) + $sDestinataire .= ',' . $this->cci; + $sMail = $aSmtp->send($sDestinataire, $aHeaders, $sBody); + if (PEAR::isError($sMail)) { + writeToErrorLog(ERROR_0023 . $this->to . '.'); + writeToErrorLog("Error message : " . $sMail->getMessage() . "."); + writeToLog("Failed sending email to the following address : " . $this->to . ' et ' . $this->cc, $this->aProperties['mail_log_file']); + writeToLog("Error message : " . $sMail->getMessage() . '.', $this->aProperties['mail_log_file']); + $sErrorMessage = $sMail->getMessage(); + } else + writeToLog("|INFORM|PHP| An email has been sent to the following address : $sDestinataire", $this->aProperties['mail_log_file']); + } + // + return $sErrorMessage; + } */ + + /** + *Load an email from an external structure. + *@param $aMailstruct Structure of the email. + * $aMailstruct = [ + * 'to' => (string) comma separated, + * 'cc' => (string) comma separated, + * 'cci' => (string) comma separated, + * 'subject' => (string) + * 'body' => (string) + * 'aAttachments' => (array) <path|string> + * 'bUseHTML' => (boolean) if not explicit is true + * ] + * + */ + function loadFromExernalDataStruct($aMailstruct) { + //error_log(print_r("start", true)); + //$this->to = $aMailstruct["to"]; + //$this->cc = $aMailstruct["cc"]; + //$this->cci = $aMailstruct["cci"]; + $this->subject = $aMailstruct["subject"]; + $this->body = $aMailstruct["body"]; + $this->aAttachments = $aMailstruct["aAttachments"]; + + if(isset($aMailstruct["bUseHTML"])){ + $this->bUseHTML = $aMailstruct["bUseHTML"]; + } + + $aMailstruct["to"] = str_replace(chr(13), ',', $aMailstruct["to"]); + $aMailstruct["cc"] = str_replace(chr(13), ',', $aMailstruct["cc"]); + $aMailstruct["cci"] = str_replace(chr(13), ',', $aMailstruct["cci"]); + $this->to = str_replace(';', ',', $aMailstruct["to"]); + $this->cc = str_replace(';', ',', $aMailstruct["cc"]); + $this->cci = str_replace(';', ',', $aMailstruct["cci"]); + //error_log(print_r("end", true)); + } + + /** + *Load an email from a template gtf. + *@param $iTemplateId Id of the template + */ + function loadFromMailTemplate($iTemplateId) { + require_once("gtf_lib/gtf_object/Order.class.inc"); + $this->oEmailTemplate = new EmailTemplateLib($this->oBd, $iTemplateId, $this->aProperties, $this->aObjects); + if (!empty($this->oEmailTemplate->name)) { + if (!empty($this->aObjects)) { + // Si édition simple : génère le code de l'email + if (!$this->oEmailTemplate->use_advanced) + $this->oEmailTemplate->code = $this->oEmailTemplate->generateCode(); + // + eval($this->oEmailTemplate->code); + } + $this->to = str_replace(chr(13), ',', $this->to); + $this->cc = str_replace(chr(13), ',', $this->cc); + $this->cci = str_replace(chr(13), ',', $this->cci); + $this->to = str_replace(';', ',', $this->to); + $this->cc = str_replace(';', ',', $this->cc); + $this->cci = str_replace(';', ',', $this->cci); + } + } + + /** + * Send an email. + * @return $sErrorMessage Le message d'erreur + */ + function send() { + $mail = new PHPMailer(null); // create instance with try catch + $sErrorMessage = null; + + $mail->isSMTP(); // Set mailer to use SMTP + //$mail->SMTPDebug = 3; // debugger level (3 all with connection) + $mail->Debugoutput = function($str, $level) { + error_log("debug level $level; message: $str"); + }; + $mail->Host = $this->aProperties["smtp_host"]; // Specify main and backup SMTP servers + $mail->Port = $this->aProperties["smtp_port"]; // TCP port to connect to + $mail->SMTPAuth = $this->aProperties["smtp_authentification"]; // Enable SMTP authentication + // if authentication add parameter to connect SMTP + if ($this->aProperties["smtp_authentification"] === true) { + $mail->AuthType = 'LOGIN'; + $mail->Username = $this->aProperties["smtp_login"]; // SMTP username + $mail->Password = $this->aProperties["smtp_password"]; // SMTP password + $mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted (deprecated) + } + //error_log("defintion mail"); + $mail->SetFrom($this->aProperties['mail_sender'], $this->aProperties['nickname_sender']); + //error_log("sender"); + //error_log(print_r($this->to, true)); + // add recipients + $aTo = array($this->to); + //error_log("br1"); + if(strpos($this->to, ",") !== false){ + //error_log("br2"); + $aTo = explode(",", $this->to); + } + //error_log(print_r($aTo, true)); + if (is_array($aTo) && !empty($aTo)) { + foreach ($aTo as $sTo) { + $mail->AddAddress($sTo); + } + } + //error_log("to"); + // add copy recipient + $aCC = array($this->cc); + if(strpos($this->cc, ",") !== false){ + $aCC = explode(",", $this->cc); + } + if (is_array($aCC) && !empty($aCC)) { + foreach ($aCC as $sCC) { + $mail->AddCC($sCC); + } + } + //error_log("cc"); + // add CCI recipient + $aCCI = array($this->cci); + if(strpos($this->cci, ",") === false){ + $aCCI = explode(",", $this->cci); + } + if (is_array($aCCI) && !empty($aCCI)) { + foreach ($aCCI as $sCCI) { + $mail->AddBCC($sCCI); + } + } + //error_log("cci"); + $mail->AddReplyTo($this->aProperties["mail_sender"], $this->aProperties["nickname_sender"]); + + $mail->IsHTML($this->bUseHTML); // Set email format to HTML + $mail->CharSet = 'UTF-8'; + + $mail->Subject = $this->subject; + //error_log("subject"); + if($this->bUseHTML){ + $this->body = '<html><body>' . $this->body . '</body></html>'; + } + + $mail->Body = /* utf8_decode */($this->body); + //error_log("body"); + // Pièce jointe ? + if (is_array($this->aAttachments) && !empty($this->aAttachments)) { + foreach ($this->aAttachments as $sAttachment) { + if (file_exists($sAttachment)) { + //$mail->addAttachment($path, $name, $encoding = 'base64', $type = 'application/octet-stream'); + $mail->addAttachment($sAttachment); + } + } + } + //error_log("pj"); + // Depuis PHP 5.6 -> vérification du certificat SSL. + if (!$this->aProperties['proxy_check_ssl']) { + $mail->SMTPOptions = array( + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true + ) + ); + } + //error_log("send"); + // + if (!$mail->send()) { + writeToErrorLog(ERROR_0023 . $this->to . '.'); + writeToErrorLog("Error message : " . $mail->ErrorInfo); + writeToLog("|WARN|PHP|Failed sending email to the following address : " . $this->to . ' and copy to : ' . $this->cc, $this->logFileName); + $sErrorMessage = $mail->ErrorInfo; + } else { + writeToLog("|INFORM|PHP| An email has been sent to the following address : " . $this->to . ' and copy to : ' . $this->cc, $this->logFileName); + + if ($this->aProperties['SaveSentMail'] === true) { + require_once("gtf_lib/Imap.php"); + $imap = new Imap($this->aProperties['imapBotSender_host'], $this->aProperties['imapBotSender_port'], $this->aProperties['imapBotSender_login'], $this->aProperties['imapBotSender_pwd'], $this->aProperties['imapBotSender_encrypt']); + + if ($imap->isConnected() === false) { + writeToLog("|WARN|PHP| can't connect to the IMAP at hostname : " . $this->aProperties['imapBotSender_host'], $this->logFileName); + } else { + $imap->selectFolder("Sent"); + $imap->saveMessageInSent($mail->getSentMIMEMessage(), ""); + } + } + } + + return $sErrorMessage; + } + +} + +?> diff --git a/vas/rest/class/vmlib/EmailTemplate.class.inc b/vas/rest/class/vmlib/EmailTemplate.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..3665bf0be5facc4d497e1d58d3c1efa7e4ad1a12 --- /dev/null +++ b/vas/rest/class/vmlib/EmailTemplate.class.inc @@ -0,0 +1,107 @@ +<?php + +require_once("vmlib/logUtil.inc"); +require_once 'vmlib/error.inc'; + +class EmailTemplateLib { + + public $id; + public $name; + public $to; + public $cc; + public $cci; + public $subject; + public $body; + public $code; + public $use_advanced; + public $oBd; + public $context; + public $aObjects; + public $aAttachments; + public $aProperties; + + /* * **************************************************** + Récupère les paramètres du modèle de mail + \$oBd : objet PDO + \$iEmailTemplateId : id du modèle de mail + * **************************************************** */ + + function __construct($oBd, $iEmailTemplateId, $aProperties, $aObjects) { + require("EmailTemplate.class.sql.inc"); + $this->aProperties = $aProperties; + $this->aObjects = $aObjects; + // Récupère les données du modèle de mail + $sSql = $aSql[$oBd->sgbd]['getMailModel']; + $sSql = str_replace('[iEmailTemplateId]', $iEmailTemplateId, $sSql); + $sSql = str_replace('[sSchemaGtf]', $aProperties['schema_gtf'], $sSql); + $oResult = $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMsg = $oBd->getBDMessage(); + else { + if ($oBd->nombreLigne($oResult) > 0) { + $oRow = $oBd->objetSuivant($oResult); + $this->id = $oRow->email_template_id; + $this->name = $oRow->name; + $this->to = $oRow->to; + $this->cc = $oRow->cc; + $this->cci = $oRow->cci; + $this->subject = $oRow->subject; + $this->body = $oRow->body; + $this->code = $oRow->code; + $this->use_advanced = $oRow->use_advanced; + $this->oBd = $oBd; + $this->context = $oRow->rt_emailcontext_id; + } else + $sErrorMsg = str_replace('[iEmailTemplateId]', $iEmailTemplateId, ERROR_0024); + } + if (isset($sErrorMsg)) + writeToErrorLog($sErrorMsg); + } + + /* * ***************************************************** + Génère le code php correspondant à l'édition simple. + /Return : Code php (string) + * ***************************************************** */ + + function generateCode($bUseAdvanced = false) { + $sMailModelCode = ''; + if (!$bUseAdvanced) { + // Edition simple (récupère la valeur des balises) + require 'vmlib/context/' . $this->context . '.inc'; + } else { + // Edition avancée (récupère la syntaxe du code des balises) + $sMailContextCode = file_get_contents('vmlib/context/' . $this->context . '.inc', true); + preg_match_all('/=.+;/', $sMailContextCode, $aTagCode); + foreach ($aTagCode[0] as $iIndex => $sTagCode) { + $sTagCode = trim(substr($sTagCode, 1, strlen($sTagCode) - 2)); + if (preg_match('/^[^\'"]/', $sTagCode) === 1) + $sMailContextCode = str_replace($sTagCode, "'" . str_replace("'", "\'", $sTagCode) . "'", $sMailContextCode); + } + $sMailContextCode = preg_replace("/'{2,}/", "'", $sMailContextCode); + $sMailContextCode = str_replace(array('<?php', '?>'), '', $sMailContextCode); + eval($sMailContextCode); + } + // Remplace toutes les balises par les valeurs du fichier de contexte. + if (!empty($properties)) { + foreach ($properties as $sIndex => $aValues) + $aContextTag[$sIndex] = $aValues['value']; + $aEmailParameter = array('to', 'cc', 'cci', 'subject', 'body'); + foreach ($aEmailParameter as $sEmailParameter) { + $sEmailParameterValue = str_replace("'", "\'", $this->$sEmailParameter); + foreach ($aContextTag as $sTag => $sValue) { + if ($bUseAdvanced) { + if (substr($sValue, 0, 1) == '$') + $sValue = "' . $sValue . '"; + $sEmailParameterValue = str_replace("[$sTag]", $sValue, $sEmailParameterValue); + } else + $sEmailParameterValue = str_replace("[$sTag]", str_replace("'", "\'", $sValue), $sEmailParameterValue); + } + $sMailModelCode .= '$this->' . $sEmailParameter . ' = \'' . $sEmailParameterValue . '\';' . PHP_EOL; + } + } + return $sMailModelCode; + } + +} + +?> diff --git a/vas/rest/class/vmlib/EmailTemplate.class.sql.inc b/vas/rest/class/vmlib/EmailTemplate.class.sql.inc new file mode 100755 index 0000000000000000000000000000000000000000..daf314cda9dcb7f54aa6bc5a4d88d44a13b262c5 --- /dev/null +++ b/vas/rest/class/vmlib/EmailTemplate.class.sql.inc @@ -0,0 +1,4 @@ +<?php + +$aSql['pgsql']['getMailModel'] = "SELECT * FROM [sSchemaGtf].email_template WHERE email_template_id = '[iEmailTemplateId]'"; +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/Ldap.class.inc b/vas/rest/class/vmlib/Ldap.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..71af099959946ec546c30ea578451d61a49e95f2 --- /dev/null +++ b/vas/rest/class/vmlib/Ldap.class.inc @@ -0,0 +1,276 @@ +<?php + +/** + * \file Ldap.class.inc + * \brief Ldap.class.inc \n \n Ce fichier contient la classe php Ldap. + * + * Cette classe permet de cr�er une connexion � l'annuaire Ldap et contient plusieurs m�thodes (recherche, gestion du message d'erreur). + * + * \author Fabien Marty <fabien.marty@veremes.com> + * \author Nicolas Chazeau <nicolas.chazeau@veremes.com> + */ + +/** + * \class Ldap + * \brief Ldap Class \n \n Ldap est une classe PHP qui permet de cr�er une connexion � l'annuaire Ldap . + * + * Cette classe permet de cr�er une connexion � l'annuaire Ldap et contient plusieurs m�thodes (recherche, gestion du message d'erreur). + * + * \author Fabien Marty <fabien.marty@veremes.com> + * \author Nicolas Chazeau <nicolas.chazeau@veremes.com> + */ +class Ldap { + /* + * Variable globale stockant le nom de dossier lib. + */ + + var $sFolderLib = "vmlib"; + + /** + * Objet connexion en cours au serveur. + */ + var $oConnexion; + + /** + * Message � afficher. + */ + var $sMessage = ""; + + /** + * Bool�en, permet de savoir si une erreur � �t� rencontr�e. + */ + var $bErreurRencontree = false; + + /** + * Identifiant de l'utilisateur. + */ + var $sLogin; + var $lang; + + /** + * \param $sLogin Identifiant de l'utilisateur. + * \param $sMotDePasse Mot de passe de l'utilisateur. + * \param $sDomaine Nom de domaine. + * \param $sServeur Nom ou IP du serveur utilis�. + */ + function __construct($sLogin, $sMotDePasse, $sDomaine, $sServeur, $sPageEncoding = "ISO-8859-1", $lang = "fr") { + $this->lang = $lang; + loadLang($this->sFolderLib, $this->lang); + $this->sLogin = $sLogin; + + // connecxion au serveur ldap + $this->oConnexion = ldap_connect($sServeur); + ldap_set_option($this->oConnexion, LDAP_OPT_PROTOCOL_VERSION, 3); + if ($this->oConnexion) { + @$oLdapbind = ldap_bind($this->oConnexion, $sDomaine . "\\" . $sLogin, $sMotDePasse); + if (!$oLdapbind) { + //Test utilisateur Active Directory + $sErrorMessage = ERROR_USER_NOT_FOUND_LDAP; + $sErrorMessage = $this->setEncodeLdapMessage($sErrorMessage); + $sErrorMessage = str_replace("[LOGIN]", $this->sLogin, $sErrorMessage); + $this->setLdapMessage($sErrorMessage); + $this->bErreurRencontree = true; + } + } else { + //Test connection Active Directory + $sErrorMessage = ERROR_CONNECT_LDAP; + $this->bErreurRencontree = true; + $this->setLdapMessage($sErrorMessage); + } + } + + /** + * M�thodes permettant d'encoder la chaine ISO-8859-1 vers l'encodage du client ($this->sPageEncoding). + * \param $sMessage Message � encoder. + * \private + */ + function setEncodeLdapMessage($sMessage) { + $sEncodeLdapMessage = iconv("ISO-8859-1", $this->sPageEncoding, $sMessage) . "<br>"; + return $sEncodeLdapMessage; + } + + /** + * M�thodes pour valoriser le message � afficher. + * \param $sMessage Message � afficher. + * \private + */ + function setLdapMessage($sMessage) { + $this->sMessage .= $sMessage . "<br>"; + } + + /** + * Retourne le messsage � afficher en HTML. + * \private + * \return Le message � afficher. + */ + function getLdapMessage() { + if ($this->sMessage != "") + $sResult = USER_LABEL . $this->sLogin . "<br>" . ERROR_LABEL . $this->sMessage; + else + $sResult = ""; + return $sResult; + } + + /** + * D�connexion. + */ + function quitter() { + ldap_close($this->oConnexion); + } + + /* + * Recherche sur l'ensemble des niveaux. + * \param $sBase_dn La base DN pour le dossier. + * \param $sFilter Filtre + * \param $aAttributes Un tableau d'attributs requis, e.g. array("mail", "sn", "cn"). + * \param $iAttrsOnly Doit �tre d�fini � 1 si seuls les types des attributs sont demand�s. S'il est d�fini � 0, les types et les valeurs des attributs sont r�cup�r�s, ce qui correspond au comportement par d�faut. + * \return l'objet r�sultat de la recherche. + */ + + function search($sBaseDn, $sFilter, $aAttributes, $iAttrsOnly = 0) { + return ldap_search($this->oConnexion, $sBaseDn, $sFilter, $aAttributes, $iAttrsOnly); + } + + /* + * Recherche par niveau. + * \param $sBaseDn La base DN pour le dossier. + * \param $sFilter Filtre + * \param $aAttributes Un tableau d'attributs requis, e.g. array("mail", "sn", "cn"). + * \param $iAttrsOnly Doit �tre d�fini � 1 si seuls les types des attributs sont demand�s. S'il est d�fini � 0, les types et les valeurs des attributs sont r�cup�r�s, ce qui correspond au comportement par d�faut. + * \return l'objet r�sultat de la recherche. + */ + + function searchByLevel($sBaseDn, $sFilter, $aAttributes, $iAttrsOnly = 0) { + if ($aAttributes == array() or $aAttributes == "") { + return @ldap_list($this->oConnexion, $sBaseDn, $sFilter); + } else { + return @ldap_list($this->oConnexion, $sBaseDn, $sFilter, $aAttributes, $iAttrsOnly); + } + } + + /* + * M�thode de lecture d'un objet r�sultat d'une recherche pass� en param�tre. + * \param $oSearch R�sultat de la recherche + * \return + */ + + function getResult($oSearch) { + return ldap_get_entries($this->oConnexion, $oSearch); + } + + /* + * M�thode permettant de compter le nombre d'entr�e d'un objet r�sultat d'une recherche pass� en param�tre. + * \param $oSearch R�sultat de la recherche + * \return un entier + */ + + function countResult($oSearch) { + return ldap_count_entries($this->oConnexion, $oSearch); + } + + /* + * M�thode permettant de r�cup�rer les groupe d'un utilisateur Ldap. + * \param $ldap_serveur Adresse IP du serveur + * \param $ldap_baseRecherche Base de recherche dans l'Active Directory + * \param $ldap_userConnexion Utilisateur de l'Active Directory + * \param $ldap_passwordConnexion Mot de passe de l'utilisateur de l'Active Directory + * \param $ldap_user Utilisateur de l'Active Directory + * \param $ldap_attributUtilisateur Attribut LDAP portant le nom de l'utilisateur + * \param $ldap_attributGroupe Attribut LDAP portant le nom du groupe + * \return la fin de la clause where + */ + + // FONCTION UTILISEE POUR GTF (projet EDGAR) + + /* + function whereUserGroup($ldap_serveur,$ldap_baseRecherche,$ldap_userConnexion,$ldap_passwordConnexion,$ldap_user,$ldap_attributUtilisateur,$ldap_attributGroupe, $sUserPrefixe="", $sUserSuffixe="", $oBd="", $sldap_allUserGroup="") { + define('LDAP_HOST',$ldap_serveur); // Serveur AD + define('LDAP_DN',$ldap_baseRecherche);// DN de base pour la recherche + + //Connexion au serveur LDAP + $ldap = ldap_connect(LDAP_HOST) or die(ERROR_CONNECT_LDAP); + + if ($ldap) { + if ($oBd!=""){ + $sBaseEncoding=$oBd->getSourceEncoding(); + //Le login ainsi que le mot de passe est encod� dans l'encodage de l'AD du client (encodage en ISO-8859-1) pour permettre de r�cup�rer les groupes de l'utilisateur dans l'AD + $ldap_userConnexion=iconv($sBaseEncoding,"ISO-8859-1",$ldap_userConnexion); + $ldap_passwordConnexion=iconv($sBaseEncoding,"ISO-8859-1",$ldap_passwordConnexion); + $ldap_user=iconv($sBaseEncoding,"ISO-8859-1",$ldap_user); + } + + //Connexion au serveur LDAP + $ldapbind = ldap_bind($ldap, $sUserPrefixe.$ldap_userConnexion.$sUserSuffixe, $ldap_passwordConnexion); + if ($ldapbind) { + // Une fois connect�, on v�rifie si l'ensemble des utilisateurs de l'AD sont associ� � un ou plusieurs groupes + //(ex : tous les utilisateurs de l'AD sont associ� au groupe "Domaine User"... comme au cg67) + $sWhereAllUserGroup=""; + if ($sldap_allUserGroup!=""){ + $aldap_allUserGroup=explode("|",$sldap_allUserGroup); + $j==0; + foreach ($aldap_allUserGroup as $sAllUserGroup) { + if ($j==0){ + $sWhereAllUserGroup="groupe.groupe=SimpleQuote".$sAllUserGroup."SimpleQuote"; + }else{ + $sWhereAllUserGroup.=" or groupe.groupe=SimpleQuote".$sAllUserGroup."SimpleQuote"; + } + $j++; + } + } + + //$ldap_attributUtilisateur est le nom de l'attribut LDAP portant le nom de l'utilisateur + $filter = "(".$ldap_attributUtilisateur."=".$ldap_user.")"; + //$ldap_attributGroupe est le nom de l'attribut LDAP portant le nom du groupe (il y en a plusieurs, un par groupe) + $attrs = array($ldap_attributGroupe); + $result = ldap_search($ldap, LDAP_DN, $filter, $attrs); + $entries = ldap_get_entries($ldap, $result); + + //Le nom de l'�l�ment du groupe est en minuscule dans le tableau "entries" g�n�r� + $ldap_attributGroupe=strtolower($ldap_attributGroupe); + $i=0; + $bEntreForeach=false; + $sWhereUserGroup=""; + foreach ($entries[0][$ldap_attributGroupe] as $sMemberOf) { + $asMemberOf=explode(",",$sMemberOf); + $asMemberOfGroupe=explode("=",$asMemberOf[0]); + $sGroupe=$asMemberOfGroupe[1]; + + //Quand il est �gal � 0 $asMemberOfGroupe[1] est vide car le 1er �l�ment du tableau "$entries[0]["memberof"]" correspond au norbre de r�sultat trouv�. + if ($i==1){ + if ($sWhereAllUserGroup!=""){ + $sWhereUserGroup="and (".$sWhereAllUserGroup." or groupe.groupe=SimpleQuote".$sGroupe."SimpleQuote"; + }else{ + $sWhereUserGroup="and (groupe.groupe=SimpleQuote".$sGroupe."SimpleQuote"; + } + + }else{ + $sWhereUserGroup.=" or groupe.groupe=SimpleQuote".$sGroupe."SimpleQuote"; + } + $bEntreForeach=true; + $i++; + } + if ($bEntreForeach==true){ + $sWhereUserGroup.=")"; + }else{ + if ($sWhereAllUserGroup!=""){ + $sWhereUserGroup="and (".$sWhereAllUserGroup.")"; + } + } + if ($sWhereUserGroup!=""){ + $sWhereUserGroup = str_replace("'", "''", $sWhereUserGroup); + $sWhereUserGroup = str_replace("SimpleQuote", "'", $sWhereUserGroup); + $sWhereUserGroup = $this->setEncodeLdapMessage($sWhereUserGroup); + $sWhereUserGroup = str_replace("<br>", "", $sWhereUserGroup); + } + } else { + writeToErrorLog(ERROR_LDAP_FAILED); + } + }else { + writeToErrorLog(ERROR_LDAP_FAILED); + } + return $sWhereUserGroup; + } + */ +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/PgsqlDataAccess.class.inc b/vas/rest/class/vmlib/PgsqlDataAccess.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..c166072dca40d81023446f4b8ddffc1536bf3c36 --- /dev/null +++ b/vas/rest/class/vmlib/PgsqlDataAccess.class.inc @@ -0,0 +1,497 @@ +<?php + +/** + * \file PgsqlDataAccess.class.inc + * \brief PgsqlDataAccess.class.inc \n \n Ce fichier contient la classe php PgsqlDataAccess + * + * Cette classe permet la gestion des utilisateurs PostgreSQL. + * + * Elle permet de créer un utilisateur un niveau du noyau PostgreSQL, mais aussi + * d'attribuer différents niveaux de droits à cet utilisateur sur une base de données distincte : + * + * \li Utilisateur simple (sélection). + * \li Administrateur (sélection, mise à jour, suppression) + * + * Avec cette classe, la gestion des utilisateurs se fait toujours au niveau du noyau PostgreSQL. + * + * \author Frédéric Mauro + * \author Fabien Marty <fabien.marty@veremes.com> + */ + +/** + * \class PgsqlDataAccess + * \brief PgsqlDataAccess Class \n \n PgsqlDataAccess est une classe PHP qui permet de récuperer des Meta données du noyau PostgreSQL. + * + * Cette classe permet la gestion des utilisateurs PostgreSQL. + * + * Elle permet de créer un utilisateur un niveau du noyau PostgreSQL, mais aussi + * d'attribuer différents niveaux de droits à cet utilisateur sur une base de données distincte : + * + * \li Utilisateur simple (sélection). + * \li Administrateur (sélection, mise à jour, suppression) + * + * Avec cette classe, la gestion des utilisateurs se fait toujours au niveau du noyau PostgreSQL. + * + * \author Frédéric Mauro + * \author Fabien Marty <fabien.marty@veremes.com> + */ +class PgsqlDataAccess { + + /** + * Objet connexion à la base de données PostgreSQL. + */ + var $oBd; + + /** + * Base de données métier. + */ + var $sDatabase; + + /** + * Serveur courant. + */ + var $sServer; + + /** + * Nom des groupes d'utilisateur + */ + var $sRoleUser; + var $sRoleAdmin; + + /** + * \param $oBd Base de données noyau PostgreSQL. + * \param $sDatabase Base de données métier. + * \param $sServer IP ou Nom du serveur PostgreSQL. + * \param $sRoleUser Nom du rôle pour les droits d'utilisateur. + * \param $sRoleAdmin Nom du rôle pour les droits d'administration. + * \param $sSchema Nom du schéma ou sont stockées les tables. + */ + function __construct($oBd, $sDatabase, $sServer, $sRoleUser = "veremap_pro_user", $sRoleAdmin = "veremap_pro_admin", $sSchema = "veremap_pro") { + $this->oBd = $oBd; + $this->sDatabase = $sDatabase; + $this->sServer = $sServer; + $this->sRoleUser = $sRoleUser; + $this->sRoleAdmin = $sRoleAdmin; + $this->sSchema = $sSchema; + } + + /** + * Cette méthode recherche quel est le statut PostgreSQL de l'utilisateur à gérer. + * \param $sLogin Identifiant de l'utilisateur à gérer. + * \return Le statut de l'utilisateur à gérer. + */ + function getStatus($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT * FROM pg_user s LEFT OUTER JOIN pg_group g on (s.usesysid = any(g.grolist) ) WHERE usename='" . $sLogin . "' and groname IN ('" . $this->sRoleUser . "', '" . $this->sRoleAdmin . "')"; + $iRecordset = $oBd->execute($sSql); + $aResultat = $iRecordset->fetchAll(PDO::FETCH_ASSOC); + if ($aResultat == array()) + return "unknown"; + $sStatut = ""; + foreach ($aResultat as $aLigne) { + if ($aLigne['usesuper'] == true || $aLigne['groname'] == $this->sRoleAdmin) + return "database_admin"; + else + if ($aLigne['groname'] == $this->sRoleUser) + $sStatut = "database_user"; + else + if ($sStatut == "") + $sStatut = "sgbd_only"; + } + return $sStatut; + } + + /** + * Cette méthode tente de créer un utilisateur PostgreSQL. + * \param $sLogin Identifiant de l'utilisateur à créer. + * \param $sPassword Mot de passe de l'utilisateur à créer. + * \return Un message d'erreur s'il y a lieu. + */ + function createSgbdUser($sLogin, $sPassword) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $sErrorMessage = ""; + $sSql = "select * from pg_user where usename = [LOGIN]"; + $aParams = array(); + $aParams['LOGIN'] = array('value' => utf8_encode($sLogin), 'type' => 'quoted_string'); + $resultat = $oBd->executeWithParams($sSql, $aParams); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + if (!$aLigne = $oBd->ligneSuivante($resultat)) { + $sSql = "CREATE USER [LOGIN] PASSWORD [PASSWORD] IN ROLE " . $this->sRoleUser; + $aParams = array(); + if (mb_detect_encoding($sLogin) != 'UTF-8') + $sLogin = utf8_encode($sLogin); + $aParams['LOGIN'] = array('value' => $sLogin, 'type' => 'double_quote'); + $aParams['PASSWORD'] = array('value' => 'md5' . md5($sPassword . $sLogin), 'type' => 'quoted_string'); + $oBd->executeWithParams($sSql, $aParams); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + $sSql = " GRANT vitis_user TO \"" . $sLogin . "\";"; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage = $oBd->getBDMessage(); + } + } + } + return $sErrorMessage; + } + + /** + * Cette méthode tente de créer un utilisateur PostgreSQL. + * \param $sLogin Identifiant de l'utilisateur à créer. + * \param $sPassword Mot de passe de l'utilisateur à créer. + * \return Un message d'erreur s'il y a lieu. + */ + function createSgbdUserNoPassword($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $sErrorMessage = ""; + $sSql = "select * from pg_user where usename = '" . $sLogin . "'"; + $resultat = $oBd->execute($sSql); + if ($aLigne = $oBd->ligneSuivante($resultat)) { + $sErrorMessage = $this->createDatabaseUser($sLogin); + } else { + $sSql = "CREATE USER \"" . $sLogin . "\" PASSWORD NULL IN ROLE " . $this->sRoleUser; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage = $oBd->getBDMessage(); + } + return $sErrorMessage; + } + + /** + /** + * Cette méthode tente de mettre à jour un utilisateur PostgreSQL comme utilisateur d'une nouvelle Db. + * \param $sLogin Identifiant de l'utilisateur à modifier. + * \return Un message d'erreur s'il y a lieu. + */ + function createDatabaseUser($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $sErrorMessage = ""; + $sSql = 'GRANT ' . $this->sRoleUser . ' TO "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage = $oBd->getBDMessage(); + return $sErrorMessage; + } + + /** + * Cette méthode tente de mettre à jour le mot de passe d'un utilisateur PostgreSQL. + * \param $sLogin Identifiant de l'utilisateur à modifier. + * \param $sPasword Nouveau mot de passe de l'utilisateur. + * \return Un message d'erreur s'il y a lieu. + */ + function updateUserPassword($sLogin, $sPassword) { + $oBd = $this->oBd; + $sServer = $this->sServer; + $sErrorMessage = ""; + $sSql = "ALTER Role [LOGIN] PASSWORD [PASSWORD]"; + $aParams = array(); + if (mb_detect_encoding($sLogin) != 'UTF-8') + $sLogin = utf8_encode($sLogin); + $aParams['LOGIN'] = array('value' => $sLogin, 'type' => 'double_quote'); + $aParams['PASSWORD'] = array('value' => 'md5' . md5($sPassword . utf8_encode($sLogin)), 'type' => 'quoted_string'); + $oBd->executeWithParams($sSql, $aParams); + if ($oBd->erreurRencontree) + $sErrorMessage = $oBd->getBDMessage(); + return $sErrorMessage; + } + + /** + * Cette méthode tente de supprimer un utilisateur PostgreSQL comme utilisateur d'une Db en particulier. + * \param $sLogin Identifiant de l'utilisateur à supprimer. + * \return Un message d'erreur s'il y a lieu. + */ + function deleteDatabaseUser($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $sErrorMessage = ""; + $sSql = 'REVOKE ' . $this->sRoleUser . ' FROM "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage = $oBd->getBDMessage(); + return $sErrorMessage; + } + + /** + * Cette méthode tente de mettre à jour un utilisateur PostgreSQL comme administrateur d'une nouvelle Db. + * \param $sLogin Identifiant de l'utilisateur à modifier. + * \return Un message d'erreur s'il y a lieu. + */ + function createDatabaseAdmin($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $siLoginOrUserId = intval($sLogin); + // Deprecated Juillet 2012 + // Si siLoginOrUserId renvoi 0 c'est que la valeur passée en entré est une chaine et non un entier (Compatibilité avec Veremap) + if (is_int($siLoginOrUserId) and $siLoginOrUserId <> 0) { + $sSql = 'SELECT "LOGIN" FROM ' . $this->sSchema . '."user" WHERE "USER_ID"=' . $sLogin . ''; + $resultat = $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + $oUser = $oBd->objetSuivant($resultat); + $sLogin = $oUser->LOGIN; + } + } + $sErrorMessage = ""; + $sSql = 'GRANT ' . $this->sRoleAdmin . ' TO "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage .= $oBd->getBDMessage(); + } else { + $sSql = 'ALTER ROLE "' . $sLogin . '" SUPERUSER CREATEROLE'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage .= $oBd->getBDMessage(); + } + return $sErrorMessage; + } + + /** + * Même fonction que la précédente mais pour gtf_v2 + */ + function createDatabaseAdminV2($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $siLoginOrUserId = intval($sLogin); + // Deprecated Juillet 2012 + // Si siLoginOrUserId renvoi 0 c'est que la valeur passée en entré est une chaine et non un entier (Compatibilité avec Veremap) + if (is_int($siLoginOrUserId) and $siLoginOrUserId <> 0) { + $sSql = 'SELECT "login" FROM ' . $this->sSchema . '."user" WHERE "user_id"=' . $sLogin . ''; + $resultat = $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + $oUser = $oBd->objetSuivant($resultat); + $sLogin = $oUser->login; + } + } + $sErrorMessage = ""; + $sSql = 'GRANT ' . $this->sRoleAdmin . ' TO "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage .= $oBd->getBDMessage(); + } else { + $sSql = 'ALTER ROLE "' . $sLogin . '" CREATEROLE'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage .= $oBd->getBDMessage(); + } + return $sErrorMessage; + } + + /** + * Cette méthode tente de supprimer un utilisateur PostgreSQL comme administrateur d'une Db en particulier, + * l'utilisateur redevient simple utilisateur de la base. + * \param $sLogin Identifiant de l'utilisateur à supprimer. + * \return Un message d'erreur s'il y a lieu. + */ + function deleteDatabaseAdmin($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $siLoginOrUserId = intval($sLogin); + // Deprecated Juillet 2012 + // Si siLoginOrUserId renvoi 0 c'est que la valeur passée en entré est une chaine et non un entier (Compatibilité avec Veremap) + if (is_int($siLoginOrUserId) and $siLoginOrUserId <> 0) { + $sSql = 'SELECT "LOGIN" FROM ' . $this->sSchema . '."user" WHERE "USER_ID"=' . $sLogin . ''; + $resultat = $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + $oUser = $oBd->objetSuivant($resultat); + $sLogin = $oUser->LOGIN; + } + } + $sErrorMessage = ""; + $sSql = 'REVOKE ' . $this->sRoleAdmin . ' FROM "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage .= "<br>" . $oBd->getBDMessage(); + } else { + $sSql = 'ALTER ROLE "' . $sLogin . '" NOSUPERUSER NOCREATEROLE'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) + $sErrorMessage .= "<br>" . $oBd->getBDMessage(); + } + return $sErrorMessage; + } + + /** + * Même fonction que la précédente mais pour gtf_v2 + */ + function deleteDatabaseAdminV2($sLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sServer = $this->sServer; + $siLoginOrUserId = intval($sLogin); + // Deprecated Juillet 2012 + // Si siLoginOrUserId renvoi 0 c'est que la valeur passée en entré est une chaine et non un entier (Compatibilité avec Veremap) + if (is_int($siLoginOrUserId) and $siLoginOrUserId <> 0) { + $sSql = 'SELECT "login" FROM ' . $this->sSchema . '."user" WHERE "user_id"=' . $sLogin . ''; + $resultat = $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage = $oBd->getBDMessage(); + } else { + $oUser = $oBd->objetSuivant($resultat); + $sLogin = $oUser->login; + } + } + $sErrorMessage = ""; + $sSql = 'REVOKE ' . $this->sRoleAdmin . ' FROM "' . $sLogin . '"'; + $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + $sErrorMessage .= "<br>" . $oBd->getBDMessage(); + } + return $sErrorMessage; + } + + /** + * Cette méthode permet de déterminer si l'utilisateur se connectant à l'interface d'administration en à le droit. + * \param $sSessLogin Identifiant de l'utilisateur en cours de connexion. + * \return Vrai si l'utilisateur est administrateur. + */ + function isDatabaseAdmin($sSessLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT groname FROM pg_user RIGHT JOIN pg_group ON pg_user.usesysid = ANY(grolist) WHERE usename = '" . $sSessLogin . "'"; + $iRecordset = $oBd->execute($sSql); + $bAdmin = false; + while ($aLigne = $oBd->ligneSuivante($iRecordset)) + if ($aLigne["groname"] == $this->sRoleAdmin) + $bAdmin = true; + $iRecordset = $oBd->fermeResultat(); + if ($bAdmin) + return $bAdmin; + else { + $sSql = "SELECT * FROM pg_roles WHERE rolname='" . $sSessLogin . "' AND (rolsuper = true)"; + $iRecordset = $oBd->execute($sSql); + if ($aLigne = $oBd->ligneSuivante($iRecordset)) { + $iRecordset = $oBd->fermeResultat(); + return true; + } else { + $iRecordset = $oBd->fermeResultat(); + return false; + } + } + } + + /** + * Cette méthode permet de déterminer si l'utilisateur est un utilisateur de la base. + * \param $sSessLogin Identifiant de l'utilisateur en cours de connexion. + * \return Vrai si l'utilisateur est utilisateur. + */ + function isDatabaseUser($sSessLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT groname FROM pg_user RIGHT JOIN pg_group ON pg_user.usesysid = ANY(grolist) WHERE usename = '" . $sSessLogin . "'"; + $iRecordset = $oBd->execute($sSql); + $bUser = false; + while ($aLigne = $oBd->ligneSuivante($iRecordset)) + if ($aLigne["groname"] == $this->sRoleUser) + $bUser = true; + $iRecordset = $oBd->fermeResultat(); + return $bUser; + } + + function getUserModules($sSessLogin, $modules) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $modules = "'" . str_replace(',', "','", $modules) . "'"; + $sSql = "SELECT distinct module_id FROM pg_user RIGHT JOIN pg_group ON pg_user.usesysid = ANY(grolist) inner join " . $this->sSchema . ".vm_mode_rolname ON groname = vm_mode_rolname.rolname left join " . $this->sSchema . ".vm_mode ON vm_mode_rolname.mode_id = vm_mode.mode_id WHERE usename = '" . $sSessLogin . "' and module_id IN (" . $modules . ")"; + + $iRecordset = $oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($iRecordset)) { + + $aModules[] = $aLigne['module_id']; + } + $iRecordset = $oBd->fermeResultat(); + return $aModules; + } + + function getUserModes($sSessLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT distinct mode_id, \"index\" FROM pg_user RIGHT JOIN pg_group ON pg_user.usesysid = ANY(grolist) inner join " . $this->sSchema . ".vm_mode_rolname ON groname = vm_mode_rolname.rolname WHERE usename = '" . $sSessLogin . "' order by \"index\""; + + $iRecordset = $oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($iRecordset)) { + + $aMode[] = $aLigne["mode_id"]; + } + $iRecordset = $oBd->fermeResultat(); + return $aMode; + } + + function getUserModesFramework($sSessLogin, $modules) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $modules = "'" . str_replace(',', "','", $modules) . "'"; + $sSql = "SELECT distinct module_id, vm_mode.mode_id, \"index\" FROM pg_user RIGHT JOIN pg_group ON pg_user.usesysid = ANY(grolist) inner join " . $this->sSchema . ".vm_mode_rolname ON groname = vm_mode_rolname.rolname left join " . $this->sSchema . ".vm_mode ON vm_mode_rolname.mode_id = vm_mode.mode_id WHERE usename = '" . $sSessLogin . "' and module_id IN (" . $modules . ") order by \"index\""; + + $iRecordset = $oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($iRecordset)) { + + $aMode[] = $aLigne; + } + $iRecordset = $oBd->fermeResultat(); + return $aMode; + } + + function getModeTabsFramework($aMode, $lang = 'fr') { + $sModeId = $aMode['mode_id']; + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT vm_translation.translation as label, event FROM " . $this->sSchema . ".vm_tab LEFT JOIN " . $this->sSchema . ".vm_translation ON vm_tab.label_id = vm_translation.translation_id where mode_id='" . $sModeId . "' and vm_translation.lang='" . $lang . "' order by \"index\""; + $iRecordset = $oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($iRecordset)) { + $aTab['module_id'] = $aMode['module_id']; + $aTab['tab'][] = $aLigne; + } + $iRecordset = $oBd->fermeResultat(); + + return $aTab; + } + + function getModeTabs($sMode, $lang = 'fr') { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT vm_translation.translation as label, event FROM " . $this->sSchema . ".vm_tab LEFT JOIN " . $this->sSchema . ".vm_translation ON vm_tab.label_id = vm_translation.translation_id where mode_id='" . $sMode . "' and vm_translation.lang='" . $lang . "' order by \"index\""; + + $iRecordset = $oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($iRecordset)) { + $aTab[] = $aLigne; + } + $iRecordset = $oBd->fermeResultat(); + return $aTab; + } + + function DeleteDatabaseRole($sSessLogin) { + $oBd = $this->oBd; + $sDatabase = $this->sDatabase; + $sSql = "SELECT * FROM pg_user s LEFT OUTER JOIN pg_group g on (s.usesysid = any(g.grolist) ) WHERE usename='" . $sSessLogin . "'"; + $iRecordset = $oBd->execute($sSql); + $sMessage = ""; + if ($aLigne = $oBd->ligneSuivante($iRecordset)) { + $sSql = "DROP ROLE IF EXISTS \"" . $sSessLogin . "\""; + $oPDOresult = $oBd->execute($sSql); + $sMessage = $oBd->getBDMessage(); + } + return $sMessage; + } + +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/PostgisUtil.class.inc b/vas/rest/class/vmlib/PostgisUtil.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..0fe5122e7c6e45cc609cd7a889e33d20d1a6e445 --- /dev/null +++ b/vas/rest/class/vmlib/PostgisUtil.class.inc @@ -0,0 +1,61 @@ +<?php + +require_once ("dbUtil.inc"); +require_once ("Vm.class.inc"); +require_once ("logUtil.inc"); + +class PostgisUtil { + /* + * Variable globale stockant le nom de dossier lib. + */ + + var $sFolderLib = "vmlib"; + var $oBd; + var $lang; + + function __construct($oConnection, $lang = "fr") { + $this->lang = $lang; + loadLang($this->sFolderLib, $this->lang); + $this->oBd = $oConnection; + } + + // construit un buffer de $sSize m de rayon + function getBuffer($sWkt, $sSize) { + $sSql = "SELECT st_astext(public.st_buffer(st_geomfromtext('sWkt'),sSize)) as geombuffer"; + $sSql = str_replace('sWkt', $sWkt, $sSql); + $sSql = str_replace('sSize', $sSize, $sSql); + + $oResultat = $this->oBd->execute($sSql); + if (!$this->oBd->erreurRencontree) { + $oGeomBuffer = $this->oBd->objetSuivant($oResultat); + $sGeomBuffer = $oGeomBuffer->geombuffer; + $oResultat = $this->oBd->fermeResultat(); + } else { + // traitement de l'erreur + writeToErrorLog(ERROR_REQUEST_IMPOSSIBLE . $sSql); + $oResultat = $this->oBd->fermeResultat(); + } + return $sGeomBuffer; + } + + // calcule la distance entre deux points. + function getDistance($sWkt, $sWkt2) { + $sSql = "SELECT st_distance('debut','fin') as distance"; + $sSql = str_replace('debut', $sWkt, $sSql); + $sSql = str_replace('fin', $sWkt2, $sSql); + $oResultat = $this->oBd->execute($sSql); + if (!$this->oBd->erreurRencontree) { + $oDistance = $this->oBd->objetSuivant($oResultat); + $sDistance = $oDistance->distance; + $oResultat = $this->oBd->fermeResultat(); + } else { + // traitement de l'erreur + writeToErrorLog(ERROR_REQUEST_IMPOSSIBLE . $sSql); + $oResultat = $this->oBd->fermeResultat(); + } + return $sDistance; + } + +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/Vm.class.inc b/vas/rest/class/vmlib/Vm.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..60d51d3ecc22146dc59691f5ac03574751124ed3 --- /dev/null +++ b/vas/rest/class/vmlib/Vm.class.inc @@ -0,0 +1,891 @@ +<?php + +/** + * \file Vm.class.inc + * \brief Vm.class.inc \n \n Ce fichier contient la classe php Vm. + * + * + * \author Olivier Gayte <olivier.gayte@veremes.com>. + * \author Fabien Marty <fabien.marty@veremes.com>. + * \author Armand Bahi <armand.bahi@veremes.com>. + */ +/** + * \class Vm + * \brief Vm Class \n \n + */ +require_once (__DIR__ . "/BD.class.inc"); + +class Vm extends BD { + ## ============================================ ## + ## METHODES D'INTERROGATION DU CONTENU VM_TABLE ## + ## ============================================ ## + + /** + * M�thode qui renvoie un tableau associatif contenant des informations sur la table syst�me pass�e en param�tre. + * \param $sTable Nom de la table syst�me. + * \param $sSchema Nom du sch�ma � utiliser ('veremap_pro' par d�faut). + * \return Un tableau associatif. + */ + function getVM_TableInfo($sTable, $sSchema = "veremap_pro") { + include('vmlib/Vm.class.sql.inc'); + $sSql = $aSql[$this->sgbd]['getVM_TableInfo']; + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + $resultat = $this->execute($sSql); + if ($resultat !== false) { + if (!$aValues = $this->ligneSuivante($resultat)) + $aValues = array(); + $resultat = $this->fermeResultat(); + return $aValues; + } + } + + /** + * M�thode qui renvoie un tableau associatif contenant des informations sur la table syst�me pass�e en param�tre. + * \param $sTable Nom de la table syst�me. + * \param $sSchema Nom du sch�ma � utiliser ('veremap_pro' par d�faut). + * \param $lang langue de l'application ('fr' par d�faut). + * \return Un tableau associatif. + */ + function getVM_TableInfoTrad($sTable, $sSchema = "veremap_pro", $lang = "fr") { + include('vmlib/Vm.class.sql.inc'); + $sSql = $aSql[$this->sgbd]['getVM_TableInfoTrad']; + $aTag = array("[sSchema]", "[sTable]", "[sLang]"); + $aReplacer = array($sSchema, $sTable, $lang); + $sSql = str_replace($aTag, $aReplacer, $sSql); + $resultat = $this->execute($sSql); + if ($resultat !== false) { + if (!$aValues = $this->ligneSuivante($resultat)) + $aValues = array(); + $resultat = $this->fermeResultat(); + return $aValues; + } + } + + /** + * M�thode qui renvoie un tableau associatif contenant des informations sur la table syst�me pass�e en param�tre. + * \param $sTable Nom de la table syst�me. + * \param $sSchema Nom du sch�ma � utiliser ('veremap_pro' par d�faut). + * \param $lang langue de l'application ('fr' par d�faut). + * \return Un tableau associatif. + */ + function getVM_TableInfoTradFramework($sTable, $sSchema = "veremap_pro", $lang = "fr") { + include('vmlib/Vm.class.sql.inc'); + $sSql = $aSql[$this->sgbd]['getVM_TableInfoTradFramework']; + $aTag = array("[sSchema]", "[sTable]", "[sLang]"); + $aReplacer = array($sSchema, $sTable, $lang); + $sSql = str_replace($aTag, $aReplacer, $sSql); + $resultat = $this->execute($sSql); + if ($resultat !== false) { + if (!$aValues = $this->ligneSuivante($resultat)) + $aValues = array(); + $resultat = $this->fermeResultat(); + return $aValues; + } + } + + /** + * M�thode qui renvoie un tableau associatif contenant des informations sur la couche syst�me pass�e en param�tre. + * \param $sLayer Nom de la couche syst�me. + * \param $sSchema Nom du sch�ma � utiliser ('veremap_pro' par d�faut). + * \return Un tableau associatif. + */ + function getVM_LayerInfo($sLayer, $sSchema = "veremap_pro") { + include('vmlib/Vm.class.sql.inc'); + $sSql = $aSql[$this->sgbd]['getVM_LayerInfo']; + $aTag = array("[sSchema]", "[sLayer]"); + $aReplacer = array($sSchema, $sLayer); + $sSql = str_replace($aTag, $aReplacer, $sSql); + $resultat = $this->execute($sSql); + if ($resultat !== false) { + if (!$aValues = $this->ligneSuivante($resultat)) + $aValues = array(); + $resultat = $this->fermeResultat(); + return $aValues; + } + } + + ## ============================================================ ## + ## METHODES D'INTERROGATION DES DROITS SUR LES COUCHES ## + ## ============================================================ ## + + /** + * M�thode qui renvoie un tableau associatif contenant les droits sur la couche pour un groupe pass�e en param�tre. + * \param $sLayer Nom de la couche syst�me. + * \param $iGroupId Groupe de l'utilisateur. + * \return Un tableau associatif. + */ + function getVM_LayerRightInfo($sLayer, $iGroupId, $sSchema = 'veremap_pro') { + include('vmlib/Vm.class.sql.inc'); + $aValues = Array("UPDATE" => false, "DELETE" => false, "INSERT" => false, "EXTRACT" => false, "UPLOAD" => false); + $sSql = $aSql[$this->sgbd]['getVM_LayerRightInfo']; + $sSql = str_replace('[sSchema]', $sSchema, $sSql); + $sSql = str_replace(array("[sLayerName]", "[iGroupId]"), array($sLayer, $iGroupId), $sSql); + $oResultat = $this->execute($sSql); + // DEPRECATED 2011_01 + if ($this->erreurRencontree) { + $sSql = $aSql[$this->sgbd]['getVM_LayerRightInfo_0']; + $sSql = str_replace('[sSchema]', $sSchema, $sSql); + $sSql = str_replace(array("[sLayerName]", "[iGroupId]"), array($sLayer, $iGroupId), $sSql); + $oResultat = $this->execute($sSql); + } + // + if ($oResultat !== false) { + $aValues = $this->ligneSuivante($oResultat); + } + $resultat = $this->fermeResultat(); + return $aValues; + } + + ## ===================================================== ## + ## METHODES AUTOUR DE LA STRUCTURE DE LA BASE DE DONNEES ## + ## ===================================================== ## + + /** + * M�thode permettant de tester si une table est une vue. + * Si c'est le cas, cette m�thode permet de rapatrier le nom de la table contenant la colonne g�om�trique utilis�e dans la vue. + * \param $sTable Nom de la table � tester. + * \param $sSchema Nom du sch�ma contenant la table � tester (vide par d�faut). + * \return Le nom de la table d'origine de la g�om�trie. + */ + function ifTableIsAView($sTable, $sSchema = "") { + $bReturn = false; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['ifTableIsAView']; + + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + $sOriginTable = $sTable; + $iResult = $this->execute($sSql); + + if ($aValues = $this->ligneSuivante($iResult)) { + $iPos = strpos($aValues["definition"], ".geom_cad"); + if ($iPos === false) { + $sGeometrieColumn = ".geom"; + $iPos = strpos($aValues["definition"], $sGeometrieColumn); + } else { + $sGeometrieColumn = ".geom_cad"; + } + $schaineAnalyse = substr($aValues["definition"], 0, $iPos + strlen($sGeometrieColumn)); + $iPosVirgule = strpos($schaineAnalyse, ","); + if ($iPosVirgule == "") { + $aTableauVirg = explode(" ", $schaineAnalyse); + $iNbrValTabVirg = count($aTableauVirg); + $sValeur2 = $aTableauVirg[$iNbrValTabVirg - 1]; + $iPosChaineAnalyse2 = strpos($sValeur2, $sGeometrieColumn); + $sOriginTable = trim(substr($sValeur2, 0, $iPosChaineAnalyse2)); + } else { + $sOriginTable = trim(substr(strrchr(substr($aValues["definition"], 0, $iPos), ","), 1)); + } + $iPosParenthese = strpos($sOriginTable, "("); + if ($iPosParenthese != "") { + $aTableauPar = explode("(", $sOriginTable); + $iNbrValTab = count($aTableauPar); + $sOriginTable = trim($aTableauPar[$iNbrValTab - 1]); + } + } + $iResult = $this->fermeResultat(); + return $sOriginTable; + } + + /** + * M�thode permettant de r�cup�rer le nom du sch�ma contenant la table pass�e en param�tre. + * \param $sTable Nom de la table � tester. + * \return Le nom du sch�ma. + */ + function getTableSchema($sTable) { + $bReturn = false; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getTableSchema']; + switch ($this->sgbd) { + case "pgsql" : + $sSql = str_replace("[sTable]", $sTable, $sSql); + break; + } + $sSchema = ""; + $iResult = $this->execute($sSql); + if ($aValues = $this->ligneSuivante($iResult)) { + $sSchema = $aValues["nspname"]; + } + $iResult = $this->fermeResultat(); + return $sSchema; + } + + /** + * M�thode permettant de cloner un enregistrement en tenant compte de la liste des cl�s uniques + * sp�cifi�es dans la vm_table et en leur associant la valeur 'null' lors de l'insertion. + * \param $sSchema Schema de la base de donn�es + * \param $sTable Table dans laquelle on ajoute. + * \param $aValues Valeurs � ajouter. + * \param $sSequence Nom de la s�quence � utiliser. + * \param $iIdField Nom de l'attribut identifiant. + * \param $sUkList Liste des cl�s uniques dans la table s�par�es par un '|'. + * \return L'id de la derni�re ligne ins�r�e. + */ + function cloneObj($sSchema, $sTable, $aValues, $sSequence, $iIdField, $sUkList) { + $aUk = explode("|", $sUkList); + foreach ($aUk as $sUk) + foreach ($aValues as $sKey => $sValue) + if ($sKey === $sUk) + $aValues[$sKey] = ""; + + return $this->insert($sSchema, $sTable, $aValues, $sSequence, $iIdField); + } + + ## ============================================ ## + ## METHODES DE MANIPULATION DES OBJETS SPATIAUX ## + ## ============================================ ## + + /** + * M�thode permettant de tester si une g�om�trie est au format EWKT + * \param $sGeom G�om�trie + * \return Bool�en. + */ + function isEWKTFormat($sGeom) { + if (strtoupper(substr($sGeom, 0, 5)) === 'SRID=') + return true; + else + return false; + } + + /** + * M�thode permettant de tester si une table contient une colonne supportant le stockage de donn�es spatiales. + * \param $sTable Nom de la table � tester. + * \param $sSchema Nom du sch�ma contenant la table � tester (vide par d�faut). + * \return Bool�en. + */ + function isTableSpatial($sTable, $sSchema = "") { + $bReturn = false; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['isTableSpatial']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + + $iResult = $this->execute($sSql); + if ($this->nombreLigne($iResult) != 0) + $bReturn = true; + $iResult = $this->fermeResultat(); + return $bReturn; + } + + /** + * M�thode permettant de r�cup�rer le 'SRID' d'une table contenant des donn�es spatiales. + * \private + * \param $sTable Nom de la table. + * \param $sSchema Nom du sch�ma contenant la table (vide par d�faut). + * \return Code SRID (nombre entier, 4 ou 5 chiffres) retourne 0 si aucun SRID d�fini. + */ + function getTableSRID($sTable, $sSchema = "") { + $iSrid = 0; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getTableSrid']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + $iResult = $this->execute($sSql); + if ($aValue = $this->ligneSuivante($iResult)) + $iSrid = $aValue['srid']; + $iResult = $this->fermeResultat(); + return $iSrid; + } + + /** + * Get a column projection + * @param string $sSchema + * @param string $sTable + * @param string $sColumn + * @return string + */ + function getColumnSRID($sSchema, $sTable, $sColumn) { + $sColumnProj = null; + $sSchemaKey = 'schema_' . vitisUniqId(); + $sTableKey = 'table_' . vitisUniqId(); + $sColumnKey = 'column_' . vitisUniqId(); + + $aParams = array(); + $aParams[$sSchemaKey] = array('value' => $sSchema, 'type' => 'column_name'); + $aParams[$sTableKey] = array('value' => $sTable, 'type' => 'column_name'); + $aParams[$sColumnKey] = array('value' => $sColumn, 'type' => 'column_name'); + $sSQLSRID = 'SELECT st_srid("[' . $sColumnKey . ']") as column_srid FROM "[' . $sSchemaKey . ']"."[' . $sTableKey . ']" WHERE "[' . $sColumnKey . ']" is not null AND st_srid("[' . $sColumnKey . ']") != 0 LIMIT 1'; + + $oResult = $this->executeWithParams($sSQLSRID, $aParams); + if ($this->enErreur()) { + writeToErrorLog($this->getBDMessage()); + } else { + if (!isset($this->enErreur)) { + $this->enErreur = false; + } + if (!$this->enErreur && $this->nombreLigne($oResult) > 0) { + $aData = array(); + while ($aObject = $this->ligneSuivante($oResult)) { + foreach ($aObject as $sParamKey => $sParamValue) { + if ($sParamKey === 'column_srid') { + $sColumnProj = $sParamValue; + } + } + } + } + } + + // Nouvelle tentative avec une requête différente + if ($sColumnProj === null || $sColumnProj == "0") { + // ne fonctionne pas dans tous les cas pour les vues + $sSQLSRID = "SELECT Find_SRID('[" . $sSchemaKey . "]', '[" . $sTableKey . "]', '[" . $sColumnKey . "]') as column_srid"; + + $oResult = $this->executeWithParams($sSQLSRID, $aParams); + if ($this->enErreur()) { + writeToErrorLog($this->getBDMessage()); + } else { + if (!isset($this->enErreur)) { + $this->enErreur = false; + } + if (!$this->enErreur && $this->nombreLigne($oResult) > 0) { + $aData = array(); + while ($aObject = $this->ligneSuivante($oResult)) { + foreach ($aObject as $sParamKey => $sParamValue) { + if ($sParamKey === 'column_srid') { + $sColumnProj = $sParamValue; + } + } + } + } + } + } + + // Nouvelle tentative avec une requête différente + if ($sColumnProj === null || $sColumnProj == "0") { + $sColumnProj = $this->getTableSRID($sTable, $sSchema); + } + + return $sColumnProj; + } + + /** + * M�thode permettant de r�cup�rer le type de g�om�trie d'une table contenant des donn�es spatiales. + * \private + * \param $sTable Nom de la table. + * \param $sSchema Nom du sch�ma contenant la table (vide par d�faut). + * \return Type de g�om�trie support�e retourne GEOMETRY si aucun type de g�om�trie d�fini. + */ + function getTableGeometryType($sTable, $sSchema = "") { + $sGeometryType = "GEOMETRY"; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getTableGeometryType']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + $iResult = $this->execute($sSql); + if ($aValue = $this->ligneSuivante($iResult)) + $sGeometryType = $aValue['type']; + $iResult = $this->fermeResultat(); + return $sGeometryType; + } + + /** + * M�thode permettant de r�cup�rer la dimension d'une table contenant des donn�es spatiales (2 pour 2D, 3 pour 3D...). + * \private + * \param $sTable Nom de la table. + * \param $sSchema Nom du sch�ma contenant la table (vide par d�faut). + * \return Un entier correspondant au nombre de dimension d'une table. + */ + function getTableDimension($sTable, $sSchema = "") { + $iDims = "2"; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getTableDimension']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]"); + $aReplacer = array($sSchema, $sTable); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + $iResult = $this->execute($sSql); + if ($aValue = $this->ligneSuivante($iResult)) + $iDims = $aValue['coord_dimension']; + $iResult = $this->fermeResultat(); + return $iDims; + } + + /** + * M�thode permettant de r�cup�rer la dimension d'une colonne contenant des donn�es spatiales (2 pour 2D, 3 pour 3D...). + * \private + * \param $sSchema Nom du sch�ma contenant la table. + * \param $sTable Nom de la table. + * \param $sColumn Nom de la colonne. + * \return Un entier correspondant au nombre de dimension d'une table. + */ + function getColumnDimension($sSchema, $sTable, $sColumn) { + $iDims = "2"; + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getColumnDimension']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sSchema]", "[sTable]", "[sColumn]"); + $aReplacer = array($sSchema, $sTable, $sColumn); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + $iResult = $this->execute($sSql); + if ($aValue = $this->ligneSuivante($iResult)) + $iDims = $aValue['coord_dimension']; + $iResult = $this->fermeResultat(); + return $iDims; + } + + /** + * M�thode permettant de renvoyer la g�om�trie (sous la forme d'une cha�ne WKT) en cours d'�dtion + * apr�s ajout des d'un nouveau vertex dont les coordonn�es ont �t� interpol�es selon les coordonn�es + * du point saisie par l'utilisateur dans l'interface graphique. + * \param $sTable Nom de la table dans laquelle se trouve la g�om�trie en cours d'�dition. + * \param $sSchema Sch�ma contenant la 'vm_table' � exploiter. + * \param $sX Coordonn�es X du point cliqu�. + * \param $sY Coordonn�es Y du point cliqu�. + * \param $sWKT Cha�ne WKT constitutive de la g�om�trie en cours d'�dition. + * \param $dTolerance Tol�rance de distance entre le nouveau vertex et la g�om�trie en cours d'�dition. + * \return La cha�ne WKT mise � jour. + */ + function geomAddVertex($sTable, $sSchema = "", $sX, $sY, $sWKT, $dTolerance) { + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['geomAddVertex']; + + $aTableInfo = $this->getVM_TableInfo($sTable, $sSchema); + $sTable = $this->ifTableIsAView($sTable, $aTableInfo["SCHEMA_NAME"]); + if ($sTable != $aTableInfo["TABLE_NAME"]) { + $sSchema = $this->getTableSchema($sTable); + $iSRID = $this->getTableSRID($sTable, $sSchema); + } else { + $iSRID = $this->getTableSRID($sTable, $aTableInfo["SCHEMA_NAME"]); + } + $sVertexCoords = $sX . " " . $sY; + + // Cas des polygones + $bPolygon = false; + if (substr_count($sWKT, "POLYGON") === 1) + $bPolygon = true; + + if ($bPolygon) + $sWKT = str_replace(array("POLYGON((", "))"), array("LINESTRING(", ")"), $sWKT); + // ---- + + $dCurrentDistance = $this->getVertexDistance($sWKT, $iSRID, $sVertexCoords); + if ($dTolerance >= $dCurrentDistance) { + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sWKT]", "[sVertexCoords]", "[iSRID]"); + $aReplacer = array($sWKT, $sVertexCoords, $iSRID); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + + $iResult = $this->execute($sSql); + if ($iResult !== false) { + $aValues = $this->ligneSuivante($iResult); + $sWKT = $aValues["wkt"]; + } + $iResult = $this->fermeResultat(); + } + + if ($bPolygon) + $sWKT = str_replace(array("LINESTRING(", ")"), array("POLYGON((", "))"), $sWKT); + + return $sWKT; + } + + /** + * M�thode permettant de renvoyer deux g�om�tries (sous la forme de deux cha�nes WKT) + * apr�s d�coupe de la g�om�trie d'origine (selon la localisation d'un vertex de d�coupe...). + * \param $sTable Nom de la table dans laquelle se trouve la g�om�trie en cours d'�dition. + * \param $sSchema Sch�ma contenant la 'vm_table' � exploiter. + * \param $sX Coordonn�es X du point cliqu�. + * \param $sY Coordonn�es Y du point cliqu�. + * \param $sWKT Cha�ne WKT constitutive de la g�om�trie en cours d'�dition. + * \param $dTolerance Tol�rance de distance entre le nouveau vertex et la g�om�trie en cours d'�dition. + * \return La cha�ne WKT mise � jour. + */ + function geomCutLine($sTable, $sSchema = "", $sX, $sY, $sWKT, $dTolerance) { + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['geomCutLine']; + + $aTableInfo = $this->getVM_TableInfo($sTable, $sSchema); + $sTable = $this->ifTableIsAView($sTable, $aTableInfo["SCHEMA_NAME"]); + if ($sTable != $aTableInfo["TABLE_NAME"]) { + $sSchema = $this->getTableSchema($sTable); + $iSRID = $this->getTableSRID($sTable, $sSchema); + } else { + $iSRID = $this->getTableSRID($sTable, $aTableInfo["SCHEMA_NAME"]); + } + + $sVertexCoords = $sX . " " . $sY; + + $dCurrentDistance = $this->getVertexDistance($sWKT, $iSRID, $sVertexCoords); + if ($dTolerance >= $dCurrentDistance) { + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sWKT]", "[sVertexCoords]", "[iSRID]"); + $aReplacer = array($sWKT, $sVertexCoords, $iSRID); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + + $iResult = $this->execute($sSql); + ($iResult !== false) ? + $aValues = $this->ligneSuivante($iResult) : + $aValues = array(); + $iResult = $this->fermeResultat(); + } + + return $aValues; + } + + /** + * M�thode permettant d'assurer l'accrochage de la g�om�trie en cours d'�dition s'il y a lieu. + * \param $sIdValue Valeur de l'identifiant associ� � la g�om�trie (vide lors d'un ajout). + * \param $sWKT Cha�ne WKT constitutive de la g�om�trie en cours d'�dition. + * \param $aTableInfo Informations provenant de la vm_table pour la table en cours d'�dition. + * \param $sExtendLine Param�tre valoris� uniquement pour le prolongement des lignes (vaut "start" ou "end" dans ce cas, vide sinon). + * \return La cha�ne WKT mise � jour. + */ + function geomBinding($sIdValue, $sWKT, $aTableInfo, $sExtendLine = "") { + include("vmlib/Vm.class.sql.inc"); + $sWhereClause = ""; + if ($sIdValue != "") + $sWhereClause = $aTableInfo["ID_FIELD"] . " != " . $sIdValue . " AND"; + $sOriginTable = $this->ifTableIsAView($aTableInfo["TABLE_NAME"], $aTableInfo["SCHEMA_NAME"]); + if ($sOriginTable != $aTableInfo["TABLE_NAME"]) + $sSchema = $this->getTableSchema($sOriginTable); + else + $sSchema = $aTableInfo["SCHEMA_NAME"]; + $iSRID = $this->getTableSRID($sOriginTable, $sSchema); + $sGeomType = $this->getTableGeometryType($sOriginTable, $sSchema); + if ($sGeomType == "GEOMETRY" || $sGeomType == "ST_Geometry") + $sGeomType = substr($sWKT, 0, 10); + if ($sGeomType == "LINESTRING" || $sGeomType == "ST_LineString") { + $sSqlStart = $aSql[$this->sgbd]['geomBinding_1']; + $sSqlEnd = $aSql[$this->sgbd]['geomBinding_2']; + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sWKT]", "[iSRID]", "[sSchema]", "[sTable]", "[sWhereClause]", "[dTolerance]"); + $aReplacer = array($sWKT, $iSRID, $aTableInfo["SCHEMA_NAME"], $aTableInfo["TABLE_NAME"], $sWhereClause, round($aTableInfo["BIND_TOLERANCE"], 2)); + $sSqlStart = str_replace($aTag, $aReplacer, $sSqlStart); + $sSqlEnd = str_replace($aTag, $aReplacer, $sSqlEnd); + break; + } + $bStart = $bEnd = true; + switch ($sExtendLine) { + case "start" : + $bEnd = false; + break; + case "end" : + $bStart = false; + break; + } + + if ($bStart) { + $iResult = $this->execute($sSqlStart); + if ($iResult !== false) { + if ($aValues = $this->ligneSuivante($iResult)) { + if ($aValues["distance"] <= $aTableInfo["BIND_TOLERANCE"]) { + $iVertexIndex = 0; + $aValues = array($sWKT, $iSRID, $aValues["wkt"], $iVertexIndex); + $sWKT = $this->geomBinding_private($aSql[$this->sgbd]['geomBinding_3'], $aValues); + } + } + } + $iResult = $this->fermeResultat(); + } + + if ($bEnd) { + $iResult = $this->execute($sSqlEnd); + if ($iResult !== false) { + if ($aValues = $this->ligneSuivante($iResult)) { + if ($aValues["distance"] <= $aTableInfo["BIND_TOLERANCE"]) { + $iVertexIndex = ($aValues["nb_vertex"] - 1); + $aValues = array($sWKT, $iSRID, $aValues["wkt"], $iVertexIndex); + $sWKT = $this->geomBinding_private($aSql[$this->sgbd]['geomBinding_3'], $aValues); + } + } + } + $iResult = $this->fermeResultat(); + } + } + + return $sWKT; + } + + /** + * M�thode priv�e permettant de finaliser l'accorchage des g�om�tries. + * \param $sSqlTemplate Requ�te SQL mod�le. + * \param $aValues Tableau contenant les valeurs � associer � la requ�te mod�le. + * \private + * \return La g�om�trie accroch�e selon un num�ro d'index de vertex. + */ + function geomBinding_private($sSqlTemplate, $aValues) { + switch ($this->sgbd) { + case "pgsql" : + $sWKT = $aValues[0]; + $aTag = array("[sWKT]", "[iSRID]", "[sVertexWKT]", "[iVertexIndex]"); + $aReplacer = array($aValues[0], $aValues[1], $aValues[2], $aValues[3]); + $sSql = str_replace($aTag, $aReplacer, $sSqlTemplate); + break; + } + + $iResult = $this->execute($sSql); + if ($iResult !== false) { + $aValues = $this->ligneSuivante($iResult); + $sWKT = $aValues["wkt"]; + } + $iResult = $this->fermeResultat(); + + return $sWKT; + } + + /** + * Cette m�thode permet de r�cup�rer la distance (exprim�e en unit� terrain) entre un vertex (correspondant aux + * coordonn�es du point cliqu� sur la carte) 'utilisateur' et la g�om�trie en cours d'�dition. + * \private + * \param $sWKT Cha�ne WKT constitutive de la g�om�trie en cours d'�dition. + * \param $iSRID Code SRID du syst�me de projection de la g�om�trie en cours d'�dition. + * \param $sWKT Cha�ne WKT constitutive de la g�om�trie en cours d'�dition. + * \return La distance du nouveau vertex. + */ + function getVertexDistance($sWKT, $iSRID, $sVertexCoords) { + include("vmlib/Vm.class.sql.inc"); + $sSql = $aSql[$this->sgbd]['getVertexDistance']; + + switch ($this->sgbd) { + case "pgsql" : + $aTag = array("[sWKT]", "[iSRID]", "[sVertexCoords]"); + $aReplacer = array($sWKT, $iSRID, $sVertexCoords); + $sSql = str_replace($aTag, $aReplacer, $sSql); + break; + } + + $iResult = $this->execute($sSql); + + $dDistance = 0; + if ($iResult !== false) { + $aValues = $this->ligneSuivante($iResult); + $dDistance = $aValues["distance"]; + } + + $iResult = $this->fermeResultat(); + + return $dDistance; + } + + ## ===================================== ## + ## METHODES DE STRUCTURATION DE TABLEAUX ## + ## ===================================== ## + + /** + * M�thode qui renvoie une cha�ne de caract�re de type html pr�sentant sous forme de tableau le contenu du resultset. + * \param $resultset Le jeu d'enregistrement r�sultant de l'�x�cution d'une requ�te. + * \param $sMessageSiVide Message affich� dans le tableau si le resultset est vide + * \param $sCssLabel Style css � appliquer au noms d'attributs - 1�re ligne du tableau + * \param $sCssValue Style css � appliquer aux valeurs - lignes suivantes + * \return Une cha�ne de caract�res . + */ + function resultset2Table($resultset, $sMessageSiVide = "", $sCssLabel, $sCssValue = "") { + if ($sMessageSiVide == "") { + $sMessageSiVide = NOT_RECORD_FOUND_VM; + } + $sResult = "<center><table border='1'>"; + if ($aValues = $this->tableauSuivant($resultset)) { + // s'il y a un r�sultat on construit la premi�re ligne du tableau + $iFieldCount = $this->getFieldsNumber($resultset); + + $sLigne = "<tr CLASS='$sCssLabel'>"; + for ($i = 0; $i < $iFieldCount; $i++) + $sLigne .= "<td>" . $this->getFieldName($resultset, $i) . "</td>"; + $sLigne .= "</tr>"; + + // Deuxi�me ligne avec les valeurs + $sLigne .= "<tr CLASS='$sCssValue'>"; + for ($i = 0; $i < $iFieldCount; $i++) + $sLigne .= "<td>" . $aValues{$i} . "</td>"; + $sLigne .= "</tr>"; + $sResult .= $sLigne; + + // lignes suivantes + while ($aValues = $this->tableauSuivant($resultset)) { + $sLigne = "<tr CLASS='$sCssValue'>"; + for ($i = 0; $i < $iFieldCount; $i++) + $sLigne .= "<td>" . $aValues{$i} . "</td>"; + $sLigne .= "</tr>"; + $sResult .= $sLigne; + } + } else { + $sLigne = "<tr><td>$sMessageSiVide</td></tr>"; + $sResult .= $sLigne; + } + $sResult .= "</table></center>"; + return $sResult; + } + + /** + * Méthode qui renvoie une cha�ne de caract�re de type html pr�sentant sous forme de tableau editable. + * Ce tableau a les caract�ristiques suivantes : + * Nom de champ clickable (pour d�finir l'ordre de pr�sentation) + * La premi�re colonne permet de se mettre en mode �dition + * La seconde colonne permet de supprimer l'enregistrement + * La troisi�me colonne permet d'afficher l'enregistrement + * \param $resultset Le jeu d'enregistrement r�sultant de l'�x�cution d'une requ�te. + * \param $sMessageSiVide Message affich� dans le tableau si le resultset est vide + * \param $sCssLabel Style css � appliquer au noms d'attributs - 1�re ligne du tableau + * \param $sCssValue Style css � appliquer aux valeurs - lignes suivantes + * \param $sIdField : nom du champ identifiant de la table pr�sent�e + * \return Une cha�ne de caract�res . + */ + function resultset2EditTable($resultset, $sMessageSiVide = "", $sCssLabel, $sCssValue = "", $sCssValue2 = "", $sIdField, $aRights = array(), $aTableParams = array()) { + if ($sMessageSiVide == "") { + $sMessageSiVide = NOT_RECORD_FOUND_VM; + } + // Tableau de param�trage de la m�thode + if ($aTableParams != array()) { + extract($aTableParams); + } else { + $IMAGE = false; + $CENTER = true; + $SPACING = 1; + $PADDING = 5; + $EMPTY_HEAD_CELLS = true; + $IMAGE_PATH = "../images/"; + $GEOM = false; + } + + // Red�claration des variables (pour plus de lisibilit�) + $bImage = $IMAGE; + $sImagePath = $IMAGE_PATH; + if (isset($LAYER)) + $sLayerName = $LAYER; + $bGeom = $GEOM; + + if ($CENTER) + $aCenter = array("tag" => "<center>", "endtag" => "</center>"); + else + $aCenter = array("tag" => "", "endtag" => ""); + + if ($EMPTY_HEAD_CELLS) + $sEmptyCellCss = " class='emptyCell'"; + else + $sEmptyCellCss = ""; + + $sResult = ""; + $bDisplay = true; + $bGeom ? ($iColspan = 2) : ($iColspan = 1); + + if ($aRights == array()) { + $bEdit = true; + $bDelete = true; + $bCheckBox = true; + $iColspan = $iColspan + 3; + } else { + if ($aRights["UPDATE"] == true) { + $bEdit = true; + $iColspan++; + } else { + $bEdit = false; + } + if ($aRights["DELETE"] == true) { + $bDelete = true; + $bCheckBox = true; + $iColspan = $iColspan + 2; + } else { + $bDelete = false; + $bCheckBox = false; + } + } + + $iIdField = 4; + $bPremiereLigne = true; + $iJ = 0; + $iN = 0; + + //ligneSuivante � la place tableauSuivant + while ($aValues = $this->ligneSuivante($resultset)) { + $iJ++; + $iN++; + $sLigne = ""; + if ($bPremiereLigne) { + $sResult = $aCenter["tag"] . "<table border='0' cellpadding='" . $PADDING . "' cellspacing='" . $SPACING . "'><form name='listForm'>"; + $iFieldCount = $this->getFieldsNumber($resultset); + $iColspan = $iColspan + $iFieldCount; + $sLigne = "<tr class='$sCssLabel'>"; + if ($bEdit) + $sLigne .= "<td" . $sEmptyCellCss . "> </td>"; + if ($bDisplay) + $sLigne .= "<td" . $sEmptyCellCss . "> </td>"; + if ($bGeom) + $sLigne .= "<td" . $sEmptyCellCss . "> </td>"; + if ($bDelete) + $sLigne .= "<td" . $sEmptyCellCss . "> </td>"; + if ($bCheckBox) + $sLigne .= "<td" . $sEmptyCellCss . "> </td>"; + $i = 0; + foreach ($aValues as $valueName => $value) { + if ($valueName != 'LIMIT_NUM_ROW') { + $i++; + $sField = $valueName; + $sLigne .= '<td><a class="tabLink" href="javascript:parent.orderby(\'' . $sField . '\');">' . $sField . '</a></td>'; + } + } + $sLigne .= "</tr>"; + if ($bImage) + $sLigne .= "<tr><td colspan='" . $iColspan . "' width='100%' class='interligne'> </td></tr>"; + $bPremiereLigne = false; + } + if (($iN % 2) == 0) + $sLigne .= "<tr CLASS='$sCssValue2'>"; + else + $sLigne .= "<tr CLASS='$sCssValue'>"; + + $IdValue = $aValues{$sIdField}; + if ($bEdit) + $sLigne .= '<td><a href="javascript:parent.edit(\'' . $IdValue . '\');"><img src="' . $sImagePath . 'button_edit.png" alt="Modifier" title="Modifier" border="0" /></a></td>'; + if ($bDisplay) + $sLigne .= '<td><a href="javascript:parent.display(\'' . $IdValue . '\');"><img src="' . $sImagePath . 'button_display.png" alt="Voir" title="Voir" border="0" /></a></td>'; + if ($bGeom) + $sLigne .= '<td><a href="javascript:parent.zoom(\'' . $sLayerName . '\', \'' . $IdValue . '\');"><img src="' . $sImagePath . 'button_zoom.png" alt="Zoomer" title="Zoomer" border="0" /></a></td>'; + if ($bDelete) + $sLigne .= '<td><a href="javascript:parent.deleteRecord(\'' . $IdValue . '\');" onclick="return confirm(' . WARNING_DELETE_VM_01 . $IdValue . WARNING_DELETE_VM_02 . '\')"><img src="' . $sImagePath . 'button_delete.png" alt="Supprimer" title="Supprimer" border="0" /></a></td>'; + if ($bCheckBox) + $sLigne .= '<td><input type="checkbox" name="' . $IdValue . '" value="" id="checkbox_' . $iJ . '" /></td>'; + + foreach ($aValues as $valueName => $value) + if ($valueName != 'LIMIT_NUM_ROW') + $sLigne .= "<td>" . $value . "</td>"; + //for ($i=0;$i<$iFieldCount;$i++) $sLigne .= "<td>".$aValues{$i}."</td>"; + $sLigne .= "</tr>"; + if ($bImage) + $sLigne .= "<tr><td colspan='" . $iColspan . "' width='100%' class='interligne'> </td></tr>"; + $sResult .= $sLigne; + } + if ($sResult == "") + $sResult = $aCenter["tag"] . "<table border='1' cellpadding='" . $PADDING . "' cellspacing='" . $SPACING . "'><form name='listForm'><tr CLASS='$sCssValue'><td>$sMessageSiVide</td></tr>"; + $sResult .= "</form></table>" . $aCenter["endtag"]; + return $sResult; + } + +// Fin de la classe +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/Vm.class.sql.inc b/vas/rest/class/vmlib/Vm.class.sql.inc new file mode 100755 index 0000000000000000000000000000000000000000..2154255e30febeb339f37f60622a6b4078730138 --- /dev/null +++ b/vas/rest/class/vmlib/Vm.class.sql.inc @@ -0,0 +1,30 @@ +<?php + +//Requ�te de la classe Vm pour mysql +$aSql['mysql']['getVM_TableInfo'] = "SELECT * FROM vm_table WHERE name = '[sTable]'"; + +//Requ�te de la classe Vm pour pgsql +$aSql['pgsql']['getVM_TableInfo'] = "SELECT * FROM [sSchema].vm_table WHERE \"TABLE_NAME\" = '[sTable]'"; +$aSql['pgsql']['getVM_TableInfoTradFramework'] = "SELECT \"name\", \"id_field\", \"id_field_type\", \"id_field_label\", \"sql_list\", \"form_class\", \"sql_form\", translation_title.\"translation\" as \"TITRE_LISTE\", translation_form.\"translation\" as \"form_title\", \"id_field_sequence\", \"schema_name\", \"sorted_by\", \"sorted_dir\", \"edit_column\" , \"show_column\", \"module\", \"work_class\", \"business_id\" FROM [sSchema].vm_table INNER JOIN [sSchema].vm_translation as translation_title ON translation_title.translation_id = vm_table.\"title_list_label_id\" INNER JOIN [sSchema].vm_translation as translation_form ON translation_form.translation_id = vm_table.\"title_form_label_id\" and translation_form.lang=translation_title.lang WHERE \"name\" = '[sTable]' AND translation_title.lang = '[sLang]'"; +$aSql['pgsql']['getVM_TableInfoTrad'] = "SELECT \"name\", \"id_field\", \"id_field_type\", \"id_field_label\", \"sql_list\", \"form_class\", \"sql_form\", translation_title.\"translation\" as \"TITRE_LISTE\", translation_form.\"translation\" as \"form_title\", \"id_field_sequence\", \"schema_name\", \"sorted_by\", \"sorted_dir\", \"edit_column\" , \"show_column\", \"business_id\" FROM [sSchema].vm_table INNER JOIN [sSchema].vm_translation as translation_title ON translation_title.translation_id = vm_table.\"title_list_label_id\" INNER JOIN [sSchema].vm_translation as translation_form ON translation_form.translation_id = vm_table.\"title_form_label_id\" and translation_form.lang=translation_title.lang WHERE \"name\" = '[sTable]' AND translation_title.lang = '[sLang]'"; +$aSql['pgsql']['getVM_LayerInfo'] = "SELECT * FROM [sSchema].vm_table WHERE \"LAYER_NAME\" = '[sLayer]'"; +$aSql['pgsql']['getVM_LayerRightInfo'] = "SELECT \"UPDATE\", \"DELETE\", \"INSERT\", \"UPLOAD\", \"EXTRACT\" FROM [sSchema].group_rights LEFT JOIN [sSchema].layer ON group_rights.\"LAYER_ID\" = layer.\"LAYER_ID\" WHERE \"LAYER_NAME\" ='[sLayerName]' AND \"GROUP_ID\" IN ([iGroupId])"; +// getVM_LayerRightInfo_0 DEPRECATED 2011_01 +$aSql['pgsql']['getVM_LayerRightInfo_0'] = "SELECT \"UPDATE\", \"UPDATE\" AS \"INSERT\", \"UPDATE\" AS \"DELETE\", \"UPLOAD\", \"EXTRACT\" FROM [sSchema].group_rights LEFT JOIN [sSchema].layer ON group_rights.\"LAYER_ID\" = layer.\"LAYER_ID\" WHERE \"LAYER_NAME\" ='[sLayerName]' AND \"GROUP_ID\" IN ([iGroupId])"; +$aSql['pgsql']['isTableSpatial'] = "SELECT attname, relname, typname, nspname FROM pg_attribute, pg_class, pg_type, pg_namespace WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relnamespace = pg_namespace.oid AND pg_attribute.atttypid = pg_type.oid AND nspname = '[sSchema]' AND relname = '[sTable]' AND typname = 'geometry' ORDER BY attname ASC"; +$aSql['pgsql']['ifTableIsAView'] = "SELECT definition FROM pg_views WHERE schemaname = '[sSchema]' AND viewname = '[sTable]'"; +$aSql['pgsql']['getTableSchema'] = "SELECT nspname FROM pg_class, pg_namespace WHERE pg_class.relnamespace = pg_namespace.oid AND relname = '[sTable]'"; +$aSql['pgsql']['getTableSrid'] = "SELECT COALESCE(NULLIF(postgis_typmod_srid(pg_attribute.atttypmod), 0), postgis_constraint_srid(pg_namespace.nspname::text, pg_class.relname::text, pg_attribute.attname::text), 0) AS srid FROM pg_class, pg_attribute, pg_type, pg_namespace WHERE pg_type.typname = 'geometry'::name AND pg_attribute.attisdropped = false AND pg_attribute.atttypid = pg_type.oid AND pg_attribute.attrelid = pg_class.oid AND pg_class.relnamespace = pg_namespace.oid AND (pg_class.relkind = 'r'::\"char\" OR pg_class.relkind = 'v'::\"char\") AND NOT pg_is_other_temp_schema(pg_class.relnamespace) AND pg_namespace.nspname = '[sSchema]'::name AND pg_class.relname = '[sTable]'::name;"; +$aSql['pgsql']['getTableGeometryType'] = "SELECT replace(replace(COALESCE(NULLIF(upper(postgis_typmod_type(pg_attribute.atttypmod)), 'GEOMETRY'::text), postgis_constraint_type(pg_namespace.nspname::text, pg_class.relname::text, pg_attribute.attname::text)::text, 'GEOMETRY'::text), 'ZM'::text, ''::text), 'Z'::text, ''::text)::character varying(30) AS type FROM pg_class, pg_attribute, pg_type, pg_namespace WHERE pg_type.typname = 'geometry'::name AND pg_attribute.attisdropped = false AND pg_attribute.atttypid = pg_type.oid AND pg_attribute.attrelid = pg_class.oid AND pg_class.relnamespace = pg_namespace.oid AND (pg_class.relkind = 'r'::\"char\" OR pg_class.relkind = 'v'::\"char\") AND NOT pg_is_other_temp_schema(pg_class.relnamespace) AND pg_namespace.nspname = '[sSchema]'::name AND pg_class.relname = '[sTable]'::name;"; +$aSql['pgsql']['getTableDimension'] = "SELECT COALESCE(NULLIF(postgis_typmod_dims(pg_attribute.atttypmod), 2), postgis_constraint_dims(pg_namespace.nspname::text, pg_class.relname::text, pg_attribute.attname::text), 2) AS coord_dimension FROM pg_class, pg_attribute, pg_type, pg_namespace WHERE pg_type.typname = 'geometry'::name AND pg_attribute.attisdropped = false AND pg_attribute.atttypid = pg_type.oid AND pg_attribute.attrelid = pg_class.oid AND pg_class.relnamespace = pg_namespace.oid AND (pg_class.relkind = 'r'::\"char\" OR pg_class.relkind = 'v'::\"char\") AND NOT pg_is_other_temp_schema(pg_class.relnamespace) AND pg_namespace.nspname = '[sSchema]'::name AND pg_class.relname = '[sTable]'::name;"; +$aSql['pgsql']['getColumnDimension'] = "SELECT COALESCE(NULLIF(postgis_typmod_dims(pg_attribute.atttypmod), 2), postgis_constraint_dims(pg_namespace.nspname::text, pg_class.relname::text, pg_attribute.attname::text), 2) AS coord_dimension FROM pg_class, pg_attribute, pg_type, pg_namespace WHERE pg_type.typname = 'geometry'::name AND pg_attribute.attisdropped = false AND pg_attribute.atttypid = pg_type.oid AND pg_attribute.attrelid = pg_class.oid AND pg_class.relnamespace = pg_namespace.oid AND (pg_class.relkind = 'r'::\"char\" OR pg_class.relkind = 'v'::\"char\") AND NOT pg_is_other_temp_schema(pg_class.relnamespace) AND pg_namespace.nspname = '[sSchema]'::name AND pg_class.relname = '[sTable]'::name AND pg_attribute.attname = '[sColumn]'::name;"; +$aSql['pgsql']['getVertexDistance'] = "SELECT st_distance(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('POINT([sVertexCoords])', [iSRID])) as distance"; +$aSql['pgsql']['geomAddVertex'] = "SELECT st_asText(st_addPoint(st_geometryFromText('[sWKT]', [iSRID]), st_line_interpolate_point(st_geometryFromText('[sWKT]', [iSRID]), st_line_locate_point(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('POINT([sVertexCoords])', [iSRID]))), vm_get_new_vertex_position(st_geometryFromText('[sWKT]', [iSRID]) ,st_line_interpolate_point(st_geometryFromText('[sWKT]', [iSRID]), st_line_locate_point(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('POINT([sVertexCoords])', [iSRID])))))) as wkt"; +$aSql['pgsql']['geomBinding_1'] = "SELECT st_asText(vm_get_nearest_vertex(geom, st_startPoint(st_geometryFromText('[sWKT]', [iSRID])))) as wkt, st_distance(vm_get_nearest_vertex(geom, st_startPoint(st_geometryFromText('[sWKT]', [iSRID]))), st_startPoint(st_geometryFromText('[sWKT]', [iSRID]))) as distance FROM [sSchema].[sTable] WHERE [sWhereClause] st_intersects(geom, st_buffer(st_geometryFromText('[sWKT]', [iSRID]), [dTolerance])) = true ORDER BY distance ASC"; +$aSql['pgsql']['geomBinding_2'] = "SELECT st_asText(vm_get_nearest_vertex(geom, st_endPoint(st_geometryFromText('[sWKT]', [iSRID])))) as wkt, st_distance(vm_get_nearest_vertex(geom, st_endPoint(st_geometryFromText('[sWKT]', [iSRID]))), st_endPoint(st_geometryFromText('[sWKT]', [iSRID]))) as distance, st_npoints(st_geometryFromText('[sWKT]', [iSRID])) as nb_vertex FROM [sSchema].[sTable] WHERE [sWhereClause] st_intersects(geom, st_buffer(st_geometryFromText('[sWKT]', [iSRID]), [dTolerance])) = true ORDER BY distance ASC"; +$aSql['pgsql']['geomBinding_3'] = "SELECT st_asText(vm_move_vertex_from_geom(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('[sVertexWKT]', [iSRID]), [iVertexIndex])) as wkt"; +$aSql['pgsql']['geomCutLine'] = "SELECT st_asText(st_line_substring(st_geometryFromText('[sWKT]', [iSRID]), 0, st_line_locate_point(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('POINT([sVertexCoords])', [iSRID])))) as wkt_start, st_asText(st_line_substring(st_geometryFromText('[sWKT]', [iSRID]), st_line_locate_point(st_geometryFromText('[sWKT]', [iSRID]), st_geometryFromText('POINT([sVertexCoords])', [iSRID])), 1)) as wkt_end"; + +//Requ�te de la classe Vm pour oci +$aSql['oci']['getVM_TableInfo'] = "SELECT * FROM vm_table WHERE name = '[sTable]'"; +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/class.websocket_client.php b/vas/rest/class/vmlib/class.websocket_client.php new file mode 100755 index 0000000000000000000000000000000000000000..ad5acc665f34cf551a1cff3ec651466bec1beb70 --- /dev/null +++ b/vas/rest/class/vmlib/class.websocket_client.php @@ -0,0 +1,296 @@ +<?php + +//ini_set('display_errors', 1); +//error_reporting(E_ALL); + +/** + * Very basic websocket client. + * Supporting draft hybi-10. + * + * @author Simon Samtleben <web@lemmingzshadow.net> + * @author Armand Bahi <armand.bahi@veremes.com> + * @version 2011-10-18 + */ +class WebsocketClient { + + private $_host; + private $_port; + private $_path; + private $_origin; + private $_Socket = null; + private $_connected = false; + + public function __construct() { + + } + + public function __destruct() { + $this->disconnect(); + } + + public function isConnected() { + return $this->_connected; + } + + public function sendData($data, $type = 'text', $masked = true) { + if ($this->_connected === false) { + trigger_error("Not connected", E_USER_WARNING); + return false; + } + if (!is_string($data)) { + trigger_error("Not a string data was given.", E_USER_WARNING); + return false; + } + if (strlen($data) == 0) { + return false; + } + $res = @fwrite($this->_Socket, $this->_hybi10Encode($data, $type, $masked)); + if ($res === 0 || $res === false) { + return false; + } + $buffer = ' '; + while ($buffer !== '') { + $buffer = fread($this->_Socket, 512); // drop? + } + + return true; + } + + public function connect($host, $port, $path, $origin = 'foo.lh') { + $this->_host = $host; + $this->_port = $port; + $this->_path = $path; + $this->_origin = $origin; + + $key = base64_encode($this->_generateRandomString(16, false, true)); + $header = "GET " . $path . " HTTP/1.1\r\n"; + $header .= "Host: " . $host . ":" . $port . "\r\n"; + $header .= "Upgrade: websocket\r\n"; + $header .= "Connection: Upgrade\r\n"; + $header .= "Sec-WebSocket-Key: " . $key . "\r\n"; + if ($origin !== false) { + $header .= "Sec-WebSocket-Origin: " . $origin . "\r\n"; + } + $header .= "Sec-WebSocket-Version: 13\r\n"; + + $this->_Socket = fsockopen($host, $port, $errno, $errstr, 2); + socket_set_timeout($this->_Socket, 0, 10000); + $response = @fread($this->_Socket, 1500); + + @fwrite($this->_Socket, $header); + $response = @fread($this->_Socket, 1500); + preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches); + + if ($matches) { + $keyAccept = trim($matches[1]); + $expectedResonse = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); + $this->_connected = ($keyAccept === $expectedResonse) ? true : false; + } + + return $this->_connected; + } + + public function checkConnection() { + $this->_connected = false; + + // send ping: + $data = 'ping?'; + @fwrite($this->_Socket, $this->_hybi10Encode($data, 'ping', true)); + $response = @fread($this->_Socket, 300); + if (empty($response)) { + return false; + } + $response = $this->_hybi10Decode($response); + if (!is_array($response)) { + return false; + } + if (!isset($response['type']) || $response['type'] !== 'pong') { + return false; + } + $this->_connected = true; + return true; + } + + public function disconnect() { + $this->_connected = false; + is_resource($this->_Socket) and fclose($this->_Socket); + } + + public function reconnect() { + sleep(10); + $this->_connected = false; + fclose($this->_Socket); + $this->connect($this->_host, $this->_port, $this->_path, $this->_origin); + } + + private function _generateRandomString($length = 10, $addSpaces = true, $addNumbers = true) { + $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}'; + $useChars = array(); + // select some random chars: + for ($i = 0; $i < $length; $i++) { + $useChars[] = $characters[mt_rand(0, strlen($characters) - 1)]; + } + // add spaces and numbers: + if ($addSpaces === true) { + array_push($useChars, ' ', ' ', ' ', ' ', ' ', ' '); + } + if ($addNumbers === true) { + array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9)); + } + shuffle($useChars); + $randomString = trim(implode('', $useChars)); + $randomString = substr($randomString, 0, $length); + return $randomString; + } + + private function _hybi10Encode($payload, $type = 'text', $masked = true) { + $frameHead = array(); + $frame = ''; + $payloadLength = strlen($payload); + + switch ($type) { + case 'text': + // first byte indicates FIN, Text-Frame (10000001): + $frameHead[0] = 129; + break; + + case 'close': + // first byte indicates FIN, Close Frame(10001000): + $frameHead[0] = 136; + break; + + case 'ping': + // first byte indicates FIN, Ping frame (10001001): + $frameHead[0] = 137; + break; + + case 'pong': + // first byte indicates FIN, Pong frame (10001010): + $frameHead[0] = 138; + break; + } + + // set mask and payload length (using 1, 3 or 9 bytes) + if ($payloadLength > 65535) { + $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); + $frameHead[1] = ($masked === true) ? 255 : 127; + for ($i = 0; $i < 8; $i++) { + $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); + } + // most significant bit MUST be 0 (close connection if frame too big) + if ($frameHead[2] > 127) { + $this->close(1004); + return false; + } + } elseif ($payloadLength > 125) { + $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); + $frameHead[1] = ($masked === true) ? 254 : 126; + $frameHead[2] = bindec($payloadLengthBin[0]); + $frameHead[3] = bindec($payloadLengthBin[1]); + } else { + $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; + } + + // convert frame-head to string: + foreach (array_keys($frameHead) as $i) { + $frameHead[$i] = chr($frameHead[$i]); + } + if ($masked === true) { + // generate a random mask: + $mask = array(); + for ($i = 0; $i < 4; $i++) { + $mask[$i] = chr(rand(0, 255)); + } + + $frameHead = array_merge($frameHead, $mask); + } + $frame = implode('', $frameHead); + + // append payload to frame: + $framePayload = array(); + for ($i = 0; $i < $payloadLength; $i++) { + $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i]; + } + + return $frame; + } + + private function _hybi10Decode($data) { + $payloadLength = ''; + $mask = ''; + $unmaskedPayload = ''; + $decodedData = array(); + + // estimate frame type: + $firstByteBinary = sprintf('%08b', ord($data[0])); + $secondByteBinary = sprintf('%08b', ord($data[1])); + $opcode = bindec(substr($firstByteBinary, 4, 4)); + $isMasked = ($secondByteBinary[0] == '1') ? true : false; + $payloadLength = ord($data[1]) & 127; + + switch ($opcode) { + // text frame: + case 1: + $decodedData['type'] = 'text'; + break; + + case 2: + $decodedData['type'] = 'binary'; + break; + + // connection close frame: + case 8: + $decodedData['type'] = 'close'; + break; + + // ping frame: + case 9: + $decodedData['type'] = 'ping'; + break; + + // pong frame: + case 10: + $decodedData['type'] = 'pong'; + break; + + default: + return false; + break; + } + + if ($payloadLength === 126) { + $mask = substr($data, 4, 4); + $payloadOffset = 8; + $dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset; + } elseif ($payloadLength === 127) { + $mask = substr($data, 10, 4); + $payloadOffset = 14; + $tmp = ''; + for ($i = 0; $i < 8; $i++) { + $tmp .= sprintf('%08b', ord($data[$i + 2])); + } + $dataLength = bindec($tmp) + $payloadOffset; + unset($tmp); + } else { + $mask = substr($data, 2, 4); + $payloadOffset = 6; + $dataLength = $payloadLength + $payloadOffset; + } + + if ($isMasked === true) { + for ($i = $payloadOffset; $i < $dataLength; $i++) { + $j = $i - $payloadOffset; + if (isset($data[$i])) { + $unmaskedPayload .= $data[$i] ^ $mask[$j % 4]; + } + } + $decodedData['payload'] = $unmaskedPayload; + } else { + $payloadOffset = $payloadOffset - 4; + $decodedData['payload'] = substr($data, $payloadOffset); + } + + return $decodedData; + } + +} diff --git a/vas/rest/class/vmlib/coffeescript/class.jstocoffee.php b/vas/rest/class/vmlib/coffeescript/class.jstocoffee.php new file mode 100755 index 0000000000000000000000000000000000000000..f1341a0d995d4bf5962d985b71291188bdcdfe3c --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/class.jstocoffee.php @@ -0,0 +1,136 @@ +<?php +/** + * Dynamically convert coffeescript to javascript. + * + * @author Simon Samtleben <web@lemmingzshadow.net> + */ +include_once 'coffeescript.php'; + +class JsToCoffee +{ + const CACHING = true; + const CACHING_TYPE = 'file'; // @todo support for memcache + + private $_cacheDir = ''; + private $_coffeeDir = array(); + + public function makeJavascript($coffeeFile) + { + if(false === ($coffeeFile = $this->_getCoffeefilePath($coffeeFile))) + { + return false; + } + + return $this->_getJs($coffeeFile); + } + + private function _getJs($coffeeFile) + { + // get file from cache if possible: + if(self::CACHING === true) + { + $coffeeHash = sha1_file($coffeeFile); + if(file_exists($this->_cacheDir . $coffeeHash)) + { + return file_get_contents($this->_cacheDir . $coffeeHash); + } + } + + // file not cached or cache disabled -> covert, cache, return: + $coffee = file_get_contents($coffeeFile); + try + { + $js = CoffeeScript\compile($coffee); + if(self::CACHING === true) + { + $this->_cacheJs($js, $coffeeFile, $coffeeHash); + } + return $js; + } + catch (Exception $e) + { + var_dump($e); + } + + return false; + } + + private function _cacheJs($js, $coffeeFile, $coffeeHash) + { + // save to cache: + file_put_contents($this->_cacheDir . $coffeeHash, $js); + + // register in cache-content and delete possible old version: + if(!file_exists($this->_cacheDir . 'cache_content')) + { + $cacheConent = array(); + file_put_contents($this->_cacheDir . 'cache_content', serialize($cacheConent)); + } + $temp = file_get_contents($this->_cacheDir . 'cache_content'); + $cacheConent = unserialize($temp); + unset($temp); + + if(isset($cacheConent[$coffeeFile])) + { + unlink($this->_cacheDir . $cacheConent[$coffeeFile]); + unset($cacheConent[$coffeeFile]); + } + $cacheConent[$coffeeFile] = $coffeeHash; + file_put_contents($this->_cacheDir . 'cache_content', serialize($cacheConent)); + unset($cacheConent); + } + + private function _getCoffeefilePath($coffeeFile) + { + $coffeeFile = preg_replace('#[^a-z0-9\.]#', '', $coffeeFile); + foreach($this->_coffeeDir as $coffeeDir) + { + if(file_exists($coffeeDir . $coffeeFile)) + { + return $coffeeDir . $coffeeFile; + } + } + return false; + } + + + /** + * Sets cache folder. + * + * @param string $path Path to cache folder. + * @return bool True if cache path could be set. + */ + public function setCacheDir($path) + { + if(file_exists($path) && is_dir($path)) + { + if(substr($path, 0, -1) !== '/') + { + $path = $path . '/'; + } + $this->_cacheDir = $path; + return true; + } + return false; + } + + /** + * Adds a path with is searched for coffeescripts. + * + * @param string $path Path containing coffeescript. + * @return bool True if path was added. + */ + public function setAllowedCoffeeDir($path) + { + if(file_exists($path) && is_dir($path)) + { + if(substr($path, 0, -1) !== '/') + { + $path = $path . '/'; + } + $this->_coffeeDir[] = $path; + return true; + } + return false; + } +} \ No newline at end of file diff --git a/vas/rest/class/vmlib/coffeescript/classes/errors.php b/vas/rest/class/vmlib/coffeescript/classes/errors.php new file mode 100755 index 0000000000000000000000000000000000000000..437657b472104542981ba9d72f2a205354a074ee --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/errors.php @@ -0,0 +1,15 @@ +<?php + +namespace CoffeeScript; + +class Error extends \Exception +{ + function __construct($message) + { + $this->message = $message; + } +} + +class SyntaxError extends Error {} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/helpers.php b/vas/rest/class/vmlib/coffeescript/classes/helpers.php new file mode 100755 index 0000000000000000000000000000000000000000..eb6f95740ed6fdc96b0714b947995041f2382921 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/helpers.php @@ -0,0 +1,236 @@ +<?php + +namespace CoffeeScript; + +function compact(array $array) +{ + $compacted = array(); + + foreach ($array as $k => $v) + { + if ($v) + { + $compacted[] = $v; + } + } + + return $compacted; +} + +function del( & $obj, $key) +{ + $val = NULL; + + if (isset($obj[$key])) + { + $val = $obj[$key]; + unset($obj[$key]); + } + + return $val; +} + +function extend($obj, $properties) +{ + foreach ($properties as $k => $v) + { + $obj->{$k} = $v; + } + + return $obj; +} + +function flatten(array $array) +{ + $flattened = array(); + + foreach ($array as $k => $v) + { + if (is_array($v)) + { + $flattened = array_merge($flattened, flatten($v)); + } + else + { + $flattened[] = $v; + } + } + + return $flattened; +} + +function & last( & $array, $back = 0) +{ + static $NULL; + $i = count($array) - $back - 1; + + if (isset($array[$i])) + { + return $array[$i]; + } + else + { + // Make sure $NULL is really NULL. + $NULL = NULL; + + return $NULL; + } +} + +/** + * In Jison, token tags can be represented simply using strings, whereas with + * ParserGenerator (a port of Lemon) we're stuck using numeric constants for + * everything. + * + * This function maps those string representations to their numeric constants, + * making it easier to port directly from the CoffeeScript source. + */ +function t($name) +{ + static $map = array( + '.' => 'ACCESSOR', + '[' => 'ARRAY_START', + ']' => 'ARRAY_END', + '@' => 'AT_SIGN', + '=>' => 'BOUND_FUNC', + ':' => 'COLON', + ',' => 'COMMA', + '--' => 'DECREMENT', + '=' => 'EQUALS', + '?' => 'EXISTENTIAL', + '?.' => 'EXISTENTIAL_ACCESSOR', + '->' => 'FUNC', + '++' => 'INCREMENT', + '&' => 'LOGIC', + '&&' => 'LOGIC', + '||' => 'LOGIC', + '-' => 'MINUS', + '{' => 'OBJECT_START', + '}' => 'OBJECT_END', + '(' => 'PAREN_START', + ')' => 'PAREN_END', + '+' => 'PLUS', + '::' => 'PROTOTYPE', + '...' => 'RANGE_EXCLUSIVE', + '..' => 'RANGE_INCLUSIVE', + ); + + if (func_num_args() > 1) + { + $name = func_get_args(); + } + + if (is_array($name) || (func_num_args() > 1 && $name = func_get_args())) + { + $tags = array(); + + foreach ($name as $v) + { + $tags[] = t($v); + } + + return $tags; + } + + $name = 'CoffeeScript\Parser::YY_'.(isset($map[$name]) ? $map[$name] : $name); + + // Don't return the original name if there's no matching constant, in some + // cases intermediate token types are created and the value returned by this + // function still needs to be unique. + return defined($name) ? constant($name) : $name; +} + +/** + * Change a CoffeeScript PHP token tag to it's equivalent canonical form (the + * form used in the JavaScript version). + * + * This function is used for testing purposes only. + */ +function t_canonical($token) +{ + static $map = array( + 'ACCESSOR' => '.', + + // These are separate from INDEX_START and INDEX_END. + 'ARRAY_START' => '[', + 'ARRAY_END' => ']', + + 'AT_SIGN' => '@', + 'BOUND_FUNC' => '=>', + 'COLON' => ':', + 'COMMA' => ',', + 'DECREMENT' => '--', + 'EQUALS' => '=', + 'EXISTENTIAL' => '?', + 'EXISTENTIAL_ACCESSOR' => '?.', + 'FUNC' => '->', + 'INCREMENT' => '++', + 'MINUS' => '-', + 'OBJECT_START' => '{', + 'OBJECT_END' => '}', + + // These are separate from CALL_START and CALL_END. + 'PAREN_START' => '(', + 'PAREN_END' => ')', + + 'PLUS' => '+', + 'PROTOTYPE' => '::', + 'RANGE_EXCLUSIVE' => '...', + 'RANGE_INCLUSIVE' => '..' + ); + + if (is_array($token)) + { + if (is_array($token[0])) + { + for ($i = 0; $i < count($token); $i++) + { + $token[$i] = t_canonical($token[$i]); + } + } + else + { + // Single token. + $token[0] = t_canonical($token[0]); + $token[1] = ''.$token[1]; + } + + return $token; + } + else if (is_numeric($token)) + { + $token = substr(Parser::tokenName($token), 3); + } + else if (is_string($token)) + { + // The token type isn't known to the parser, so t() returned a unique + // string to use instead. + $token = substr($token, strlen('CoffeeScript\Parser::YY_')); + } + + return isset($map[$token]) ? $map[$token] : $token; +} + +class Value +{ + function __construct($v) + { + $this->v = $v; + } + + function __toString() + { + return $this->v; + } +} + +/** + * Wrap a primitive with an object, so that properties can be attached to it + * like in JavaScript. + */ +function wrap($v) +{ + return new Value($v); +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/lexer.php b/vas/rest/class/vmlib/coffeescript/classes/lexer.php new file mode 100755 index 0000000000000000000000000000000000000000..17411c293cf1b9e9cbe0782ec39d5be7866e0a3f --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/lexer.php @@ -0,0 +1,1108 @@ +<?php + +namespace CoffeeScript; + +require_once 'errors.php'; +require_once 'helpers.php'; +require_once 'nodes.php'; +require_once 'rewriter.php'; + +/** + * CoffeeScript lexer. For the most part it's directly from the original + * source code, though there are some relatively minor differences in how it + * works with the parser (since we're using Lemon). + */ +class Lexer +{ + static $COFFEE_ALIASES = array( + 'and' => '&&', + 'or' => '||', + 'is' => '==', + 'isnt' => '!=', + 'not' => '!', + 'yes' => 'true', + 'no' => 'false', + 'on' => 'true', + 'off' => 'false' + ); + + static $COFFEE_KEYWORDS = array( + 'by', + 'loop', + 'of', + 'then', + 'undefined', + 'unless', + 'until', + 'when' + ); + + // exports.RESERVED. + static $COFFEE_RESERVED = array(); + + static $JS_KEYWORDS = array( + 'break', + 'catch', + 'class', + 'continue', + 'debugger', + 'delete', + 'do', + 'else', + 'extends', + 'false', + 'finally', + 'for', + 'if', + 'in', + 'instanceof', + 'new', + 'null', + 'this', + 'throw', + 'typeof', + 'return', + 'switch', + 'super', + 'true', + 'try', + 'while', + ); + + // RESERVED. + static $JS_RESERVED = array( + '__bind', + '__extends', + '__hasProp', + '__indexOf', + '__slice', + 'case', + 'const', + 'default', + 'enum', + 'export', + 'function', + 'import', + 'let', + 'native', + 'var', + 'void', + 'with', + ); + + static $JS_FORBIDDEN = array(); + + static $ASSIGNED = '/^\s*@?([$A-Za-z_][$\w\x7f-\x{ffff}]*|[\'"].*[\'"])[^\n\S]*?[:=][^:=>]/u'; + static $CODE = '/^[-=]>/'; + static $COMMENT = '/^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/'; + static $HEREDOC = '/^("""|\'\'\')([\s\S]*?)(?:\n[^\n\S]*)?\1/'; + static $HEREDOC_INDENT = '/\n+([^\n\S]*)/'; + static $HEREDOC_ILLEGAL = '%\*/%'; + static $HEREGEX = '%^/{3}([\s\S]+?)/{3}([imgy]{0,4})(?!\w)%'; + static $HEREGEX_OMIT = '/\s+(?:#.*)?/'; + static $IDENTIFIER = '/^([$A-Za-z_\x7f-\x{ffff}][$\w\x7f-\x{ffff}]*)([^\n\S]*:(?!:))?/u'; + static $JSTOKEN = '/^`[^\\\\`]*(?:\\\\.[^\\\\`]*)*`/'; + static $LINE_CONTINUER = '/^\s*(?:,|\??\.(?![.\d])|::)/'; + static $MULTI_DENT = '/^(?:\n[^\n\S]*)+/'; + static $MULTILINER = '/\n/'; + static $NO_NEWLINE = '#^(?:[-+*&|/%=<>!.\\\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$#'; + static $NUMBER = '/^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i'; + static $OPERATOR = '#^(?:[-=]>|[-+*/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})#'; + static $REGEX = '%^/(?![\s=])[^[/\n\\\\]*(?:(?:\\\\[\s\S]|\[[^\]\n\\\\]*(?:\\\\[\s\S][^\]\n\\\\]*)*\])[^[/\n\\\\]*)*/[imgy]{0,4}(?!\w)%'; + static $SIMPLESTR = '/^\'[^\\\\\']*(?:\\\\.[^\\\\\']*)*\'/'; + static $TRAILING_SPACES = '/\s+$/'; + static $WHITESPACE = '/^[^\n\S]+/'; + + static $BOOL = array('TRUE', 'FALSE', 'NULL', 'UNDEFINED'); + static $CALLABLE = array('IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'); + static $COMPARE = array('==', '!=', '<', '>', '<=', '>='); + static $COMPOUND_ASSIGN = array('-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=' ); + static $INDEXABLE = array('NUMBER', 'BOOL'); + static $LINE_BREAK = array('INDENT', 'OUTDENT', 'TERMINATOR'); + static $LOGIC = array('&&', '||', '&', '|', '^'); + static $MATH = array('*', '/', '%'); + static $NOT_REGEX = array('NUMBER', 'REGEX', 'BOOL', '++', '--', ']'); + static $NOT_SPACED_REGEX = array(')', '}', 'THIS', 'IDENTIFIER', 'STRING'); + static $RELATION = array('IN', 'OF', 'INSTANCEOF'); + static $SHIFT = array('<<', '>>', '>>>'); + static $UNARY = array('!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'); + + function __construct($code, $options) + { + if (preg_match(self::$WHITESPACE, $code)) + { + $code = "\n{$code}"; + } + + $code = preg_replace(self::$TRAILING_SPACES, '', str_replace("\r", '', $code)); + + $options = array_merge(array( + 'indent' => 0, + 'index' => 0, + 'line' => 0, + 'rewrite' => TRUE + ), + $options); + + $this->code = $code; + $this->chunk = $code; + $this->indent = 0; + $this->indents = array(); + $this->indebt = 0; + $this->index = $options['index']; + $this->length = strlen($this->code); + $this->line = $options['line']; + $this->outdebt = 0; + $this->options = $options; + $this->tokens = array(); + } + + function assignment_error() + { + throw new SyntaxError('Reserved word "'.$this->value().'" on line '.($this->line + 1).' can\'t be assigned'); + } + + function balanced_string($str, $end) + { + $stack = array($end); + $prev = NULL; + + for ($i = 1; $i < strlen($str); $i++) + { + switch ($letter = $str{$i}) + { + case '\\': + $i++; + continue 2; + + case $end: + array_pop($stack); + + if ( ! count($stack)) + { + return substr($str, 0, $i + 1); + } + + $end = $stack[count($stack) - 1]; + continue 2; + } + + if ($end === '}' && ($letter === '"' || $letter === '\'')) + { + $stack[] = $end = $letter; + } + else if ($end === '}' && $letter === '{') + { + $stack[] = $end = '}'; + } + else if ($end === '"' && $prev === '#' && $letter === '{') + { + $stack[] = $end = '}'; + } + + $prev = $letter; + } + + throw new Error('missing '.array_pop($stack).' starting on line '.($this->line + 1)); + } + + function close_indentation() + { + $this->outdent_token($this->indent); + } + + function comment_token() + { + if ( ! preg_match(self::$COMMENT, $this->chunk, $match)) + { + return 0; + } + + $comment = $match[0]; + + if (isset($match[1]) && ($here = $match[1])) + { + $this->token('HERECOMMENT', $this->sanitize_heredoc($here, array( + 'herecomment' => TRUE, + 'indent' => str_pad('', $this->indent) + ))); + + $this->token('TERMINATOR', "\n"); + } + + $this->line += substr_count($comment, "\n"); + + return strlen($comment); + } + + function escape_lines($str, $heredoc = NULL) + { + return preg_replace(self::$MULTILINER, $heredoc ? '\\n' : '', $str); + } + + function heredoc_token() + { + if ( ! preg_match(self::$HEREDOC, $this->chunk, $match)) + { + return 0; + } + + $heredoc = $match[0]; + $quote = $heredoc{0}; + $doc = $this->sanitize_heredoc($match[2], array('quote' => $quote, 'indent' => NULL)); + + if ($quote === '"' && strpos($doc, '#{') !== FALSE) + { + $this->interpolate_string($doc, array('heredoc' => TRUE)); + } + else + { + $this->token('STRING', $this->make_string($doc, $quote, TRUE)); + } + + $this->line += substr_count($heredoc, "\n"); + + return strlen($heredoc); + } + + function heregex_token($match) + { + list($heregex, $body, $flags) = $match; + + if (strpos($body, '#{') === FALSE) + { + $re = preg_replace(self::$HEREGEX_OMIT, '', $body); + $re = preg_replace('/\//', '\\/', $re); + + $this->token('REGEX', '/'.($re ? $re : '(?:)').'/'.$flags); + + return strlen($heregex); + } + + $this->token('IDENTIFIER', 'RegExp'); + $this->tokens[] = array(t('CALL_START'), '('); + + $tokens = array(); + + foreach ($this->interpolate_string($body, array('regex' => TRUE)) as $token) + { + list($tag, $value) = $token; + + if ($tag === 'TOKENS') + { + $tokens = array_merge($tokens, (array) $value); + } + else + { + if ( ! ($value = preg_replace(self::$HEREGEX_OMIT, '', $value))) + { + continue; + } + + $value = preg_replace('/\\\\/', '\\\\\\\\', $value); + $tokens[] = array(t('STRING'), $this->make_string($value, '"', TRUE)); + } + + $tokens[] = array(t('+'), '+'); + } + + array_pop($tokens); + + if ( ! (isset($tokens[0]) && $tokens[0][0] === 'STRING')) + { + array_push($this->tokens, array(t('STRING'), '""'), array(t('+'), '+')); + } + + $this->tokens = array_merge($this->tokens, $tokens); + + if ($flags) + { + array_push($this->tokens, array(t(','), ','), array(t('STRING'), "\"{$flags}\"")); + } + + $this->token(')', ')'); + + return strlen($heregex); + } + + function identifier_error($word) + { + throw new SyntaxError('Reserved word "'.$word.'" on line '.($this->line + 1)); + } + + function identifier_token() + { + if ( ! preg_match(self::$IDENTIFIER, $this->chunk, $match)) + { + return 0; + } + + list($input, $id) = $match; + + $colon = isset($match[2]) ? $match[2] : NULL; + + if ($id === 'own' && $this->tag() === t('FOR')) + { + $this->token('OWN', $id); + + return strlen($id); + } + + $forced_identifier = $colon || ($prev = last($this->tokens)) && + (in_array($prev[0], t('.', '?.', '::')) || + ( ! (isset($prev['spaced']) && $prev['spaced']) && $prev[0] === t('@'))); + + $tag = 'IDENTIFIER'; + + if (in_array($id, self::$JS_KEYWORDS) || ! $forced_identifier && in_array($id, self::$COFFEE_KEYWORDS)) + { + $tag = strtoupper($id); + + if ($tag === 'WHEN' && in_array($this->tag(), t(self::$LINE_BREAK))) + { + $tag = 'LEADING_WHEN'; + } + else if ($tag === 'FOR') + { + $this->seen_for = TRUE; + } + else if ($tag === 'UNLESS') + { + $tag = 'IF'; + } + else if (in_array($tag, self::$UNARY)) + { + $tag = 'UNARY'; + } + else if (in_array($tag, self::$RELATION)) + { + if ($tag !== 'INSTANCEOF' && (isset($this->seen_for) && $this->seen_for)) + { + $tag = 'FOR'.$tag; + $this->seen_for = FALSE; + } + else + { + $tag = 'RELATION'; + + if ($this->value() === '!') + { + array_pop($this->tokens); + $id = '!'. $id; + } + } + } + } + + $reserved = FALSE; + + if (in_array($id, self::$JS_FORBIDDEN, TRUE)) + { + if ($forced_identifier) + { + // TODO: Doing this seems to work just fine. Sometime in the future I + // will take out the nastiness of attaching properties to the token + // rather than directly to the value like below. + $id = wrap($id); + $id->reserved = $reserved = TRUE; + + $tag = 'IDENTIFIER'; + } + else if (in_array($id, self::$JS_RESERVED, TRUE)) + { + $this->identifier_error($id); + } + } + + if ( ! $forced_identifier) + { + if (isset(self::$COFFEE_ALIASES[$id])) + { + $id = self::$COFFEE_ALIASES[$id]; + } + + $map = array( + 'UNARY' => array('!'), + 'COMPARE' => array('==', '!='), + 'LOGIC' => array('&&', '||'), + 'BOOL' => array('true', 'false', 'null', 'undefined'), + 'STATEMENT' => array('break', 'continue', 'debugger') + ); + + foreach ($map as $k => $v) + { + if (in_array($id, $v)) + { + $tag = $k; + break; + } + } + } + + $this->token($tag, $id, array('reserved' => $reserved)); + + if ($colon) + { + $this->token(':', ':'); + } + + return strlen($input); + } + + /** + * Initialize some static variables (called at the end of this file). + */ + static function init() + { + self::$COFFEE_KEYWORDS = array_merge(self::$COFFEE_KEYWORDS, array_keys(self::$COFFEE_ALIASES)); + self::$COFFEE_RESERVED = array_merge(array_merge(self::$JS_RESERVED, self::$JS_KEYWORDS), self::$COFFEE_KEYWORDS); + self::$JS_FORBIDDEN = array_merge(self::$JS_KEYWORDS, self::$JS_RESERVED); + self::$INDEXABLE = array_merge(self::$CALLABLE, self::$INDEXABLE); + self::$NOT_SPACED_REGEX = array_merge(self::$NOT_REGEX, self::$NOT_SPACED_REGEX); + } + + function interpolate_string($str, array $options = array()) // #{0} + { + $options = array_merge(array( + 'heredoc' => '', + 'regex' => NULL + ), + $options); + + $tokens = array(); + $pi = 0; + $i = -1; + + while ( isset($str{++$i}) ) + { + $letter = $str{$i}; + + if ($letter === '\\') + { + $i++; + continue; + } + + if ( ! ($letter === '#' && $str{$i + 1} === '{' && + ($expr = $this->balanced_string(substr($str, $i + 1), '}'))) ) + { + continue; + } + + if ($pi < $i) + { + $tokens[] = array('NEOSTRING', substr($str, $pi, $i - $pi)); + } + + $inner = substr($expr, 1, -1); + + if (strlen($inner)) + { + $lexer = new Lexer($inner, array( + 'line' => $this->line, + 'rewrite' => FALSE, + )); + + $nested = $lexer->tokenize(); + + array_pop($nested); + + if (isset($nested[0]) && $nested[0][0] === t('TERMINATOR')) + { + array_shift($nested); + } + + if ( ($length = count($nested)) ) + { + if ($length > 1) + { + array_unshift($nested, array(t('('), '(')); + $nested[] = array(t(')'), ')'); + } + + $tokens[] = array('TOKENS', $nested); + } + } + + $i += strlen($expr); + $pi = $i + 1; + } + + if ($i > $pi && $pi < strlen($str)) + { + $tokens[] = array('NEOSTRING', substr($str, $pi)); + } + + if ($options['regex']) + { + return $tokens; + } + + if ( ! count($tokens)) + { + return $this->token('STRING', '""'); + } + + if ( ! ($tokens[0][0] === 'NEOSTRING')) + { + array_unshift($tokens, array('', '')); + } + + if ( ($interpolated = count($tokens) > 1) ) + { + $this->token('(', '('); + } + + for ($i = 0; $i < count($tokens); $i++) + { + list($tag, $value) = $tokens[$i]; + + if ($i) + { + $this->token('+', '+'); + } + + if ($tag === 'TOKENS') + { + $this->tokens = array_merge($this->tokens, $value); + } + else + { + $this->token('STRING', $this->make_string($value, '"', $options['heredoc'])); + } + } + + if ($interpolated) + { + $this->token(')', ')'); + } + + return $tokens; + } + + function js_token() + { + if ( ! ($this->chunk{0} === '`' && preg_match(self::$JSTOKEN, $this->chunk, $match))) + { + return 0; + } + + $this->token('JS', substr($script = $match[0], 1, -1)); + + return strlen($script); + } + + function line_token() + { + if ( ! preg_match(self::$MULTI_DENT, $this->chunk, $match)) + { + return 0; + } + + $indent = $match[0]; + $this->line += substr_count($indent, "\n"); + + // $prev = & last($this->tokens, 1); + $size = strlen($indent) - 1 - strrpos($indent, "\n"); + + $no_newlines = $this->unfinished(); + + if (($size - $this->indebt) === $this->indent) + { + if ($no_newlines) + { + $this->suppress_newlines(); + } + else + { + $this->newline_token(); + } + + return strlen($indent); + } + + if ($size > $this->indent) + { + if ($no_newlines) + { + $this->indebt = $size - $this->indent; + $this->suppress_newlines(); + + return strlen($indent); + } + + $diff = $size - $this->indent + $this->outdebt; + + $this->token('INDENT', $diff); + $this->indents[] = $diff; + $this->outdebt = $this->indebt = 0; + } + else + { + $this->indebt = 0; + $this->outdent_token($this->indent - $size, $no_newlines); + } + + $this->indent = $size; + + return strlen($indent); + } + + function literal_token() + { + if (preg_match(self::$OPERATOR, $this->chunk, $match)) + { + list($value) = $match; + + if (preg_match(self::$CODE, $value)) + { + $this->tag_parameters(); + } + } + else + { + $value = $this->chunk{0}; + } + + $tag = $value; + $prev = & last($this->tokens); + + if ($value === '=' && $prev) + { + if (isset($prev['reserved']) && $prev['reserved'] && in_array($prev[1], t(self::$JS_FORBIDDEN))) + { + $this->assignment_error(); + } + + if (in_array($prev[1], array('||', '&&'))) + { + $prev[0] = t('COMPOUND_ASSIGN'); + $prev[1] .= '='; + + return 1; // strlen($value); + } + } + + $map = array( + 'TERMINATOR' => array(';'), + 'MATH' => self::$MATH, + 'COMPARE' => self::$COMPARE, + 'COMPOUND_ASSIGN' => self::$COMPOUND_ASSIGN, + 'UNARY' => self::$UNARY, + 'SHIFT' => self::$SHIFT + ); + + $mapped = FALSE; + + foreach ($map as $k => $v) + { + if (in_array($value, $v)) + { + $tag = $k; + $mapped = TRUE; + + break; + } + } + + if ( ! $mapped) + { + if (in_array($value, self::$LOGIC) || $value === '?' && ($prev && isset($prev['spaced']) && $prev['spaced'])) + { + $tag = 'LOGIC'; + } + else if ($prev && ! (isset($prev['spaced']) && $prev['spaced'])) + { + if ($value === '(' && in_array($prev[0], t(self::$CALLABLE))) + { + if ($prev[0] === t('?')) + { + $prev[0] = t('FUNC_EXIST'); + } + + $tag = 'CALL_START'; + } + else if ($value === '[' && in_array($prev[0], t(self::$INDEXABLE))) + { + $tag = 'INDEX_START'; + + if ($prev[0] === t('?')) + { + $prev[0] = t('INDEX_SOAK'); + } + else if ($prev[0] === t('::')) + { + $prev[0] = t('INDEX_PROTO'); + } + } + } + } + + $this->token($tag, $value); + + return strlen($value); + } + + function make_string($body, $quote, $heredoc = NULL) + { + if ( ! $body) + { + return $quote.$quote; + } + + $body = preg_replace_callback('/\\\\([\s\S])/', function($match) use ($quote) + { + $contents = $match[1]; + + if (in_array($contents, array("\n", $quote))) + { + return $contents; + } + + return $match[0]; + }, + $body); + + $body = preg_replace('/'.$quote.'/', '\\\\$0', $body); + + return $quote.$this->escape_lines($body, $heredoc).$quote; + } + + function newline_token() + { + if ($this->tag() !== t('TERMINATOR')) + { + $this->token('TERMINATOR', "\n"); + } + } + + function number_token() + { + if ( ! preg_match(self::$NUMBER, $this->chunk, $match)) + { + return 0; + } + + $this->token('NUMBER', $number = $match[0]); + + return strlen($number); + } + + function outdent_token($move_out, $no_newlines = FALSE, $close = NULL) + { + while ($move_out > 0) + { + $len = count($this->indents) - 1; + + if ( ! isset($this->indents[$len])) + { + $move_out = 0; + } + else if ($this->indents[$len] === $this->outdebt) + { + $move_out -= $this->outdebt; + $this->outdebt = 0; + } + else if ($this->indents[$len] < $this->outdebt) + { + $this->outdebt -= $this->indents[$len]; + $move_out -= $this->indents[$len]; + } + else + { + $dent = array_pop($this->indents) - $this->outdebt; + $move_out -= $dent; + $this->outdebt = 0; + $this->token('OUTDENT', $dent); + } + } + + if (isset($dent) && $dent) + { + $this->outdebt -= $move_out; + } + + if ( ! ($this->tag() === t('TERMINATOR') || $no_newlines)) + { + $this->token('TERMINATOR', "\n"); + } + + return $this; + } + + function regex_token() + { + if ($this->chunk{0} !== '/') + { + return 0; + } + + if (preg_match(self::$HEREGEX, $this->chunk, $match)) + { + $length = $this->heregex_token($match); + + // This seems to be broken in the JavaScript compiler... + // $this->line += substr_count($match[0], "\n"); + + return $length; + } + + $prev = last($this->tokens); + + if ($prev) + { + if (in_array($prev[0], t((isset($prev['spaced']) && $prev['spaced']) ? + self::$NOT_REGEX : self::$NOT_SPACED_REGEX))) + { + return 0; + } + } + + if ( ! preg_match(self::$REGEX, $this->chunk, $match)) + { + return 0; + } + + $regex = $match[0]; + + $this->token('REGEX', $regex === '//' ? '/(?:)/' : $regex); + + return strlen($regex); + } + + function sanitize_heredoc($doc, array $options) + { + $herecomment = isset($options['herecomment']) ? $options['herecomment'] : NULL; + $indent = isset($options['indent']) ? $options['indent'] : NULL; + + if ($herecomment) + { + if (preg_match(self::$HEREDOC_ILLEGAL, $doc)) + { + throw new Error('block comment cannot contain \"*/\", starting on line '.($line + 1)); + } + + if (strpos($doc, "\n") == 0) // No match or 0 + { + return $doc; + } + } + else + { + $offset = 0; + + while (preg_match(self::$HEREDOC_INDENT, $doc, $match, PREG_OFFSET_CAPTURE, $offset)) + { + $attempt = $match[1][0]; + $offset = strlen($match[0][0]) + $match[0][1]; + + if ( is_null($indent) || (strlen($indent) > strlen($attempt) && strlen($attempt) > 0)) + { + $indent = $attempt; + } + } + } + + if ($indent) + { + $doc = preg_replace('/\n'.$indent.'/', "\n", $doc); + } + + if ( ! $herecomment) + { + $doc = preg_replace('/^\n/', '', $doc); + } + + return $doc; + } + + function string_token() + { + switch ($this->chunk{0}) + { + case "'": + if ( ! preg_match(self::$SIMPLESTR, $this->chunk, $match)) + { + return 0; + } + + $this->token('STRING', preg_replace(self::$MULTILINER, "\\\n", $string = $match[0])); + break; + + case '"': + if ( ! ($string = $this->balanced_string($this->chunk, '"'))) + { + return 0; + } + + if (strpos($string, '#{', 1) > 0) + { + $this->interpolate_string(substr($string, 1, -1)); + } + else + { + $this->token('STRING', $this->escape_lines($string)); + } + + break; + + default: + return 0; + } + + $this->line += substr_count($string, "\n"); + + return strlen($string); + } + + function suppress_newlines() + { + if ($this->value() === '\\') + { + array_pop($this->tokens); + } + } + + function tag($index = 0, $tag = NULL) + { + $token = & last($this->tokens, $index); + + if ( ! is_null($tag)) + { + $token[0] = $tag; + } + + return $token[0]; + } + + function tag_parameters() + { + if ($this->tag() !== t(')')) + { + return $this; + } + + $stack = array(); + $tokens = &$this->tokens; + + $i = count($tokens); + $tokens[--$i][0] = t('PARAM_END'); + + while ( ($tok = &$tokens[--$i]) ) + { + if ($tok[0] === t(')')) + { + $stack[] = $tok; + } + else if (in_array($tok[0], t('(', 'CALL_START'))) + { + if (count($stack)) + { + array_pop($stack); + } + else if ($tok[0] === t('(')) + { + $tok[0] = t('PARAM_START'); + return $this; + } + } + } + + return $this; + } + + function token($tag, $value = NULL, $props = array()) + { + if ( ! is_numeric($tag)) + { + $tag = t($tag); + } + + $token = array($tag, $value, $this->line); + + if ($props) + { + foreach ($props as $k => $v) + { + $token[$k] = $v; + } + } + + return ($this->tokens[] = $token); + } + + function tokenize() + { + while ( ($this->chunk = substr($this->code, $this->index)) !== FALSE ) + { + $types = array('identifier', 'comment', 'whitespace', 'line', 'heredoc', + 'string', 'number', 'regex', 'js', 'literal'); + + foreach ($types as $type) + { + if ( ($d = $this->{$type.'_token'}()) ) + { + $this->index += $d; + break; + } + } + } + + $this->close_indentation(); + + if ($this->options['rewrite']) + { + $rewriter = new Rewriter($this->tokens); + $this->tokens = $rewriter->rewrite(); + } + + return $this->tokens; + } + + function value($index = 0, $value = NULL) + { + $token = & last($this->tokens, $index); + + if ( ! is_null($value)) + { + $token[1] = $value; + } + + return $token[1]; + } + + function unfinished() + { + return + preg_match(self::$LINE_CONTINUER, $this->chunk) || + ($prev = last($this->tokens, 1)) && + ($prev[0] !== t('.')) && + ($value = $this->value()) && + // ( ! (isset($value->reserved) && $value->reserved)) && + ( ! (isset($prev['reserved']) && $prev['reserved'])) && + preg_match(self::$NO_NEWLINE, $value) && + ( ! preg_match(self::$CODE, $value)) && + ( ! preg_match(self::$ASSIGNED, $this->chunk)); + } + + function whitespace_token() + { + if ( ! (preg_match(self::$WHITESPACE, $this->chunk, $match) || ($nline = ($this->chunk{0} === "\n")))) + { + return 0; + } + + $prev = & last($this->tokens); + + if ($prev) + { + $prev[$match ? 'spaced' : 'newLine'] = TRUE; + } + + return $match ? strlen($match[0]) : 0; + } +} + +Lexer::init(); + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes.php b/vas/rest/class/vmlib/coffeescript/classes/nodes.php new file mode 100755 index 0000000000000000000000000000000000000000..70e8769b37ed00a49ff778ad367ee8fcc6199fed --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes.php @@ -0,0 +1,137 @@ +<?php + +namespace CoffeeScript; + +require_once 'helpers.php'; +require_once 'scope.php'; + +define('LEVEL_TOP', 1); +define('LEVEL_PAREN', 2); +define('LEVEL_LIST', 3); +define('LEVEL_COND', 4); +define('LEVEL_OP', 5); +define('LEVEL_ACCESS', 6); + +define('TAB', ' '); + +define('IDENTIFIER', '/^[$A-Za-z_\x7f-\x{ffff}][$\w\x7f-\x{ffff}]*$/u'); +define('IS_STRING', '/^[\'"]/'); +define('SIMPLENUM', '/^[+-]?\d+$/'); + +$UTILITIES = array( + 'hasProp' => 'Object.prototype.hasOwnProperty', + 'slice' => 'Array.prototype.slice' +); + +$UTILITIES['bind'] = <<<'BIND' +function(fn, me){ return function(){ return fn.apply(me, arguments); }; } +BIND; + +$UTILITIES['extends'] = <<<'EXTENDS' +function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; +} +EXTENDS; + +$UTILITIES['indexOf'] = <<<'INDEXOF' +Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; +} +INDEXOF; + +function multident($code, $tab) +{ + return preg_replace('/\n/', "\n{$tab}", $code); +} + +function unfold_soak($options, $parent, $name) +{ + if ( ! (isset($parent->{$name}) && $parent->{$name} && $ifn = $parent->{$name}->unfold_soak($options))) + { + return; + } + + $parent->{$name} = $ifn->body; + $ifn->body = yy('Value', $parent); + + return $ifn; +} + +function utility($name) +{ + global $UTILITIES; + + Scope::$root->assign($ref = "__$name", $UTILITIES[$name]); + + return $ref; +} + +/** + * Since PHP can't return values from __construct, and some of the node + * classes rely heavily on this feature in JavaScript, we use this function + * instead of the new keyword to instantiate and implicitly call the + * constructor. + */ +function yy($type) +{ + $args = func_get_args(); + array_shift($args); + + $type = __NAMESPACE__.'\yy_'.$type; + + $inst = new $type; + $inst = call_user_func_array(array($inst, 'constructor'), $args); + + return $inst; +} + +// Base class. +require_once 'nodes/base.php'; + +$nodes = array( + 'access', + 'arr', + 'assign', + 'block', + 'call', + 'class', + 'closure', + 'code', + 'comment', + 'existence', + 'extends', + 'for', + 'if', + 'in', + 'index', + 'literal', + 'obj', + 'op', + 'param', + 'parens', + 'push', + 'range', + 'return', + 'slice', + 'splat', + 'switch', + 'throw', + 'try', + 'value', + 'while' +); + +foreach ($nodes as $node) +{ + require_once "nodes/{$node}.php"; +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/access.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/access.php new file mode 100755 index 0000000000000000000000000000000000000000..a98d2ae4b2af306088710087b565a485be6a04d3 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/access.php @@ -0,0 +1,32 @@ +<?php + +namespace CoffeeScript; + +class yy_Access extends yy_Base +{ + public $children = array('name'); + + function constructor($name, $tag = NULL) + { + $this->name = $name; + $this->name->as_key = TRUE; + + $this->proto = $tag === 'proto' ? '.prototype' : ''; + $this->soak = $tag === 'soak'; + + return $this; + } + + function compile($options, $level = NULL) + { + $name = $this->name->compile($options); + return $this->proto.(preg_match(IS_STRING, $name) ? "[{$name}]" : ".{$name}"); + } + + function is_complex() + { + return FALSE; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/arr.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/arr.php new file mode 100755 index 0000000000000000000000000000000000000000..cb37656802d2aee7fa92f7b3a93dbe2f2fd8ae00 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/arr.php @@ -0,0 +1,69 @@ +<?php + +namespace CoffeeScript; + +class yy_Arr extends yy_Base +{ + public $children = array('objects'); + + function constructor($objs) + { + $this->objects = $objs ? $objs : array(); + + return $this; + } + + function assigns($name) + { + foreach ($this->objects as $obj) + { + if ($obj->assigns($name)) + { + return TRUE; + } + } + + return FALSE; + } + + function compile_node($options) + { + if ( ! count($options)) + { + return '[]'; + } + + $options['indent'] .= TAB; + $objs = $this->filter_implicit_objects($this->objects); + + if (($code = yy_Splat::compile_splatted_array($options, $objs))) + { + return $code; + } + + $code = array(); + + foreach ($objs as $obj) + { + $code[] = $obj->compile($options); + } + + $code = implode(', ', $code); + + if (strpos($code, "\n") !== FALSE) + { + return "[\n{$options['indent']}{$code}\n{$this->tab}]"; + } + else + { + return "[{$code}]"; + } + } + + function filter_implicit_objects() + { + return call_user_func_array(array(yy('Call'), __FUNCTION__), func_get_args()); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/assign.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/assign.php new file mode 100755 index 0000000000000000000000000000000000000000..e7d2e2ca42526250dfc1b1208195257c0420ddaa --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/assign.php @@ -0,0 +1,300 @@ +<?php + +namespace CoffeeScript; + +class yy_Assign extends yy_Base +{ + public $children = array('variable', 'value'); + + const METHOD_DEF = '/^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\x{ffff}]*)$/u'; + + function constructor($variable, $value, $context = '', $options = NULL) + { + $this->variable = $variable; + $this->value = $value; + $this->context = $context; + $this->param = $options ? $options['param'] : NULL; + + return $this; + } + + function assigns($name) + { + if ($this->context === 'object') + { + return $this->value->assigns($name); + } + else + { + return $this->variable->assigns($name); + } + } + + function compile_conditional($options) + { + list($left, $rite) = $this->variable->cache_reference($options); + $tmp = yy('Op', substr($this->context, 0, -1), $left, yy('Assign', $rite, $this->value, '=')); + + return $tmp->compile($options); + } + + function compile_node($options) + { + if (($is_value = ($this->variable instanceof yy_Value))) + { + if ($this->variable->is_array() || $this->variable->is_object()) + { + return $this->compile_pattern_match($options); + } + + if ($this->variable->is_splice()) + { + return $this->compile_splice($options); + } + + if (in_array($this->context, array('||=', '&&=', '?='), TRUE)) + { + return $this->compile_conditional($options); + } + } + + $name = $this->variable->compile($options, LEVEL_LIST); + + if ( ! ($this->context || $this->variable->is_assignable())) + { + throw new SyntaxError('"'.$this->variable->compile($options).'" cannot be assigned.'); + } + + if ( ! ($this->context || $is_value && + ((isset($this->variable->namespaced) && $this->variable->namespaced) || + $this->variable->has_properties()))) + { + if ($this->param) + { + $options['scope']->add($name, 'var'); + } + else + { + $options['scope']->find($name); + } + } + + if ($this->value instanceof yy_Code && preg_match(self::METHOD_DEF, $name, $match)) + { + $this->value->name = $match[2]; + + if (isset($match[1]) && $match[1]) + { + $this->value->klass = $match[1]; + } + } + + $val = $this->value->compile($options, LEVEL_LIST); + + if ($this->context === 'object') + { + return "{$name}: {$val}"; + } + + $val = $name.' '.($this->context ? $this->context : '=').' '.$val; + + return $options['level'] <= LEVEL_LIST ? $val : "({$val})"; + } + + function compile_pattern_match($options) + { + $top = $options['level'] === LEVEL_TOP; + $value = $this->value; + $objects = $this->variable->base->objects; + + if ( ! ($olen = count($objects))) + { + $code = $value->compile($options); + return $options['level'] >= LEVEL_OP ? "({$code})" : $code; + } + + $is_object = $this->variable->is_object(); + + if ($top && $olen === 1 && ! (($obj = $objects[0]) instanceof yy_Splat)) + { + if ($obj instanceof yy_Assign) + { + $idx = $obj->variable->base; + $obj = $obj->value; + } + else + { + if ($obj->base instanceof yy_Parens) + { + $tmp = yy('Value', $obj->unwrap_all()); + list($obj, $idx) = $tmp->cache_reference($options); + } + else + { + if ($is_object) + { + $idx = $obj->this ? $obj->properties[0]->name : $obj; + } + else + { + $idx = yy('Literal', 0); + } + } + } + + $acc = preg_match(IDENTIFIER, $idx->unwrap()->value); + $value = yy('Value', $value); + + if ($acc) + { + $value->properties[] = yy('Access', $idx); + } + else + { + $value->properties[] = yy('Index', $idx); + } + + $tmp = yy('Assign', $obj, $value); + + return $tmp->compile($options); + } + + $vvar = $value->compile($options, LEVEL_LIST); + $assigns = array(); + $splat = FALSE; + + if ( ! preg_match(IDENTIFIER, $vvar) || $this->variable->assigns($vvar)) + { + $assigns[] = ($ref = $options['scope']->free_variable('ref')).' = '.$vvar; + $vvar = $ref; + } + + foreach ($objects as $i => $obj) + { + $idx = $i; + + if ($is_object) + { + if ($obj instanceof yy_Assign) + { + $idx = $obj->variable->base; + $obj = $obj->value; + } + else + { + if ($obj->base instanceof yy_Parens) + { + $tmp = yy('Value', $obj->unwrap_all()); + list($obj, $idx) = $tmp->cache_reference($options); + } + else + { + $idx = $obj->this ? $obj->properties[0]->name : $obj; + } + } + } + + if ( ! $splat && ($obj instanceof yy_Splat)) + { + $val = "{$olen} <= {$vvar}.length ? ".utility('slice').".call({$vvar}, {$i}"; + $ivar = 'undefined'; + + if (($rest = $olen - $i - 1)) + { + $ivar = $options['scope']->free_variable('i'); + $val .= ", {$ivar} = {$vvar}.length - {$rest}) : ({$ivar} = {$i}, [])"; + } + else + { + $val .= ') : []'; + } + + $val = yy('Literal', $val); + $splat = "{$ivar}++"; + } + else + { + if ($obj instanceof yy_Splat) + { + $obj = $obj->name->compile($options); + throw SyntaxError("multiple splats are disallowed in an assignment: {$obj} ..."); + } + + if (is_numeric($idx)) + { + $idx = yy('Literal', $splat ? $splat : $idx); + $acc = FALSE; + } + else + { + $acc = $is_object ? preg_match(IDENTIFIER, $idx->unwrap()->value) : 0; + } + + $val = yy('Value', yy('Literal', $vvar), array($acc ? yy('Access', $idx) : yy('Index', $idx))); + } + + $tmp = yy('Assign', $obj, $val, NULL, array('param' => $this->param)); + $assigns[] = $tmp->compile($options, LEVEL_TOP); + } + + if ( ! $top) + { + $assigns[] = $vvar; + } + + $code = implode(', ', $assigns); + + return $options['level'] < LEVEL_LIST ? $code : "({$code})"; + } + + function compile_splice($options) + { + $tmp = array_pop($this->variable->properties); + + $from = $tmp->range->from; + $to = $tmp->range->to; + $exclusive = $tmp->range->exclusive; + + $name = $this->variable->compile($options); + + list($from_decl, $from_ref) = $from ? $from->cache($options, LEVEL_OP) : array('0', '0'); + + if ($to) + { + if (($from && $from->is_simple_number()) && $to->is_simple_number()) + { + $to = intval($to->compile($options)) - intval($from_ref); + + if ( ! $exclusive) + { + $to++; + } + } + else + { + $to = $to->compile($options).' - '. $from_ref; + + if ( ! $exclusive) + { + $to .= ' + 1'; + } + } + } + else + { + $to = '9e9'; + } + + list($val_def, $val_ref) = $this->value->cache($options, LEVEL_LIST); + + $code = "[].splice.apply({$name}, [{$from_decl}, {$to}].concat({$val_def})), {$val_ref}"; + return $options['level'] > LEVEL_TOP ? "({$code})" : $code; + } + + function unfold_soak($options) + { + return unfold_soak($options, $this, 'variable'); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/base.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/base.php new file mode 100755 index 0000000000000000000000000000000000000000..05b570eba71b77849389d1911c8cdcfe11deb921 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/base.php @@ -0,0 +1,279 @@ +<?php + +namespace CoffeeScript; + +class yy_Base +{ + public $as_key = FALSE; + public $assigns = FALSE; + public $children = array(); + public $ctor = NULL; + public $exclusive = NULL; + public $expression = NULL; + public $from = NULL; + public $front = NULL; + public $namespaced = FALSE; + public $negated = FALSE; + public $no_return = FALSE; + public $proto = FALSE; + public $soak = FALSE; + public $this = NULL; + public $to = NULL; + + function __construct() {} + + function constructor() { return $this; } + + function __toString() + { + return ''.$this->to_string(); + } + + function cache($options, $level = NULL, $reused = NULL) + { + if ( ! $this->is_complex()) + { + $ref = $level ? $this->compile($options, $level) : $this; + return array($ref, $ref); + } + else + { + $ref = yy('Literal', $reused ? $reused : $options['scope']->free_variable('ref')); + $sub = yy('Assign', $ref, $this); + + if ($level) + { + return array($sub->compile($options, $level), $ref->value); + } + else + { + return array($sub, $ref); + } + } + } + + function compile($options, $level = NULL) + { + if ($level) + { + $options['level'] = $level; + } + + if ( ! ($node = $this->unfold_soak($options))) + { + $node = $this; + } + + $node->tab = $options['indent']; + + if ($options['level'] === LEVEL_TOP || ! $node->is_statement($options)) + { + return $node->compile_node($options); + } + + return $node->compile_closure($options); + } + + function compile_closure($options) + { + if ($this->jumps() || ($this instanceof yy_Throw)) + { + throw new SyntaxError('cannot use a pure statement in an expression.'); + } + + $options['shared_scope'] = TRUE; + + $closure = yy_Closure::wrap($this); + return $closure->compile_node($options); + } + + function compile_loop_reference($options, $name) + { + $src = $tmp = $this->compile($options, LEVEL_LIST); + + if ( ! (abs($src) < INF || preg_match(IDENTIFIER, $src) && + $options['scope']->check($src, TRUE))) + { + $src = ($tmp = $options['scope']->free_variable($name)).' = '.$src; + } + + return array($src, $tmp); + } + + function contains($pred) + { + $contains = FALSE; + + if (is_string($pred)) + { + $tmp = __NAMESPACE__.'\\'.$pred; + + $pred = function($node) use ($tmp) + { + return call_user_func($tmp, $node); + }; + } + + $this->traverse_children(FALSE, function($node) use ( & $contains, & $pred) + { + if ($pred($node)) + { + $contains = TRUE; + return FALSE; + } + }); + + return $contains; + } + + function contains_type($type) + { + return ($this instanceof $type) || $this->contains(function($node) use ( & $type) + { + return $node instanceof $type; + }); + } + + function each_child($func) + { + if ( ! ($this->children)) + { + return $this; + } + + foreach ($this->children as $i => $attr) + { + if (isset($this->{$attr}) && $this->{$attr}) + { + foreach (flatten(array($this->{$attr})) as $i => $child) + { + if ($func($child) === FALSE) + { + break 2; + } + } + } + } + + return $this; + } + + function invert() + { + return yy('Op', '!', $this); + } + + function is_assignable() + { + return FALSE; + } + + function is_complex() + { + return FALSE; + } + + function is_chainable() + { + return FALSE; + } + + function is_object() + { + return FALSE; + } + + function is_statement() + { + return FALSE; + } + + function is_undefined() + { + return FALSE; + } + + function jumps() + { + return FALSE; + } + + function last_non_comment($list) + { + $i = count($list); + + while ($i--) + { + if ( ! ($list[$i] instanceof yy_Comment)) + { + return $list[$i]; + } + } + + return NULL; + } + + function make_return() + { + return yy('Return', $this); + } + + function to_string($idt = '', $name = NULL) + { + if ($name === NULL) + { + $name = get_class($this); + } + + $tree = "\n{$idt}{$name}"; + + if ($this->soak) + { + $tree .= '?'; + } + + $this->each_child(function($node) use ($idt, & $tree) + { + $tree .= $node->to_string($idt.TAB); + }); + + return $tree; + } + + function traverse_children($cross_scope, $func) + { + $this->each_child(function($child) use ($cross_scope, & $func) + { + if ($func($child) === FALSE) + { + return FALSE; + } + + return $child->traverse_children($cross_scope, $func); + }); + } + + function unfold_soak($options) + { + return FALSE; + } + + function unwrap() + { + return $this; + } + + function unwrap_all() + { + $node = $this; + + while ($node !== ($node = $node->unwrap())) + { + continue; + } + + return $node; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/block.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/block.php new file mode 100755 index 0000000000000000000000000000000000000000..5fadbf914a172369c8e76a9f3d2a142772a05781 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/block.php @@ -0,0 +1,226 @@ +<?php + +namespace CoffeeScript; + +class yy_Block extends yy_Base +{ + public $children = array('expressions'); + + function constructor($nodes = array()) + { + $this->expressions = compact(flatten($nodes)); + + return $this; + } + + function compile($options, $level = NULL) + { + if (isset($options['scope'])) + { + return parent::compile($options, $level); + } + else + { + return $this->compile_root($options); + } + } + + function compile_node($options) + { + $this->tab = $options['indent']; + + $top = $options['level'] === LEVEL_TOP; + $codes = array(); + + foreach ($this->expressions as $i => $node) + { + $node = $node->unwrap_all(); + $node = ($tmp = $node->unfold_soak($options)) ? $tmp : $node; + + if ($top) + { + $node->front = TRUE; + $code = $node->compile($options); + + if ($node->is_statement($options)) + { + $codes[] = $code; + } + else + { + $codes[] = $this->tab.$code.';'; + } + } + else + { + $codes[] = $node->compile($options, LEVEL_LIST); + } + } + + if ($top) + { + return implode("\n", $codes); + } + + $code = ($tmp = implode(', ', $codes)) ? $tmp : 'void 0'; + + if (count($codes) && $options['level'] >= LEVEL_LIST) + { + return "({$code})"; + } + else + { + return $code; + } + } + + function compile_root($options) + { + $options['indent'] = ($this->tab = isset($options['bare']) && $options['bare'] ? '' : TAB); + $options['scope'] = new Scope(NULL, $this, NULL); + $options['level'] = LEVEL_TOP; + + $code = $this->compile_with_declarations($options); + + return (isset($options['bare']) && $options['bare']) ? $code : + "(function() {\n{$code}\n}).call(this);\n"; + } + + function compile_with_declarations($options) + { + $code = $post = ''; + + foreach ($this->expressions as $i => $expr) + { + $expr = $expr->unwrap(); + + if ( ! ($expr instanceof yy_Comment || $expr instanceof yy_Literal)) + { + break; + } + } + + $options = array_merge($options, array('level' => LEVEL_TOP)); + + if ($i) + { + $rest = array_splice($this->expressions, $i, count($this->expressions)); + $code = $this->compile_node($options); + + $this->expressions = $rest; + } + + $post = $this->compile_node($options); + + $scope = $options['scope']; + + if ($scope->expressions === $this) + { + if ($scope->has_declarations()) + { + $code .= $this->tab.'var '.implode(', ', $scope->declared_variables()).";\n"; + } + + if ($scope->has_assignments()) + { + $code .= $this->tab.'var '.multident(implode(', ', $scope->assigned_variables()), $this->tab).";\n"; + } + } + + return $code.$post; + } + + function is_empty() + { + return ! count($this->expressions); + } + + function is_statement($options) + { + foreach ($this->expressions as $i => $expr) + { + if ($expr->is_statement($options)) + { + return TRUE; + } + } + + return FALSE; + } + + function jumps($options = array()) + { + foreach ($this->expressions as $i => $expr) + { + if ($expr->jumps($options)) + { + return $expr; + } + } + + return FALSE; + } + + function make_return() + { + $len = count($this->expressions); + + while ($len--) + { + $expr = $this->expressions[$len]; + + if ( ! ($expr instanceof yy_Comment)) + { + $this->expressions[$len] = $expr->make_return(); + + if ($expr instanceof yy_Return && ! $expr->expression) + { + return array_splice($this->expressions, $len, 1); + } + + break; + } + } + + return $this; + } + + function pop() + { + return array_pop($this->expressions); + } + + function push($node) + { + $this->expressions[] = $node; + return $this; + } + + function unshift($node) + { + array_unshift($this->expressions, $node); + return $this; + } + + function unwrap() + { + return count($this->expressions) === 1 ? $this->expressions[0] : $this; + } + + static function wrap($nodes) + { + if ( ! is_array($nodes)) + { + $nodes = array($nodes); + } + + if (count($nodes) === 1 && $nodes[0] instanceof yy_Block) + { + return $nodes[0]; + } + + return yy('Block', $nodes); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/call.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/call.php new file mode 100755 index 0000000000000000000000000000000000000000..a942919984a4f5af93da180d38235287be3b3f66 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/call.php @@ -0,0 +1,271 @@ +<?php + +namespace CoffeeScript; + +class yy_Call extends yy_Base +{ + public $children = array('variable', 'args'); + + private $is_new; + private $is_super; + + function constructor($variable = NULL, $args = array(), $soak = FALSE) + { + $this->args = $args; + $this->is_new = FALSE; + $this->is_super = $variable === 'super'; + $this->variable = $this->is_super() ? NULL : $variable; + + return $this; + } + + function compile_node($options) + { + if ($this->variable) + { + $this->variable->front = $this->front; + } + + if (($code = yy_Splat::compile_splatted_array($options, $this->args, TRUE))) + { + return $this->compile_splat($options, $code); + } + + $args = $this->filter_implicit_objects($this->args); + $tmp = array(); + + foreach ($args as $arg) + { + $tmp[] = $arg->compile($options, LEVEL_LIST); + } + + $args = implode(', ', $tmp); + + if ($this->is_super()) + { + return $this->super_reference($options).'.call(this'.($args ? ', '.$args : '').')'; + } + else + { + return ($this->is_new() ? 'new ' : '').$this->variable->compile($options, LEVEL_ACCESS)."({$args})"; + } + } + + function compile_super($args, $options) + { + return $this->super_reference($options).'.call(this'.(count($args) ? ', ' : '').$args.')'; + } + + function compile_splat($options, $splat_args) + { + if ($this->is_super()) + { + return $this->super_reference($options).'.apply(this, '.$splat_args.')'; + } + + if ($this->is_new()) + { + $idt = $this->tab.TAB; + + return + "(function(func, args, ctor) {\n" + . "{$idt}ctor.prototype = func.prototype;\n" + . "{$idt}var child = new ctor, result = func.apply(child, args);\n" + . "{$idt}return typeof result === \"object\" ? result : child;\n" + . "{$this->tab}})(".$this->variable->compile($options, LEVEL_LIST).", $splat_args, function() {})"; + } + + $base = yy('Value', $this->variable); + + if (($name = array_pop($base->properties)) && $base->is_complex()) + { + $ref = $options['scope']->free_variable('ref'); + $fun = "($ref = ".$base->compile($options, LEVEL_LIST).')'.$name->compile($options).''; + } + else + { + $fun = $base->compile($options, LEVEL_ACCESS); + $fun = preg_match(SIMPLENUM, $fun) ? "($fun)" : $fun; + + if ($name) + { + $ref = $fun; + $fun .= $name->compile($options); + } + else + { + $ref = NULL; + } + } + + return "{$fun}.apply({$ref}, {$splat_args})"; + } + + function is_new($set = NULL) + { + if ($set !== NULL) + { + $this->is_new = !! $set; + } + + return $this->is_new; + } + + function is_super() + { + return $this->is_super; + } + + function filter_implicit_objects($list) + { + $nodes = array(); + + foreach ($list as $node) + { + if ( ! ($node->is_object() && $node->base->generated)) + { + $nodes[] = $node; + continue; + } + + $obj = $tmp = NULL; + + foreach ($node->base->properties as $prop) + { + if ($prop instanceof yy_Assign) + { + if ( ! $obj) + { + $nodes[] = ($obj = $tmp = yy('Obj', array(), TRUE)); + } + + $tmp->properties[] = $prop; + } + else + { + $nodes[] = $prop; + $obj = NULL; + } + } + } + + return $nodes; + } + + function new_instance() + { + $base = isset($this->variable->base) ? $this->variable->base : $this->variable; + + if ($base instanceof yy_Call) + { + $base->new_instance(); + } + else + { + $this->is_new = TRUE; + } + + return $this; + } + + function super_reference($options) + { + $method = $options['scope']->method; + + if ( ! $method) + { + throw SyntaxError('cannot call super outside of a function.'); + } + + $name = $method->name; + + if ( ! $name) + { + throw SyntaxError('cannot call super on an anonymous function.'); + } + + if (isset($method->klass) && $method->klass) + { + return $method->klass.'.__super__.'.$name; + } + else + { + return $name.'.__super__.constructor'; + } + } + + function unfold_soak($options) + { + if ($this->soak) + { + if ($this->variable) + { + if ($ifn = unfold_soak($options, $this, 'variable')) + { + return $ifn; + } + + $tmp = yy('Value', $this->variable); + list($left, $rite) = $tmp->cache_reference($options); + } + else + { + $left = yy('Literal', $this->super_reference($options)); + $rite = yy('Value', $left); + } + + $rite = yy('Call', $rite, $this->args); + $rite->is_new($this->is_new()); + $left = yy('Literal', 'typeof '.$left->compile($options).' === "function"'); + + return yy('If', $left, yy('Value', $rite), array('soak' => TRUE)); + } + + $call = $this; + $list = array(); + + while (TRUE) + { + if ($call->variable instanceof yy_Call) + { + $list[] = $call; + $call = $call->variable; + + continue; + } + + if ( ! ($call->variable instanceof yy_Value)) + { + break; + } + + $list[] = $call; + + if ( ! (($call = $call->variable->base) instanceof yy_Call)) + { + break; + } + } + + foreach (array_reverse($list) as $call) + { + if (isset($ifn)) + { + if ($call->variable instanceof yy_Call) + { + $call->variable = $ifn; + } + else + { + $call->variable->base = $ifn; + } + } + + $ifn = unfold_soak($options, $call, 'variable'); + } + + return isset($ifn) ? $ifn : NULL; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/class.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/class.php new file mode 100755 index 0000000000000000000000000000000000000000..a8ce027b6418c349f036e4655378d9ba499b937c --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/class.php @@ -0,0 +1,236 @@ +<?php + +namespace CoffeeScript; + +class yy_Class extends yy_Base +{ + public $children = array('variable', 'parent', 'body'); + + function constructor($variable = NULL, $parent = NULL, $body = NULL) + { + $this->variable = $variable; + $this->parent = $parent; + + $this->body = $body === NULL ? yy('Block') : $body; + $this->body->class_body = TRUE; + + $this->bound_funcs = array(); + + return $this; + } + + function add_bound_functions($options) + { + if (count($this->bound_funcs)) + { + foreach ($this->bound_funcs as $bvar) + { + $bname = $bvar->compile($options); + $body = is_array($this->ctor->body) ? $this->ctor->body : array($this->ctor->body); + array_unshift($body, yy('Literal', "this.{$bname} = ".utility('bind')."(this.{$bname}, this)")); + } + } + } + + function add_properties($node, $name, $options) + { + $props = array_slice($node->base->properties, 0); + $exprs = array(); + + while ($assign = array_shift($props)) + { + if ($assign instanceof yy_Assign) + { + $base = $assign->variable->base; + $func = $assign->value; + + $assign->context = NULL; + + if ($base->value === 'constructor') + { + if ($this->ctor) + { + throw new Error('cannot define more than one constructor in a class'); + } + + if (isset($func->bound) && $func->bound) + { + throw new Error('cannot define a constructor as a bound functions'); + } + + if ($func instanceof yy_Code) + { + $assign = $this->ctor = $func; + } + else + { + $this->external_ctor = $options['scope']->free_variable('class'); + $assign = yy('Assign', yy('Literal', $this->external_ctor), $func); + } + } + else + { + if ( ! (isset($assign->variable->this) && $assign->variable->this)) + { + $assign->variable = yy('Value', yy('Literal', $name), array(yy('Access', $base, 'proto'))); + } + + if ($func instanceof yy_Code && isset($func->bound) && $func->bound) + { + $this->bound_funcs[] = $base; + $func->bound = FALSE; + } + } + } + + $exprs[] = $assign; + } + + return compact($exprs); + } + + function compile_node($options) + { + $decl = $this->determine_name(); + + if ($decl) + { + $name = $decl; + } + else if (isset($this->name) && $this->name) + { + $name = $this->name; + } + else + { + $name = '_Class'; + } + + $lname = yy('Literal', $name); + + $this->set_context($name); + $this->walk_body($name, $options); + $this->ensure_constructor($name); + + if ($this->parent) + { + array_unshift($this->body->expressions, yy('Extends', $lname, $this->parent)); + } + + if ( ! ($this->ctor instanceof yy_Code)) + { + array_unshift($this->body->expressions, $this->ctor); + } + + $this->body->expressions[] = $lname; + + $this->add_bound_functions($options); + + $klass = yy('Parens', yy_Closure::wrap($this->body), TRUE); + + if ($this->variable) + { + $klass = yy('Assign', $this->variable, $klass); + } + + return $klass->compile($options); + } + + function determine_name() + { + if ( ! (isset($this->variable) && $this->variable)) + { + return NULL; + } + + if (($tail = last($this->variable->properties))) + { + $decl = $tail instanceof yy_Access ? $tail->name->value : FALSE; + } + else + { + $decl = $this->variable->base->value; + } + + $decl = $decl ? (preg_match(IDENTIFIER, $decl) ? $decl : FALSE) : FALSE; + + return $decl; + } + + function ensure_constructor($name) + { + if ( ! (isset($this->ctor) && $this->ctor)) + { + $this->ctor = yy('Code'); + + if ($this->parent) + { + $this->ctor->body->push(yy('Literal', "{$name}.__super__.constructor.apply(this, arguments)")); + } + + if (isset($this->external_ctor) && $this->external_ctor) + { + $this->ctor->body->push(yy('Literal', "{$this->external_ctor}.apply(this, arguments)")); + } + + array_unshift($this->body->expressions, $this->ctor); + } + + $this->ctor->ctor = $this->ctor->name = $name; + $this->ctor->klass = NULL; + $this->ctor->no_return = TRUE; + } + + function set_context($name) + { + $this->body->traverse_children(FALSE, function($node) use ($name) + { + if (isset($node->class_body) && $node->class_body) + { + return FALSE; + } + + if ($node instanceof yy_Literal && ''.$node->value === 'this') + { + $node->value = $name; + } + else if ($node instanceof yy_Code) + { + $node->klass = $name; + + if ($node->bound) + { + $node->context = $name; + } + } + }); + } + + function walk_body($name, $options) + { + $self = $this; + + $this->traverse_children(FALSE, function($child) use ($name, $options, & $self) + { + if ($child instanceof yy_Class) + { + return FALSE; + } + + if ($child instanceof yy_Block) + { + foreach (($exps = $child->expressions) as $i => $node) + { + if ($node instanceof yy_Value && $node->is_object(TRUE)) + { + $exps[$i] = $self->add_properties($node, $name, $options); + } + } + + $child->expressions = $exps = flatten($exps); + } + }); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/closure.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/closure.php new file mode 100755 index 0000000000000000000000000000000000000000..5751ab0b5a1019a3844760a9c8d41f999347bcc0 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/closure.php @@ -0,0 +1,49 @@ +<?php + +namespace CoffeeScript; + +class yy_Closure +{ + static function wrap($expressions, $statement = NULL, $no_return = FALSE) + { + if ($expressions->jumps()) + { + return $expressions; + } + + $func = yy('Code', array(), yy_Block::wrap(array($expressions))); + $args = array(); + + if (($mentions_args = $expressions->contains('yy_Closure::literal_args')) || + $expressions->contains('yy_Closure::literal_this')) + { + $meth = yy('Literal', $mentions_args ? 'apply' : 'call'); + $args = array(yy('Literal', 'this')); + + if ($mentions_args) + { + $args[] = yy('Literal', 'arguments'); + } + + $func = yy('Value', $func, array(yy('Access', $meth))); + } + + $func->no_return = $no_return; + $call = yy('Call', $func, $args); + + return $statement ? yy_Block::wrap(array($call)) : $call; + } + + static function literal_args($node) + { + return ($node instanceof yy_Literal) && (''.$node->value === 'arguments') && ! $node->as_key; + } + + static function literal_this($node) + { + return (($node instanceof yy_Literal) && (''.$node->value === 'this') && ! $node->as_key) || + ($node instanceof yy_Code && $node->bound); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/code.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/code.php new file mode 100755 index 0000000000000000000000000000000000000000..33f5db2d42fadda0e4d39bce67988c52814f57e6 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/code.php @@ -0,0 +1,160 @@ +<?php + +namespace CoffeeScript; + +class yy_Code extends yy_Base +{ + public $children = array('params', 'body'); + + function constructor($params = NULL, $body = NULL, $tag = NULL) + { + $this->params = $params ? $params : array(); + $this->body = $body ? $body : yy('Block'); + $this->bound = $tag === 'boundfunc'; + $this->context = $this->bound ? 'this' : NULL; + + return $this; + } + + function compile_node($options) + { + $options['scope'] = new Scope($options['scope'], $this->body, $this); + $options['scope']->shared = del($options, 'sharedScope'); + $options['indent'] .= TAB; + + unset($options['bare']); + + $vars = array(); + $exprs = array(); + + foreach ($this->params as $param) + { + if ($param->splat) + { + if (isset($param->name->value) && $param->name->value) + { + $options['scope']->add($param->name->value, 'var'); + } + + $params = array(); + + foreach ($this->params as $p) + { + $params[] = $p->as_reference($options); + } + + $splats = yy('Assign', yy('Value', yy('Arr', $params)), yy('Value', yy('Literal', 'arguments'))); + + break; + } + } + + foreach ($this->params as $param) + { + if ($param->is_complex()) + { + $val = $ref = $param->as_reference($options); + + if ($param->value) + { + $val = yy('Op', '?', $ref, $param->value); + } + + $exprs[] = yy('Assign', yy('Value', $param->name), $val, '=', array('param' => TRUE)); + } + else + { + $ref = $param; + + if ($param->value) + { + $lit = yy('Literal', $ref->name->value.' == null'); + $val = yy('Assign', yy('Value', $param->name), $param->value, '='); + + $exprs[] = yy('If', $lit, $val); + } + } + + if ( ! (isset($splats) && $splats)) + { + $vars[] = $ref; + } + } + + $was_empty = $this->body->is_empty(); + + if (isset($splats) && $splats) + { + array_unshift($exprs, $splats); + } + + if (count($exprs)) + { + $this->body->expressions = array_merge($this->body->expressions, $exprs); + } + + if ( ! (isset($splats) && $splats)) + { + foreach ($vars as $i => $v) + { + $options['scope']->parameter(($vars[$i] = $v->compile($options))); + } + } + + if ( ! ($was_empty || $this->no_return)) + { + $this->body->make_return(); + } + + $idt = $options['indent']; + $code = 'function'; + + if ($this->ctor) + { + $code .= ' '.$this->name; + } + + $code .= '('.implode(', ', $vars).') {'; + + if ( ! $this->body->is_empty()) + { + $code .= "\n".$this->body->compile_with_declarations($options)."\n{$this->tab}"; + } + + $code .= '}'; + + if ($this->ctor) + { + return $this->tab.$code; + } + + if ($this->bound) + { + return utility('bind')."({$code}, {$this->context})"; + } + + return ($this->front || $options['level'] >= LEVEL_ACCESS) ? "({$code})" : $code; + } + + function is_statement() + { + return !! $this->ctor; + } + + function jumps() + { + return FALSE; + } + + function traverse_children($cross_scope, $func) + { + if ($cross_scope) + { + return parent::traverse_children($cross_scope, $func); + } + + return NULL; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/comment.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/comment.php new file mode 100755 index 0000000000000000000000000000000000000000..12555dd3bc1f64cf945a30195154bfc04f42daad --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/comment.php @@ -0,0 +1,37 @@ +<?php + +namespace CoffeeScript; + +class yy_Comment extends yy_Base +{ + function constructor($comment) + { + $this->comment = $comment; + + return $this; + } + + function compile_node($options, $level = NULL) + { + $code = '/*'.multident($this->comment, $this->tab).'*/'; + + if ($level === LEVEL_TOP || $options['level'] === LEVEL_TOP) + { + $code = $options['indent'].$code; + } + + return $code; + } + + function is_statement() + { + return TRUE; + } + + function make_return() + { + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/existence.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/existence.php new file mode 100755 index 0000000000000000000000000000000000000000..fd338739f484f7b550c8d93252e6f40227eaf6ae --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/existence.php @@ -0,0 +1,47 @@ +<?php + +namespace CoffeeScript; + +class yy_Existence extends yy_Base +{ + public $children = array('expression'); + + function constructor($expression) + { + $this->expression = $expression; + + return $this; + } + + function compile_node($options = array()) + { + $code = $this->expression->compile($options, LEVEL_OP); + + if (preg_match(IDENTIFIER, $code) && ! $options['scope']->check($code)) + { + if ($this->negated) + { + $code = "typeof {$code} === \"undefined\" || {$code} === null"; + } + else + { + $code = "typeof {$code} !== \"undefined\" && {$code} !== null"; + } + } + else + { + $sym = $this->negated ? '==' : '!='; + $code = "{$code} {$sym} null"; + } + + return (isset($options['level']) && $options['level'] <= LEVEL_COND) ? $code : "({$code})"; + } + + function invert() + { + $this->negated = ! $this->negated; + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/extends.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/extends.php new file mode 100755 index 0000000000000000000000000000000000000000..a547e49ea347b11f014a26299659f18a21293e0f --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/extends.php @@ -0,0 +1,28 @@ +<?php + +namespace CoffeeScript; + +class yy_Extends extends yy_Base +{ + public $children = array('child', 'parent'); + + function constructor($child, $parent) + { + $this->child = $child; + $this->parent = $parent; + + return $this; + } + + function compile($options) + { + utility('hasProp'); + + $tmp = yy('Call', yy('Value', yy('Literal', utility('extends'))), + array($this->child, $this->parent)); + + return $tmp->compile($options); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/for.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/for.php new file mode 100755 index 0000000000000000000000000000000000000000..05c1119017c44186bd7cfef5787f22ac07bfd344 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/for.php @@ -0,0 +1,258 @@ +<?php + +namespace CoffeeScript; + +class yy_For extends yy_Base +{ + public $children = array('body', 'source', 'guard', 'step'); + + function constructor($body, $source) + { + $this->source = $source['source']; + $this->guard = isset($source['guard']) ? $source['guard'] : NULL; + $this->step = isset($source['step']) ? $source['step'] : NULL; + $this->name = isset($source['name']) ? $source['name'] : NULL; + $this->index = isset($source['index']) ? $source['index'] : NULL; + + $this->body = yy_Block::wrap(array($body)); + + $this->own = (isset($source['own']) && $source['own']); + $this->object = (isset($source['object']) && $source['object']); + + if ($this->object) + { + $tmp = $this->name; + $this->name = $this->index; + $this->index = $tmp; + } + + if ($this->index instanceof yy_Value) + { + throw SyntaxError('index cannot be a pattern matching expression'); + } + + $this->range = $this->source instanceof yy_Value && $this->source->base instanceof yy_Range && + ! count($this->source->properties); + + $this->pattern = $this->name instanceof yy_Value; + + if ($this->range && $this->index) + { + throw SyntaxError('indexes do not apply to range loops'); + } + + if ($this->range && $this->pattern) + { + throw SyntaxError('cannot pattern match over range loops'); + } + + $this->returns = FALSE; + + return $this; + } + + function compile_node($options) + { + $body = yy_Block::wrap(array($this->body)); + + $last_jumps = last($body->expressions); + $last_jumps = $last_jumps ? $last_jumps->jumps() : FALSE; + + if ($last_jumps && $last_jumps instanceof yy_Return) + { + $this->returns = FALSE; + } + + if ($this->range) + { + $source = $this->source->base; + } + else + { + $source = $this->source; + } + + $scope = $options['scope']; + + $name = $this->name ? $this->name->compile($options, LEVEL_LIST) : FALSE; + $index = $this->index ? $this->index->compile($options, LEVEL_LIST) : FALSE; + + if ($name && ! $this->pattern) + { + $scope->find($name, array('immediate' => TRUE)); + } + + if ($index) + { + $scope->find($index, array('immediate' => TRUE)); + } + + if ($this->returns) + { + $rvar = $scope->free_variable('results'); + } + + $ivar = $this->range ? $name : $index; + $ivar = $ivar ? $ivar : $scope->free_variable('i'); + + if ($this->step && ! $this->range) + { + $stepvar = $scope->free_variable('step'); + } + + if ($this->pattern) + { + $name = $ivar; + } + + $var_part = ''; + $guard_part = ''; + $def_part = ''; + + $idt1 = $this->tab.TAB; + + if ($this->range) + { + $for_part = $source->compile(array_merge($options, array('index' => $ivar, 'step' => $this->step))); + } + else + { + $svar = $this->source->compile($options, LEVEL_LIST); + + if (($name || $this->own) && ! preg_match(IDENTIFIER, $svar)) + { + $ref = $scope->free_variable('ref'); + $def_part = "{$this->tab}{$ref} = {$svar};\n"; + $svar = $ref; + } + + if ($name && ! $this->pattern) + { + $name_part = "{$name} = {$svar}[{$ivar}]"; + } + + if ( ! $this->object) + { + $lvar = $scope->free_variable('len'); + $for_var_part = "{$ivar} = 0, {$lvar} = {$svar}.length"; + + if ($this->step) + { + $for_var_part .= ", {$stepvar} = ".$this->step->compile($options, LEVEL_OP); + } + + $step_part = $this->step ? "{$ivar} += {$stepvar}" : "{$ivar}++"; + $for_part = "{$for_var_part}; {$ivar} < {$lvar}; {$step_part}"; + } + } + + if ($this->returns) + { + $result_part = "{$this->tab}{$rvar} = [];\n"; + $return_result = "\n{$this->tab}return {$rvar};"; + $body = yy_Push::wrap($rvar, $body); + } + + if ($this->guard) + { + $body = yy_Block::wrap(array(yy('If', $this->guard, $body))); + } + + if ($this->pattern) + { + array_unshift($body->expressions, yy('Assign', $this->name, yy('Literal', "{$svar}[{$ivar}]"))); + } + + $def_part .= $this->pluck_direct_call($options, $body); + + if (isset($name_part) && $name_part) + { + $var_part = "\n{$idt1}{$name_part};"; + } + + if ($this->object) + { + $for_part = "{$ivar} in {$svar}"; + + if ($this->own) + { + $guard_part = "\n{$idt1}if (!".utility('hasProp').".call({$svar}, {$ivar})) continue;"; + } + } + + $body = $body->compile(array_merge($options, array('indent' => $idt1)), LEVEL_TOP); + + if ($body) + { + $body = "\n{$body}\n"; + } + + return + "{$def_part}" + . (isset($result_part) ? $result_part : '') + . "{$this->tab}for ({$for_part}) {{$guard_part}{$var_part}{$body}{$this->tab}}" + . (isset($return_result) ? $return_result : ''); + } + + function is_statement() + { + return TRUE; + } + + function jumps() + { + return call_user_func_array(array(yy('While'), __FUNCTION__), func_get_args()); + } + + function make_return() + { + $this->returns = TRUE; + return $this; + } + + function pluck_direct_call($options, $body) + { + $defs = ''; + + foreach ($body->expressions as $idx => $expr) + { + $expr = $expr->unwrap_all(); + + if ( ! ($expr instanceof yy_Call)) + { + continue; + } + + $val = $expr->variable->unwrap_all(); + + if ( ! ( ($val instanceof yy_Code) || + ($val instanceof yy_Value) && + (isset($val->base) && $val->base && ($val->base->unwrap_all() instanceof yy_Code) && + count($val->properties) === 1 && + isset($val->properties[0]->name) && + in_array($val->properties[0]->name['value'], array('call', 'apply'), TRUE)))) + { + continue; + } + + $fn = (isset($val->base) && $val->base) ? $val->base->unwrap_all() : $val; + $ref = yy('Literal', $options['scope']->free_variable('fn')); + $base = yy('Value', $ref); + + if (isset($val->base) && $val->base) + { + $val->base = $base; + $base = $val; + array_unshift($args, yy('Literal', 'this')); + } + + $body->expressions[$idx] = yy('Call', $base, $expr->args); + $tmp = yy('Assign', $ref, $fn); + $defs .= $this->tab.$tmp->compile($options, LEVEL_TOP).";\n"; + } + + return $defs; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/if.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/if.php new file mode 100755 index 0000000000000000000000000000000000000000..b4b0a23c8123d25aaa54001b8b9f544cdfed299c --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/if.php @@ -0,0 +1,146 @@ +<?php + +namespace CoffeeScript; + +class yy_If extends yy_Base +{ + public $children = array('condition', 'body', 'elsebody'); + + function constructor($condition, $body, $options = array()) + { + $this->condition = (isset($options['type']) && $options['type'] === 'unless') ? $condition->invert() : $condition; + $this->body = $body; + $this->else_body = NULL; + $this->is_chain = FALSE; + $this->soak = isset($options['soak']) ? $options['soak'] : NULL; + + return $this; + } + + function add_else($else_body) + { + if ($this->is_chain()) + { + $this->else_body_node()->add_else($else_body); + } + else + { + $this->is_chain = $else_body instanceof yy_If; + $this->else_body = $this->ensure_block($else_body); + } + + return $this; + } + + function body_node() + { + return $this->body ? $this->body->unwrap() : NULL; + } + + function compile_node($options = array()) + { + return $this->is_statement($options) ? $this->compile_statement($options) : $this->compile_expression($options); + } + + function compile_expression($options) + { + $cond = $this->condition->compile($options, LEVEL_COND); + $body = $this->body_node()->compile($options, LEVEL_LIST); + + $alt = ($tmp = $this->else_body_node()) ? $tmp->compile($options, LEVEL_LIST) : 'void 0'; + $code = "{$cond} ? {$body} : {$alt}"; + + return (isset($options['level']) && $options['level'] > LEVEL_COND) ? "({$code})" : $code; + } + + function compile_statement($options) + { + $child = del($options, 'chainChild'); + $cond = $this->condition->compile($options, LEVEL_PAREN); + $options['indent'] .= TAB; + $body = $this->ensure_block($this->body)->compile($options); + + if ($body) + { + $body = "\n{$body}\n{$this->tab}"; + } + + $if_part = "if ({$cond}) {{$body}}"; + + if ( ! $child) + { + $if_part = $this->tab.$if_part; + } + + if ( ! $this->else_body) + { + return $if_part; + } + + $ret = $if_part.' else '; + + if ($this->is_chain()) + { + $options['indent'] = $this->tab; + $options['chainChild'] = TRUE; + + $ret .= $this->else_body->unwrap()->compile($options, LEVEL_TOP); + } + else + { + $ret .= "{\n".$this->else_body->compile($options, LEVEL_TOP)."\n{$this->tab}}"; + } + + return $ret; + } + + function else_body_node() + { + return (isset($this->else_body) && $this->else_body) ? $this->else_body->unwrap() : NULL; + } + + function ensure_block($node) + { + return $node instanceof yy_Block ? $node : yy('Block', array($node)); + } + + function is_chain() + { + return $this->is_chain; + } + + function is_statement($options = array()) + { + return (isset($options['level']) && $options['level'] === LEVEL_TOP) || + $this->body_node()->is_statement($options) || + ( ($tmp = $this->else_body_node()) && $tmp && $tmp->is_statement($options)); + } + + function jumps($options = array()) + { + return $this->body->jumps($options) || + (isset($this->else_body) && $this->else_body && $this->else_body->jumps($options)); + } + + function make_return() + { + if ($this->body) + { + $this->body = yy('Block', array($this->body->make_return())); + } + + if ($this->else_body) + { + $this->else_body = yy('Block', array($this->else_body->make_return())); + } + + return $this; + } + + function unfold_soak() + { + return $this->soak ? $this : FALSE; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/in.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/in.php new file mode 100755 index 0000000000000000000000000000000000000000..ef849f657065e2345bf06c6f929bd759e023472e --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/in.php @@ -0,0 +1,79 @@ +<?php + +namespace CoffeeScript; + +class yy_In extends yy_Base +{ + public $children = array('object', 'array'); + + function constructor($object = NULL, $array = NULL) + { + $this->array = $array; + $this->object = $object; + + return $this; + } + + function compile_node($options = array()) + { + if ($this->array instanceof yy_Value && $this->array->is_array()) + { + return $this->compile_or_test($options); + } + else + { + return $this->compile_loop_test($options); + } + } + + function compile_or_test($options) + { + list($sub, $ref) = $this->object->cache($options, LEVEL_OP); + list($cmp, $cnj) = $this->negated ? array(' !== ', ' && ') : array(' === ', ' || '); + + $tests = array(); + + foreach ($this->array->base->objects as $i => $item) + { + $tests[] = ($i ? $ref : $sub).$cmp.$item->compile($options, LEVEL_OP); + } + + if (count($tests) === 0) + { + return 'false'; + } + + $tests = implode($cnj, $tests); + + return (isset($options['level']) && $options['level'] < LEVEL_OP) ? $tests : "({$tests})"; + } + + function compile_loop_test($options) + { + list($sub, $ref) = $this->object->cache($options, LEVEL_LIST); + + $code = utility('indexOf').".call(".$this->array->compile($options, LEVEL_LIST).", {$ref}) " + .($this->negated ? '< 0' : '>= 0'); + + if ($sub === $ref) + { + return $code; + } + + $code = $sub.', '.$code; + return (isset($options['level']) && $options['level'] < LEVEL_LIST) ? $code : "({$code})"; + } + + function invert() + { + $this->negated = ! $this->negated; + return $this; + } + + function to_string($idt = '', $name = __CLASS__) + { + return parent::to_string($idt, $name.($this->negated ? '!' : '')); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/index.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/index.php new file mode 100755 index 0000000000000000000000000000000000000000..e6463ab74bf39b09996a3b1e5e91e0864def4e9c --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/index.php @@ -0,0 +1,27 @@ +<?php + +namespace CoffeeScript; + +class yy_Index extends yy_Base +{ + public $children = array('index'); + + function constructor($index) + { + $this->index = $index; + + return $this; + } + + function compile($options) + { + return ($this->proto ? '.prototype' : '').'['.$this->index->compile($options, LEVEL_PAREN).']'; + } + + function is_complex() + { + return $this->index->is_complex(); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/literal.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/literal.php new file mode 100755 index 0000000000000000000000000000000000000000..23894d6f620dce51292793319e905096c8026b50 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/literal.php @@ -0,0 +1,93 @@ +<?php + +namespace CoffeeScript; + +class yy_Literal extends yy_Base +{ + private $is_undefined = FALSE; + + function constructor($value) + { + $this->value = $value; + + return $this; + } + + function assigns($name) + { + return $name === $this->value; + } + + function compile_node($options) + { + if ($this->is_undefined()) + { + $code = $options['level'] >= LEVEL_ACCESS ? '(void 0)' : 'void 0'; + } + else if (isset($this->value->reserved) && $this->value->reserved) + { + $code = '"'.$this->value.'"'; + } + else + { + $code = ''.$this->value; + } + + return $this->is_statement() ? "{$this->tab}{$code};" : $code; + } + + function is_assignable() + { + return preg_match(IDENTIFIER, ''.$this->value); + } + + function is_complex() + { + return FALSE; + } + + function is_statement() + { + return in_array(''.$this->value, array('break', 'continue', 'debugger'), TRUE); + } + + function is_undefined($set = NULL) + { + if ($set !== NULL) + { + $this->is_undefined = !! $set; + } + + return $this->is_undefined; + } + + function jumps($options = array()) + { + if ( ! $this->is_statement()) + { + return FALSE; + } + + if ( ! ((isset($options['loop']) && $options['loop']) || + (isset($options['block']) && $options['block']) && (''.$this->value !== 'continue'))) + { + return $this; + } + else + { + return FALSE; + } + } + + function make_return() + { + return $this->is_statement() ? $this : yy('Return', $this); + } + + function to_string($idt = '', $name = __CLASS__) + { + return ' "'.$this->value.'"'; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/obj.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/obj.php new file mode 100755 index 0000000000000000000000000000000000000000..73e09c3365c6c5e27315c9fd54c9a7ddecc52f9a --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/obj.php @@ -0,0 +1,104 @@ +<?php + +namespace CoffeeScript; + +class yy_Obj extends yy_Base +{ + public $children = array('properties'); + + function constructor($props, $generated = FALSE) + { + $this->generated = $generated; + + $this->properties = $props ? $props : array(); + $this->objects = $this->properties; + + return $this; + } + + function assigns($name) + { + foreach ($this->properties as $prop) + { + if ($prop->assigns($name)) + { + return TRUE; + } + } + + return FALSE; + } + + function compile_node($options) + { + $props = $this->properties; + + if ( ! count($props)) + { + return ($this->front ? '({})' : '{}'); + } + + if ($this->generated) + { + foreach ($props as $node) + { + if ($node instanceof yy_Value) + { + throw new Error('cannot have an implicit value in an implicit object'); + } + } + } + + $idt = $options['indent'] .= TAB; + $last_non_com = $this->last_non_comment($this->properties); + + foreach ($props as $i => $prop) + { + if ($i === count($props) - 1) + { + $join = ''; + } + else if ($prop === $last_non_com || $prop instanceof yy_Comment) + { + $join = "\n"; + } + else + { + $join = ",\n"; + } + + $indent = $prop instanceof yy_Comment ? '' : $idt; + + if ($prop instanceof yy_Value && (isset($prop->this) && $prop->this)) + { + $prop = yy('Assign', $prop->properties[0]->name, $prop, 'object'); + } + + if ( ! ($prop instanceof yy_Comment)) + { + if ( ! ($prop instanceof yy_Assign)) + { + $prop = yy('Assign', $prop, $prop, 'object'); + } + + if (isset($prop->variable->base)) + { + $prop->variable->base->as_key = TRUE; + } + else + { + $prop->variable->as_key = TRUE; + } + } + + $props[$i] = $indent.$prop->compile($options, LEVEL_TOP).$join; + } + + $props = implode('', $props); + $obj = '{'.($props ? "\n{$props}\n{$this->tab}" : '').'}'; + + return ($this->front ? "({$obj})" : $obj); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/op.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/op.php new file mode 100755 index 0000000000000000000000000000000000000000..6d84fa2db86dd26da99e4ace33cab721ea54e500 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/op.php @@ -0,0 +1,230 @@ +<?php + +namespace CoffeeScript; + +class yy_Op extends yy_Base +{ + static $CONVERSIONS = array( + '==' => '===', + '!=' => '!==', + 'of' => 'in' + ); + + static $INVERSIONS = array( + '!==' => '===', + '===' => '!==' + ); + + public $children = array('first', 'second'); + + public $operator = NULL; + + function constructor($op, $first, $second = NULL, $flip = NULL) + { + if ($op === 'in') + { + return yy('In', $first, $second); + } + + if ($op === 'do') + { + $call = yy('Call', $first, isset($first->params) ? $first->params : array()); + $call->do = TRUE; + + return $call; + } + + if ($op === 'new') + { + if ($first instanceof yy_Call && ! (isset($first->do) && $first->do)) + { + return $first->new_instance(); + } + + if ($first instanceof yy_Code && $first->bound || (isset($first->do) && $first->do)) + { + $first = yy('Parens', $first); + } + } + + $this->operator = isset(self::$CONVERSIONS[$op]) ? self::$CONVERSIONS[$op] : $op; + $this->first = $first; + $this->second = $second; + $this->flip = !! $flip; + + return $this; + } + + function compile_chain($options) + { + $tmp = $this->first->second->cache($options); + + $this->first->second = $tmp[0]; + $shared = $tmp[1]; + + $fst = $this->first->compile($options, LEVEL_OP); + $code = "{$fst} ".($this->invert() ? '&&' : '||').' '.$shared->compile($options).' ' + .$this->operator.' '.$this->second->compile($options, LEVEL_OP); + + return "({$code})"; + } + + function compile_existence($options) + { + if ($this->first->is_complex()) + { + $ref = yy('Literal', $options['scope']->free_variable('ref')); + $fst = yy('Parens', yy('Assign', $ref, $this->first)); + } + else + { + $fst = $this->first; + $ref = $fst; + } + + $tmp = yy('If', yy('Existence', $fst), $ref, array('type' => 'if')); + $tmp->add_else($this->second); + + return $tmp->compile($options); + } + + function compile_node($options, $level = NULL) + { + if ($this->is_unary()) + { + return $this->compile_unary($options); + } + + if ($this->is_chainable() && $this->first->is_chainable()) + { + return $this->compile_chain($options); + } + + if ($this->operator === '?') + { + return $this->compile_existence($options); + } + + $this->first->front = $this->front; + + $code = $this->first->compile($options, LEVEL_OP).' '.$this->operator.' ' + .$this->second->compile($options, LEVEL_OP); + + return $options['level'] <= LEVEL_OP ? $code : "({$code})"; + } + + function compile_unary($options) + { + $parts = array($op = $this->operator); + + if (in_array($op, array('new', 'typeof', 'delete'), TRUE) || + in_array($op, array('+', '-'), TRUE) && + $this->first instanceof yy_Op && $this->first->operator === $op) + { + $parts[] = ' '; + } + + if ($op === 'new' && $this->first->is_statement($options)) + { + $this->first = yy('Parens', $this->first); + } + + $parts[] = $this->first->compile($options, LEVEL_OP); + + if ($this->flip) + { + $parts = array_reverse($parts); + } + + return implode('', $parts); + } + + function is_chainable() + { + return in_array($this->operator, array('<', '>', '>=', '<=', '===', '!=='), TRUE); + } + + function invert() + { + if ($this->is_chainable() && $this->first->is_chainable()) + { + $all_invertable = TRUE; + $curr = $this; + + while ($curr && (isset($curr->operator) && $curr->operator)) + { + $all_invertable = $all_invertable && isset(self::$INVERSIONS[$curr->operator]); + $curr = $curr->first; + } + + if ( ! $all_invertable) + { + $tmp = yy('Parens', $this); + return $tmp->invert(); + } + + $curr = $this; + + while ($curr && (isset($curr->operator) && $curr->operator)) + { + $curr->invert = ! (isset($curr->invert) && $curr->invert); + $curr->operator = self::$INVERSIONS[$curr->operator]; + $curr = $curr->first; + } + + return $this; + } + else if (isset(self::$INVERSIONS[$this->operator]) && ($op = self::$INVERSIONS[$this->operator])) + { + $this->operator = $op; + + if ($this->first->unwrap() instanceof yy_Op) + { + $this->first->invert(); + } + + return $this; + } + else if ($this->second) + { + $tmp = yy('Parens', $this); + return $tmp->invert(); + } + else if ($this->operator === '!' && (($fst = $this->first->unwrap()) instanceof yy_Op) && + in_array($fst->operator, array('!', 'in', 'instanceof'), TRUE)) + { + return $fst; + } + else + { + return yy('Op', '!', $this); + } + } + + function is_simple_number() + { + return FALSE; + } + + function is_unary() + { + return ! (isset($this->second) && $this->second); + } + + function unfold_soak($options) + { + if (in_array($this->operator, array('++', '--', 'delete'), TRUE)) + { + return unfold_soak($options, $this, 'first'); + } + + return NULL; + } + + function to_string($idt = '', $name = __CLASS__) + { + return parent::to_string($idt, $name.' '.$this->operator); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/param.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/param.php new file mode 100755 index 0000000000000000000000000000000000000000..ed25f84575fb6b21d8ec754d28116e49496f7e6f --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/param.php @@ -0,0 +1,62 @@ +<?php + +namespace CoffeeScript; + +class yy_Param extends yy_Base +{ + public $children = array('name', 'value'); + + function constructor($name, $value = NULL, $splat = NULL) + { + $this->name = $name; + $this->value = $value; + $this->splat = $splat; + + return $this; + } + + function as_reference($options) + { + if (isset($this->reference) && $this->reference) + { + return $this->reference; + } + + $node = $this->name; + + if (isset($node->this) && $node->this) + { + $node = $node->properties[0]->name; + + if (isset($this->value->reserved) && $this->value->reserved) + { + $node = yy('Literal', '_'.$node->value); + } + } + else if ($node->is_complex()) + { + $node = yy('Literal', $options['scope']->free_variable('arg')); + } + + $node = yy('Value', $node); + + if ($this->splat) + { + $node = yy('Splat', $node); + } + + return ($this->reference = $node); + } + + function compile($options, $level = NULL) + { + return $this->name->compile($options, LEVEL_LIST); + } + + function is_complex() + { + return $this->name->is_complex(); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/parens.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/parens.php new file mode 100755 index 0000000000000000000000000000000000000000..47e508d5e7777e77e9cb213a815e5a77710cb8bc --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/parens.php @@ -0,0 +1,50 @@ +<?php + +namespace CoffeeScript; + +class yy_Parens extends yy_Base +{ + public $children = array('body'); + + public function constructor($body) + { + $this->body = $body; + + return $this; + } + + public function compile_node($options = array()) + { + $expr = $this->body->unwrap(); + + if ($expr instanceof yy_Value && $expr->is_atomic()) + { + $expr->front = $this->front; + return $expr->compile($options); + } + + $code = $expr->compile($options, LEVEL_PAREN); + + $bare = $options['level'] < LEVEL_OP && ($expr instanceof yy_Op || $expr instanceof yy_Call || + ($expr instanceof yy_For && $expr->returns)); + + return $bare ? $code : "({$code})"; + } + + public function is_complex() + { + return $this->body->is_complex(); + } + + public function make_return() + { + return $this->body->make_return(); + } + + public function unwrap() + { + return $this->body; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/push.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/push.php new file mode 100755 index 0000000000000000000000000000000000000000..d90ec8bc8a100a899c8352bdb3fa05ab18675d6a --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/push.php @@ -0,0 +1,19 @@ +<?php + +namespace CoffeeScript; + +class yy_Push +{ + static function wrap($name, $exps) + { + if ($exps->is_empty() || last($exps->expressions)->jumps()) + { + return $exps; + } + + return $exps->push(yy('Call', yy('Value', yy('Literal', $name), + array(yy('Access', yy('Literal', 'push')))), array($exps->pop()))); + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/range.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/range.php new file mode 100755 index 0000000000000000000000000000000000000000..2c201b7b6e24f37d48d66da3871e245abd93246f --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/range.php @@ -0,0 +1,152 @@ +<?php + +namespace CoffeeScript; + +class yy_Range extends yy_Base +{ + public $children = array('from', 'to'); + + public $from_num = 0; + public $to_num = 0; + + function constructor($from, $to, $tag) + { + $this->from = $from; + $this->to = $to; + $this->exclusive = $tag === 'exclusive'; + $this->equals = $this->exclusive ? '' : '='; + + return $this; + } + + function compile_array($options) + { + if ( (isset($this->from_num) && $this->from_num) && + (isset($this->to_num) && $this->to_num) && abs($this->from_num - $this->to_num) <= 20) + { + $range = range($this->from_num, $this->to_num); + + if ($this->exclusive) + { + array_pop($range); + } + + return '['.implode(', ', $range).']'; + } + + $idt = $this->tab.TAB; + $i = $options['scope']->free_variable('i'); + $result = $options['scope']->free_variable('result'); + $pre = "\n{$idt}{$result} = [];"; + + if ( (isset($this->from_num) && $this->from_num) && + (isset($this->to_num) && $this->to_num)) + { + $options['index'] = $i; + $body = $this->compile_simple($options); + } + else + { + $vars = "{$i} = {$this->from}".($this->to !== $this->to_var ? ", {$this->to}" : ''); + $cond = "{$this->from_var} <= {$this->to_var}"; + $body = "var {$vars}; {$cond} ? {$i} <{$this->equals} {$this->to_var} : {$i} >{$this->equals} {$this->to_var}; {$cond} ? {$i}++ : {$i}--"; + } + + $post = "{ {$result}.push({$i}); }\n{$idt}return {$result};\n{$options['indent']}"; + + return "(function() {{$pre}\n{$idt}for ({$body}){$post}}).apply(this, arguments)"; + } + + function compile_node($options) + { + $this->compile_variables($options); + + if ( ! (isset($options['index']) && $options['index'])) + { + return $this->compile_array($options); + } + + if ($this->from_num && $this->to_num) + { + return $this->compile_simple($options); + } + + $idx = del($options, 'index'); + $step = del($options, 'step'); + + if ($step) + { + $stepvar = $options['scope']->free_variable('step'); + } + + $var_part = "{$idx} = {$this->from}".($this->to !== $this->to_var ? ", {$this->to}" : '') + .($step ? ", {$stepvar} = ".$step->compile($options) : ''); + + $cond = "{$this->from_var} <= {$this->to_var}"; + $cond_part = "{$cond} ? {$idx} <{$this->equals} {$this->to_var} : {$idx} >{$this->equals} {$this->to_var}"; + $step_part = $step ? "{$idx} += {$stepvar}" : "{$cond} ? {$idx}++ : {$idx}--"; + + return "{$var_part}; {$cond_part}; {$step_part}"; + } + + function compile_simple($options) + { + list($from, $to) = array($this->from_num, $this->to_num); + + $idx = del($options, 'index'); + $step = del($options, 'step'); + + if ($step) + { + $stepvar = $options['scope']->free_variable('step'); + } + + $var_part = "{$idx} = {$from}"; + + if ($step) + { + $var_part .= ", {$stepvar} = ".$step->compile($options); + } + + $cond_part = $from <= $to ? "{$idx} <{$this->equals} {$to}" : "{$idx} >{$this->equals} {$to}"; + + if ($step) + { + $step_part = "{$idx} += {$stepvar}"; + } + else + { + $step_part = $from <= $to ? "{$idx}++" : "{$idx}--"; + } + + return "{$var_part}; {$cond_part}; {$step_part}"; + } + + function compile_variables($options) + { + $options = array_merge($options, array('top' => TRUE)); + + list($this->from, $this->from_var) = $this->from->cache($options, LEVEL_LIST); + list($this->to, $this->to_var) = $this->to->cache($options, LEVEL_LIST); + + preg_match(SIMPLENUM, $this->from_var, $from_num); + preg_match(SIMPLENUM, $this->to_var, $to_num); + + $this->from_num = isset($from_num[0]) ? $from_num[0] : NULL; + $this->to_num = isset($to_num[0]) ? $to_num[0] : NULL; + + $parts = array(); + + if ($this->from !== $this->from_var) + { + $parts[] = $this->from; + } + + if ($this->to !== $this->to_var) + { + $parts[] = $this->to; + } + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/return.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/return.php new file mode 100755 index 0000000000000000000000000000000000000000..8cb8054964ac8935f0699f47aac859212d21bea6 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/return.php @@ -0,0 +1,56 @@ +<?php + +namespace CoffeeScript; + +class yy_Return extends yy_Base +{ + public $children = array('expression'); + + function constructor($expr = NULL) + { + if ($expr && ! ($expr->unwrap()->is_undefined())) + { + $this->expression = $expr; + } + + return $this; + } + + function compile($options, $level = NULL) + { + $expr = (isset($this->expression) && $this->expression) ? + $this->expression->make_return() : NULL; + + if ($expr && ! ($expr instanceof yy_Return)) + { + return $expr->compile($options, $level); + } + else + { + return parent::compile($options, $level); + } + } + + function compile_node($options) + { + return $this->tab.'return'.(isset($this->expression) && $this->expression ? + ' '.$this->expression->compile($options, LEVEL_PAREN) : '').';'; + } + + function is_statement() + { + return TRUE; + } + + function jumps() + { + return $this; + } + + function make_return() + { + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/slice.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/slice.php new file mode 100755 index 0000000000000000000000000000000000000000..bae5a9773446b9f8ced71e6678e8c56d8bb82eed --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/slice.php @@ -0,0 +1,48 @@ +<?php + +namespace CoffeeScript; + +class yy_Slice extends yy_Base +{ + public $children = array('range'); + + function constructor($range) + { + parent::constructor(); + + $this->range = $range; + + return $this; + } + + function compile_node($options) + { + $to = $this->range->to; + $from = $this->range->from; + + $from_str = $from ? $from->compile($options, LEVEL_PAREN) : '0'; + $compiled = $to ? $to->compile($options, LEVEL_PAREN) : ''; + + if ($to && ! ( ! $this->range->exclusive && intval($compiled) === -1)) + { + $to_str = ', '; + + if ($this->range->exclusive) + { + $to_str .= $compiled; + } + else if (preg_match(SIMPLENUM, $compiled)) + { + $to_str .= (intval($compiled) + 1); + } + else + { + $to_str .= "({$compiled} + 1) || 9e9"; + } + } + + return ".slice({$from_str}".(isset($to_str) ? $to_str : '').')'; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/splat.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/splat.php new file mode 100755 index 0000000000000000000000000000000000000000..0490358f5a182a7e071be438721c9230813cf815 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/splat.php @@ -0,0 +1,95 @@ +<?php + +namespace CoffeeScript; + +class yy_Splat extends yy_Base +{ + public $children = array('name'); + + function constructor($name) + { + if (is_object($name)) + { + $this->name = $name; + } + else + { + $this->name = yy('Literal', $name); + } + + return $this; + } + + function assigns($name) + { + return $this->name->assigns($name); + } + + function compile($options) + { + if (isset($this->index) && $this->index) + { + return $this->compile_param($options); + } + else + { + return $this->name->compile($options); + } + } + + static function compile_splatted_array($options, $list, $apply = FALSE) + { + $index = -1; + + while (isset($list[++$index]) && ($node = $list[$index]) && ! ($node instanceof yy_Splat)) + { + continue; + } + + if ($index >= count($list)) + { + return ''; + } + + if (count($list) === 1) + { + $code = $list[0]->compile($options, LEVEL_LIST); + + if ($apply) + { + return $code; + } + + return utility('slice').".call({$code})"; + } + + $args = array_slice($list, $index); + + foreach ($args as $i => $node) + { + $code = $node->compile($options, LEVEL_LIST); + $args[$i] = ($node instanceof yy_Splat) ? utility('slice').".call({$code})" : "[{$code}]"; + } + + if ($index === 0) + { + return $args[0].'.concat('.implode(', ', array_slice($args, 1)).')'; + } + + $base = array(); + + foreach (array_slice($list, 0, $index) as $node) + { + $base[] = $node->compile($options, LEVEL_LIST); + } + + return '['.implode(', ', $base).'].concat('.implode(', ', $args).')'; + } + + function is_assignable() + { + return TRUE; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/switch.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/switch.php new file mode 100755 index 0000000000000000000000000000000000000000..e867768876791353bc8215216e3c1f0352bf7a7c --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/switch.php @@ -0,0 +1,116 @@ +<?php + +namespace CoffeeScript; + +class yy_Switch extends yy_Base +{ + public $children = array('subject', 'cases', 'otherwise'); + + function constructor($subject = NULL, $cases = array(), $otherwise = NULL) + { + $this->subject = $subject; + $this->cases = $cases; + $this->otherwise = $otherwise; + + return $this; + } + + function compile_node($options) + { + $idt1 = $options['indent'].TAB; + $idt2 = $options['indent'] = $idt1.TAB; + + $code = $this->tab.'switch (' + .($this->subject ? $this->subject->compile($options, LEVEL_PAREN) : 'false') + .") {\n"; + + foreach ($this->cases as $i => $case) + { + list($conditions, $block) = $case; + + foreach (flatten(array($conditions)) as $cond) + { + if ( ! $this->subject) + { + $cond = $cond->invert(); + } + + $code .= $idt1.'case '.$cond->compile($options, LEVEL_PAREN).":\n"; + } + + if ($body = $block->compile($options, LEVEL_TOP)) + { + $code .= $body."\n"; + } + + if ($i === (count($this->cases) - 1) && ! $this->otherwise) + { + break; + } + + $expr = $this->last_non_comment($block->expressions); + + if ($expr instanceof yy_Return || + ($expr instanceof yy_Literal && $expr->jumps() && ''.$expr->value !== 'debugger')) + { + continue; + } + + $code .= $idt2."break;\n"; + } + + if ($this->otherwise && count($this->otherwise->expressions)) + { + $code .= $idt1."default:\n".$this->otherwise->compile($options, LEVEL_TOP)."\n"; + } + + return $code.$this->tab.'}'; + } + + function is_statement() + { + return TRUE; + } + + function jumps($options = array()) + { + if ( ! isset($options['block'])) + { + $options['block'] = TRUE; + } + + foreach ($this->cases as $case) + { + list($conds, $block) = $case; + + if ($block->jumps($options)) + { + return $block; + } + } + + if (isset($this->otherwise) && $this->otherwise) + { + return $this->otherwise->jumps($options); + } + + return FALSE; + } + + function make_return() + { + foreach ($this->cases as $pair) + { + $pair[1]->make_return(); + } + + if (isset($this->otherwise) && $this->otherwise) + { + $this->otherwise->make_return(); + } + + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/throw.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/throw.php new file mode 100755 index 0000000000000000000000000000000000000000..3a2cf39a2509d7feb7dc61b46a3293df54c884af --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/throw.php @@ -0,0 +1,37 @@ +<?php + +namespace CoffeeScript; + +class yy_Throw extends yy_Base +{ + public $children = array('expression'); + + function constructor($expression) + { + $this->expression = $expression; + + return $this; + } + + function compile_node($options = array()) + { + return $this->tab.'throw '.$this->expression->compile($options).';'; + } + + function is_statement() + { + return TRUE; + } + + function jumps() + { + return FALSE; + } + + function make_return() + { + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/try.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/try.php new file mode 100755 index 0000000000000000000000000000000000000000..0334a685cafdd4ed2968d08bc6fd2bace6fe66f7 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/try.php @@ -0,0 +1,67 @@ +<?php + +namespace CoffeeScript; + +class yy_Try extends yy_Base +{ + public $children = array('attempt', 'recovery', 'ensure'); + + function constructor($attempt = NULL, $error = NULL, $recovery = NULL, $ensure = NULL) + { + $this->attempt = $attempt; + $this->error = $error; + $this->recovery = $recovery; + $this->ensure = $ensure; + + return $this; + } + + function compile_node($options = array()) + { + $options['indent'] .= TAB; + $error_part = $this->error ? ' ('.$this->error->compile($options).') ' : ' '; + $catch_part = ''; + + if ($this->recovery) + { + $catch_part = " catch{$error_part}{\n".$this->recovery->compile($options, LEVEL_TOP)."\n{$this->tab}}"; + } + else if ( ! ($this->ensure || $this->recovery)) + { + $catch_part = ' catch (_e) {}'; + } + + return + "{$this->tab}try {\n" + . $this->attempt->compile($options, LEVEL_TOP)."\n" + . "{$this->tab}}{$catch_part}" + . ($this->ensure ? " finally {\n".$this->ensure->compile($options, LEVEL_TOP)."\n{$this->tab}}" : ''); + } + + function is_statement() + { + return TRUE; + } + + function jumps($options = array()) + { + return $this->attempt->jumps($options) || (isset($this->recovery) && $this->recovery->jumps($options)); + } + + function make_return() + { + if ($this->attempt) + { + $this->attempt = $this->attempt->make_return(); + } + + if ($this->recovery) + { + $this->recovery = $this->recovery->make_return(); + } + + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/value.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/value.php new file mode 100755 index 0000000000000000000000000000000000000000..f11e7c5d4f0a01c4109d1288540b1964c0760173 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/value.php @@ -0,0 +1,218 @@ +<?php + +namespace CoffeeScript; + +class yy_Value extends yy_Base +{ + public $children = array('base', 'properties'); + + function constructor($base = NULL, $props = NULL, $tag = NULL) + { + if ( ! $props && $base instanceof yy_Value) + { + return $base; + } + + $this->base = $base; + $this->properties = $props ? $props : array(); + + if ($tag) + { + $this->{$tag} = TRUE; + } + + return $this; + } + + function assigns($name) + { + return ! count($this->properties) && $this->base->assigns($name); + } + + function cache_reference($options) + { + $name = last($this->properties); + + if (count($this->properties) < 2 && ! $this->base->is_complex() && ! ($name && $name->is_complex())) + { + return array($this, $this); + } + + $base = yy('Value', $this->base, array_slice($this->properties, 0, -1)); + $bref = NULL; + + if ($base->is_complex()) + { + $bref = yy('Literal', $options['scope']->free_variable('base')); + $base = yy('Value', yy('Parens', yy('Assign', $bref, $base))); + } + + if ( ! $name) + { + return array($base, $bref); + } + + if ($name->is_complex()) + { + $nref = yy('Literal', $options['scope']->free_variable('name')); + $name = yy('Index', yy('Assign', $nref, $name->index)); + $nref = yy('Index', $nref); + } + + $base->push($name); + + return array($base, yy('Value', isset($bref) ? $bref : $base->base, + array(isset($nref) ? $nref : $name))); + } + + function compile_node($options) + { + $this->base->front = $this->front; + $props = $this->properties; + + $code = $this->base->compile($options, count($props) ? LEVEL_ACCESS : NULL); + + if ($props && $props[0] instanceof yy_Access && $this->is_simple_number()) + { + $code = "($code)"; + } + + foreach ($props as $prop) + { + $code .= $prop->compile($options); + } + + return $code; + } + + function push($prop) + { + $this->properties[] = $prop; + + return $this; + } + + function has_properties() + { + return !! count($this->properties); + } + + function is_array() + { + return ! count($this->properties) && $this->base instanceof yy_Arr; + } + + function is_assignable() + { + return $this->has_properties() || $this->base->is_assignable(); + } + + function is_atomic() + { + foreach (array_merge($this->properties, array($this->base)) as $node) + { + if ((isset($node->soak) && $node->soak) || $node instanceof yy_Call) + { + return FALSE; + } + } + + return TRUE; + } + + function is_complex() + { + return $this->has_properties() || $this->base->is_complex(); + } + + function is_object($only_generated = FALSE) + { + if (count($this->properties)) + { + return FALSE; + } + + return ($this->base instanceof yy_Obj) && ( ! $only_generated || $this->base->generated); + } + + function is_simple_number() + { + return ($this->base instanceof yy_Literal) && preg_match(SIMPLENUM, ''.$this->base->value); + } + + function is_splice() + { + return last($this->properties) instanceof yy_Slice; + } + + function is_statement($options) + { + return ! count($this->properties) && $this->base->is_statement($options); + } + + function jumps($options = array()) + { + return ! count($this->properties) && $this->base->jumps($options); + } + + function make_return() + { + if (count($this->properties)) + { + return parent::make_return(); + } + else + { + return $this->base->make_return(); + } + } + + function unfold_soak($options) + { + if (isset($this->unfolded_soak)) + { + return $this->unfolded_soak; + } + + $result = NULL; + + if (($ifn = $this->base->unfold_soak($options))) + { + $ifn->body->properties = array_merge($ifn->body->properties, $this->properties); + $result = $ifn; + } + else + { + foreach ($this->properties as $i => $prop) + { + if (isset($prop->soak) && $prop->soak) + { + $prop->soak = FALSE; + + $fst = yy('Value', $this->base, array_slice($this->properties, 0, $i)); + $snd = yy('Value', $this->base, array_slice($this->properties, $i)); + + if ($fst->is_complex()) + { + $ref = yy('Literal', $options['scope']->free_variable('ref')); + $fst = yy('Parens', yy('Assign', $ref, $fst)); + $snd->base = $ref; + } + + $result = yy('If', yy('Existence', $fst), $snd, array('soak' => TRUE)); + } + } + } + + $this->unfolded_soak = $result ? $result : FALSE; + + return $this->unfolded_soak; + } + + function unwrap() + { + return count($this->properties) ? $this : $this->base; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/nodes/while.php b/vas/rest/class/vmlib/coffeescript/classes/nodes/while.php new file mode 100755 index 0000000000000000000000000000000000000000..e19e7612d6c9aaaf7106640ff60d9f267e78d3cc --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/nodes/while.php @@ -0,0 +1,101 @@ +<?php + +namespace CoffeeScript; + +class yy_While extends yy_Base +{ + public $children = array('condition', 'guard', 'body'); + + public $returns = FALSE; + + function constructor($condition = NULL, $options = NULL) + { + $this->condition = (isset($options['invert']) && $options['invert']) ? + $condition->invert() : $condition; + + $this->guard = isset($options['guard']) ? $options['guard'] : NULL; + + return $this; + } + + function add_body($body) + { + $this->body = $body; + return $this; + } + + function compile_node($options) + { + $options['indent'] .= TAB; + $set = ''; + $body = $this->body; + + if ($body->is_empty()) + { + $body = ''; + } + else + { + if ($options['level'] > LEVEL_TOP || $this->returns) + { + $rvar = $options['scope']->free_variable('results'); + $set = "{$this->tab}{$rvar} = [];\n"; + + if ($body) + { + $body = yy_Push::wrap($rvar, $body); + } + } + + if ($this->guard) + { + $body = yy_Block::wrap(array(yy('If', $this->guard, $body))); + } + + $body = "\n".$body->compile($options, LEVEL_TOP)."\n{$this->tab}"; + } + + $code = $set.$this->tab.'while ('.$this->condition->compile($options, LEVEL_PAREN).") {{$body}}"; + + if ($this->returns) + { + $code .= "\n{$this->tab}return {$rvar};"; + } + + return $code; + } + + function is_statement() + { + return TRUE; + } + + function jumps() + { + $expressions = isset($this->body->expressions) ? $this->body->expressions : array(); + + if ( ! count($expressions)) + { + return FALSE; + } + + foreach ($expressions as $node) + { + if ($node->jumps(array('loop' => TRUE))) + { + return $node; + } + } + + return FALSE; + } + + function make_return() + { + $this->returns = TRUE; + + return $this; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/parser.php b/vas/rest/class/vmlib/coffeescript/classes/parser.php new file mode 100755 index 0000000000000000000000000000000000000000..65ad16b719d033418d0fb81e4e1776f841268fc2 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/parser.php @@ -0,0 +1,3291 @@ +<?php +namespace CoffeeScript; +use \ArrayAccess as ArrayAccess; +/* Driver template for the PHP_ParserGenerator parser generator. (PHP port of LEMON) +*/ + +/** + * This can be used to store both the string representation of + * a token, and any useful meta-data associated with the token. + * + * meta-data should be stored as an array + */ +class yyToken implements ArrayAccess +{ + public $string = ''; + public $metadata = array(); + + function __construct($s, $m = array()) + { + if ($s instanceof yyToken) { + $this->string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof yyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof yyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof yyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class yyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ + + public $generated = FALSE; +}; + +// code external to the class is included here + +// declare_class is output here +#line 2 "/var/www/coffeescript-php/grammar.y" + class Parser #line 104 "/var/www/coffeescript-php/grammar.php" +{ + static $LINE = 0; + static $FILE = 'unknown'; + +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ + const YY_POST_IF = 1; + const YY_IF = 2; + const YY_ELSE = 3; + const YY_FOR = 4; + const YY_DO = 5; + const YY_WHILE = 6; + const YY_UNTIL = 7; + const YY_LOOP = 8; + const YY_SUPER = 9; + const YY_CLASS = 10; + const YY_FORIN = 11; + const YY_FOROF = 12; + const YY_BY = 13; + const YY_WHEN = 14; + const YY_EQUALS = 15; + const YY_COLON = 16; + const YY_COMPOUND_ASSIGN = 17; + const YY_RETURN = 18; + const YY_THROW = 19; + const YY_EXTENDS = 20; + const YY_INDENT = 21; + const YY_OUTDENT = 22; + const YY_LOGIC = 23; + const YY_COMPARE = 24; + const YY_RELATION = 25; + const YY_SHIFT = 26; + const YY_PLUS = 27; + const YY_MINUS = 28; + const YY_MATH = 29; + const YY_UNARY = 30; + const YY_EXISTENTIAL = 31; + const YY_INCREMENT = 32; + const YY_DECREMENT = 33; + const YY_CALL_START = 34; + const YY_CALL_END = 35; + const YY_ACCESSOR = 36; + const YY_EXISTENTIAL_ACCESSOR = 37; + const YY_PROTOTYPE = 38; + const YY_TERMINATOR = 39; + const YY_STATEMENT = 40; + const YY_IDENTIFIER = 41; + const YY_NUMBER = 42; + const YY_STRING = 43; + const YY_JS = 44; + const YY_REGEX = 45; + const YY_BOOL = 46; + const YY_HERECOMMENT = 47; + const YY_PARAM_START = 48; + const YY_PARAM_END = 49; + const YY_FUNC = 50; + const YY_BOUND_FUNC = 51; + const YY_COMMA = 52; + const YY_RANGE_EXCLUSIVE = 53; + const YY_INDEX_START = 54; + const YY_INDEX_END = 55; + const YY_INDEX_SOAK = 56; + const YY_INDEX_PROTO = 57; + const YY_OBJECT_START = 58; + const YY_OBJECT_END = 59; + const YY_FUNC_EXIST = 60; + const YY_THIS = 61; + const YY_AT_SIGN = 62; + const YY_ARRAY_START = 63; + const YY_ARRAY_END = 64; + const YY_RANGE_INCLUSIVE = 65; + const YY_TRY = 66; + const YY_FINALLY = 67; + const YY_CATCH = 68; + const YY_PAREN_START = 69; + const YY_PAREN_END = 70; + const YY_OWN = 71; + const YY_SWITCH = 72; + const YY_LEADING_WHEN = 73; + const YY_NO_ACTION = 510; + const YY_ACCEPT_ACTION = 509; + const YY_ERROR_ACTION = 508; + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ + const YY_SZ_ACTTAB = 4481; +static public $yy_action = array( + /* 0 */ 509, 182, 181, 233, 88, 115, 286, 281, 223, 102, + /* 10 */ 105, 251, 247, 248, 249, 250, 257, 258, 265, 266, + /* 20 */ 234, 263, 236, 186, 226, 227, 235, 48, 155, 311, + /* 30 */ 43, 51, 241, 240, 225, 162, 139, 237, 238, 239, + /* 40 */ 25, 35, 23, 36, 32, 49, 48, 246, 311, 245, + /* 50 */ 132, 158, 305, 151, 132, 292, 1, 13, 126, 128, + /* 60 */ 184, 80, 116, 286, 281, 223, 102, 105, 251, 247, + /* 70 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 80 */ 186, 52, 7, 235, 66, 155, 40, 34, 309, 241, + /* 90 */ 240, 290, 162, 244, 237, 238, 239, 35, 23, 36, + /* 100 */ 32, 49, 48, 140, 311, 283, 14, 24, 158, 305, + /* 110 */ 151, 132, 32, 49, 48, 291, 311, 184, 68, 116, + /* 120 */ 286, 281, 223, 102, 105, 251, 247, 248, 249, 250, + /* 130 */ 257, 258, 265, 266, 234, 263, 236, 186, 154, 156, + /* 140 */ 235, 244, 155, 64, 220, 213, 241, 240, 290, 162, + /* 150 */ 206, 237, 238, 239, 215, 173, 209, 207, 60, 210, + /* 160 */ 147, 134, 283, 2, 65, 158, 305, 151, 132, 33, + /* 170 */ 22, 214, 188, 166, 184, 80, 116, 286, 281, 223, + /* 180 */ 102, 105, 251, 247, 248, 249, 250, 257, 258, 265, + /* 190 */ 266, 234, 263, 236, 186, 218, 176, 235, 228, 155, + /* 200 */ 224, 132, 31, 241, 240, 290, 162, 303, 237, 238, + /* 210 */ 239, 179, 23, 36, 32, 49, 48, 145, 311, 283, + /* 220 */ 307, 7, 158, 305, 151, 132, 278, 133, 13, 310, + /* 230 */ 272, 184, 80, 116, 286, 281, 223, 102, 105, 251, + /* 240 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 250 */ 236, 186, 129, 270, 235, 7, 155, 127, 270, 304, + /* 260 */ 241, 240, 290, 162, 130, 237, 238, 239, 36, 32, + /* 270 */ 49, 48, 210, 311, 144, 246, 283, 245, 132, 158, + /* 280 */ 305, 151, 132, 279, 214, 188, 21, 159, 184, 80, + /* 290 */ 116, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 300 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 208, + /* 310 */ 308, 235, 17, 155, 191, 44, 13, 241, 240, 290, + /* 320 */ 162, 15, 237, 238, 239, 229, 5, 243, 242, 16, + /* 330 */ 302, 147, 246, 283, 245, 132, 158, 305, 151, 132, + /* 340 */ 221, 74, 13, 294, 10, 184, 69, 116, 286, 281, + /* 350 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 360 */ 265, 266, 234, 263, 236, 186, 274, 222, 235, 244, + /* 370 */ 155, 153, 268, 3, 241, 240, 138, 162, 262, 237, + /* 380 */ 238, 239, 183, 180, 190, 189, 60, 177, 230, 50, + /* 390 */ 137, 2, 14, 158, 305, 151, 132, 311, 299, 275, + /* 400 */ 276, 255, 184, 80, 116, 286, 281, 223, 102, 105, + /* 410 */ 251, 247, 248, 249, 250, 257, 258, 265, 266, 234, + /* 420 */ 263, 236, 186, 175, 256, 235, 11, 155, 232, 168, + /* 430 */ 37, 241, 240, 290, 162, 297, 237, 238, 239, 5, + /* 440 */ 25, 35, 23, 36, 32, 49, 48, 289, 311, 252, + /* 450 */ 158, 305, 151, 132, 164, 253, 167, 10, 171, 184, + /* 460 */ 233, 88, 115, 286, 281, 223, 102, 105, 251, 247, + /* 470 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 480 */ 186, 178, 287, 235, 165, 155, 5, 284, 28, 241, + /* 490 */ 240, 169, 162, 332, 237, 238, 239, 25, 35, 23, + /* 500 */ 36, 32, 49, 48, 10, 311, 332, 332, 158, 305, + /* 510 */ 151, 132, 332, 332, 332, 332, 332, 184, 80, 116, + /* 520 */ 286, 281, 223, 102, 105, 251, 247, 248, 249, 250, + /* 530 */ 257, 258, 265, 266, 234, 263, 236, 186, 332, 332, + /* 540 */ 235, 332, 155, 332, 332, 332, 241, 240, 290, 162, + /* 550 */ 332, 237, 238, 239, 332, 25, 35, 23, 36, 32, + /* 560 */ 49, 48, 282, 311, 332, 158, 305, 151, 132, 332, + /* 570 */ 332, 332, 332, 174, 184, 233, 88, 115, 286, 281, + /* 580 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 590 */ 265, 266, 234, 263, 236, 186, 300, 332, 235, 332, + /* 600 */ 155, 5, 285, 42, 241, 240, 332, 162, 332, 237, + /* 610 */ 238, 239, 25, 35, 23, 36, 32, 49, 48, 10, + /* 620 */ 311, 332, 332, 158, 305, 151, 132, 332, 332, 254, + /* 630 */ 312, 332, 184, 277, 277, 332, 332, 142, 135, 172, + /* 640 */ 332, 233, 88, 115, 286, 281, 223, 102, 105, 251, + /* 650 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 660 */ 236, 186, 332, 192, 235, 332, 155, 332, 332, 374, + /* 670 */ 241, 240, 332, 162, 332, 237, 238, 239, 53, 332, + /* 680 */ 66, 332, 40, 34, 12, 143, 55, 374, 332, 158, + /* 690 */ 305, 151, 132, 332, 54, 38, 332, 312, 184, 332, + /* 700 */ 374, 277, 332, 19, 20, 135, 26, 46, 58, 56, + /* 710 */ 332, 246, 374, 245, 132, 332, 306, 244, 267, 264, + /* 720 */ 259, 260, 261, 231, 62, 332, 226, 227, 312, 194, + /* 730 */ 332, 332, 277, 332, 60, 332, 135, 293, 150, 4, + /* 740 */ 47, 295, 152, 332, 246, 8, 245, 132, 18, 273, + /* 750 */ 332, 94, 116, 286, 281, 223, 102, 105, 251, 247, + /* 760 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 770 */ 186, 61, 198, 235, 332, 155, 149, 332, 332, 241, + /* 780 */ 240, 220, 162, 332, 237, 238, 239, 206, 170, 63, + /* 790 */ 332, 219, 173, 209, 207, 271, 332, 332, 158, 305, + /* 800 */ 151, 132, 332, 332, 332, 332, 332, 184, 211, 88, + /* 810 */ 115, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 820 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 332, + /* 830 */ 332, 235, 332, 155, 332, 195, 332, 241, 240, 332, + /* 840 */ 162, 332, 237, 238, 239, 332, 14, 196, 199, 332, + /* 850 */ 332, 204, 185, 216, 332, 332, 158, 305, 151, 132, + /* 860 */ 332, 332, 332, 332, 332, 184, 91, 116, 286, 281, + /* 870 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 880 */ 265, 266, 234, 263, 236, 186, 332, 61, 235, 332, + /* 890 */ 155, 332, 332, 332, 241, 240, 332, 162, 332, 237, + /* 900 */ 238, 239, 53, 332, 66, 63, 40, 34, 12, 143, + /* 910 */ 55, 131, 332, 158, 305, 151, 132, 332, 54, 38, + /* 920 */ 332, 6, 184, 332, 332, 193, 332, 19, 20, 332, + /* 930 */ 26, 332, 58, 56, 332, 205, 332, 332, 332, 332, + /* 940 */ 306, 244, 267, 264, 259, 260, 261, 231, 62, 332, + /* 950 */ 226, 227, 210, 244, 267, 264, 244, 332, 60, 231, + /* 960 */ 332, 293, 150, 4, 214, 188, 152, 332, 332, 8, + /* 970 */ 201, 332, 18, 60, 137, 53, 332, 66, 4, 40, + /* 980 */ 34, 12, 143, 55, 332, 332, 67, 332, 217, 176, + /* 990 */ 332, 54, 38, 332, 6, 332, 332, 332, 332, 332, + /* 1000 */ 19, 20, 332, 26, 332, 58, 56, 332, 332, 332, + /* 1010 */ 332, 332, 332, 306, 244, 267, 264, 259, 260, 261, + /* 1020 */ 231, 62, 332, 226, 227, 332, 332, 332, 332, 332, + /* 1030 */ 332, 60, 332, 332, 293, 150, 4, 280, 332, 152, + /* 1040 */ 332, 332, 8, 332, 332, 18, 77, 116, 286, 281, + /* 1050 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 1060 */ 265, 266, 234, 263, 236, 186, 332, 332, 235, 332, + /* 1070 */ 155, 332, 332, 332, 241, 240, 332, 162, 332, 237, + /* 1080 */ 238, 239, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1090 */ 332, 332, 332, 158, 305, 151, 132, 332, 332, 332, + /* 1100 */ 332, 332, 184, 109, 116, 286, 281, 223, 102, 105, + /* 1110 */ 251, 247, 248, 249, 250, 257, 258, 265, 266, 234, + /* 1120 */ 263, 236, 186, 332, 332, 235, 332, 155, 332, 195, + /* 1130 */ 332, 241, 240, 332, 162, 332, 237, 238, 239, 332, + /* 1140 */ 332, 196, 199, 332, 332, 202, 185, 216, 332, 332, + /* 1150 */ 158, 305, 151, 132, 332, 332, 332, 332, 332, 184, + /* 1160 */ 117, 116, 286, 281, 223, 102, 105, 251, 247, 248, + /* 1170 */ 249, 250, 257, 258, 265, 266, 234, 263, 236, 186, + /* 1180 */ 332, 332, 235, 332, 155, 332, 332, 332, 241, 240, + /* 1190 */ 332, 162, 332, 237, 238, 239, 332, 332, 332, 332, + /* 1200 */ 332, 332, 332, 332, 332, 332, 332, 158, 305, 151, + /* 1210 */ 132, 332, 332, 332, 332, 332, 184, 84, 116, 286, + /* 1220 */ 281, 223, 102, 105, 251, 247, 248, 249, 250, 257, + /* 1230 */ 258, 265, 266, 234, 263, 236, 186, 332, 332, 235, + /* 1240 */ 332, 155, 332, 332, 332, 241, 240, 332, 162, 332, + /* 1250 */ 237, 238, 239, 332, 332, 332, 332, 332, 332, 332, + /* 1260 */ 332, 332, 332, 332, 158, 305, 151, 132, 332, 332, + /* 1270 */ 332, 332, 332, 184, 71, 116, 286, 281, 223, 102, + /* 1280 */ 105, 251, 247, 248, 249, 250, 257, 258, 265, 266, + /* 1290 */ 234, 263, 236, 186, 332, 332, 235, 332, 155, 332, + /* 1300 */ 332, 332, 241, 240, 332, 162, 332, 237, 238, 239, + /* 1310 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1320 */ 332, 158, 305, 151, 132, 332, 332, 332, 332, 332, + /* 1330 */ 184, 93, 116, 286, 281, 223, 102, 105, 251, 247, + /* 1340 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 1350 */ 186, 332, 332, 235, 332, 155, 332, 332, 332, 241, + /* 1360 */ 240, 332, 162, 332, 237, 238, 239, 332, 332, 332, + /* 1370 */ 332, 332, 332, 332, 332, 332, 332, 332, 158, 305, + /* 1380 */ 151, 132, 332, 332, 332, 332, 332, 184, 103, 116, + /* 1390 */ 286, 281, 223, 102, 105, 251, 247, 248, 249, 250, + /* 1400 */ 257, 258, 265, 266, 234, 263, 236, 186, 332, 332, + /* 1410 */ 235, 332, 155, 332, 332, 332, 241, 240, 332, 162, + /* 1420 */ 332, 237, 238, 239, 332, 332, 332, 332, 332, 332, + /* 1430 */ 332, 332, 332, 332, 332, 158, 305, 151, 132, 332, + /* 1440 */ 332, 332, 332, 332, 184, 83, 116, 286, 281, 223, + /* 1450 */ 102, 105, 251, 247, 248, 249, 250, 257, 258, 265, + /* 1460 */ 266, 234, 263, 236, 186, 332, 332, 235, 332, 155, + /* 1470 */ 332, 332, 332, 241, 240, 332, 162, 332, 237, 238, + /* 1480 */ 239, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1490 */ 332, 332, 158, 305, 151, 132, 332, 332, 332, 332, + /* 1500 */ 332, 184, 78, 116, 286, 281, 223, 102, 105, 251, + /* 1510 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 1520 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 1530 */ 241, 240, 332, 162, 332, 237, 238, 239, 332, 332, + /* 1540 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 158, + /* 1550 */ 305, 151, 132, 332, 332, 332, 332, 332, 184, 85, + /* 1560 */ 116, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 1570 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 332, + /* 1580 */ 332, 235, 332, 155, 332, 332, 332, 241, 240, 332, + /* 1590 */ 162, 332, 237, 238, 239, 332, 332, 332, 332, 332, + /* 1600 */ 332, 332, 332, 332, 332, 332, 158, 305, 151, 132, + /* 1610 */ 332, 332, 332, 332, 332, 184, 121, 116, 286, 281, + /* 1620 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 1630 */ 265, 266, 234, 263, 236, 186, 332, 332, 235, 332, + /* 1640 */ 155, 332, 332, 332, 241, 240, 332, 162, 332, 237, + /* 1650 */ 238, 239, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1660 */ 332, 332, 332, 158, 305, 151, 132, 332, 332, 332, + /* 1670 */ 332, 332, 184, 122, 116, 286, 281, 223, 102, 105, + /* 1680 */ 251, 247, 248, 249, 250, 257, 258, 265, 266, 234, + /* 1690 */ 263, 236, 186, 332, 332, 235, 332, 155, 332, 332, + /* 1700 */ 332, 241, 240, 332, 162, 332, 237, 238, 239, 332, + /* 1710 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1720 */ 158, 305, 151, 132, 332, 332, 332, 332, 332, 184, + /* 1730 */ 75, 116, 286, 281, 223, 102, 105, 251, 247, 248, + /* 1740 */ 249, 250, 257, 258, 265, 266, 234, 263, 236, 186, + /* 1750 */ 332, 332, 235, 332, 155, 332, 332, 332, 241, 240, + /* 1760 */ 332, 162, 332, 237, 238, 239, 332, 332, 332, 332, + /* 1770 */ 332, 332, 332, 332, 332, 332, 332, 158, 305, 151, + /* 1780 */ 132, 332, 332, 332, 332, 332, 184, 114, 116, 286, + /* 1790 */ 281, 223, 102, 105, 251, 247, 248, 249, 250, 257, + /* 1800 */ 258, 265, 266, 234, 263, 236, 186, 332, 332, 235, + /* 1810 */ 332, 155, 332, 332, 332, 241, 240, 332, 162, 332, + /* 1820 */ 237, 238, 239, 332, 332, 332, 332, 332, 332, 332, + /* 1830 */ 332, 332, 332, 332, 158, 305, 151, 132, 332, 332, + /* 1840 */ 332, 332, 332, 184, 108, 116, 286, 281, 223, 102, + /* 1850 */ 105, 251, 247, 248, 249, 250, 257, 258, 265, 266, + /* 1860 */ 234, 263, 236, 186, 332, 332, 235, 332, 155, 332, + /* 1870 */ 332, 332, 241, 240, 332, 162, 332, 237, 238, 239, + /* 1880 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 1890 */ 332, 158, 305, 151, 132, 332, 332, 332, 332, 332, + /* 1900 */ 184, 99, 116, 286, 281, 223, 102, 105, 251, 247, + /* 1910 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 1920 */ 186, 332, 332, 235, 332, 155, 332, 332, 332, 241, + /* 1930 */ 240, 332, 162, 332, 237, 238, 239, 332, 332, 332, + /* 1940 */ 332, 332, 332, 332, 332, 332, 332, 332, 158, 305, + /* 1950 */ 151, 132, 332, 332, 332, 332, 332, 184, 92, 116, + /* 1960 */ 286, 281, 223, 102, 105, 251, 247, 248, 249, 250, + /* 1970 */ 257, 258, 265, 266, 234, 263, 236, 186, 332, 332, + /* 1980 */ 235, 332, 155, 332, 332, 332, 241, 240, 332, 162, + /* 1990 */ 332, 237, 238, 239, 332, 332, 332, 332, 332, 332, + /* 2000 */ 332, 332, 332, 332, 332, 158, 305, 151, 132, 332, + /* 2010 */ 332, 332, 332, 332, 184, 76, 116, 286, 281, 223, + /* 2020 */ 102, 105, 251, 247, 248, 249, 250, 257, 258, 265, + /* 2030 */ 266, 234, 263, 236, 186, 332, 332, 235, 332, 155, + /* 2040 */ 332, 332, 332, 241, 240, 332, 162, 332, 237, 238, + /* 2050 */ 239, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 2060 */ 332, 332, 158, 305, 151, 132, 332, 332, 332, 332, + /* 2070 */ 332, 184, 90, 116, 286, 281, 223, 102, 105, 251, + /* 2080 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 2090 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 2100 */ 241, 240, 332, 162, 332, 237, 238, 239, 332, 332, + /* 2110 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 158, + /* 2120 */ 305, 151, 132, 332, 332, 332, 332, 332, 184, 107, + /* 2130 */ 116, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 2140 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 332, + /* 2150 */ 332, 235, 332, 155, 332, 332, 332, 241, 240, 332, + /* 2160 */ 162, 332, 237, 238, 239, 332, 332, 332, 332, 332, + /* 2170 */ 332, 332, 332, 332, 332, 332, 158, 305, 151, 132, + /* 2180 */ 332, 332, 332, 332, 332, 184, 113, 116, 286, 281, + /* 2190 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 2200 */ 265, 266, 234, 263, 236, 186, 332, 332, 235, 332, + /* 2210 */ 155, 332, 332, 332, 241, 240, 332, 162, 332, 237, + /* 2220 */ 238, 239, 332, 332, 332, 332, 332, 332, 332, 332, + /* 2230 */ 332, 332, 332, 158, 305, 151, 132, 332, 332, 332, + /* 2240 */ 332, 332, 184, 104, 116, 286, 281, 223, 102, 105, + /* 2250 */ 251, 247, 248, 249, 250, 257, 258, 265, 266, 234, + /* 2260 */ 263, 236, 186, 332, 332, 235, 332, 155, 332, 332, + /* 2270 */ 332, 241, 240, 332, 162, 332, 237, 238, 239, 332, + /* 2280 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 2290 */ 158, 305, 151, 132, 332, 332, 332, 332, 332, 184, + /* 2300 */ 95, 116, 286, 281, 223, 102, 105, 251, 247, 248, + /* 2310 */ 249, 250, 257, 258, 265, 266, 234, 263, 236, 186, + /* 2320 */ 332, 332, 235, 332, 155, 332, 332, 332, 241, 240, + /* 2330 */ 332, 162, 332, 237, 238, 239, 332, 332, 332, 332, + /* 2340 */ 332, 332, 332, 332, 332, 332, 332, 158, 305, 151, + /* 2350 */ 132, 332, 332, 332, 332, 332, 184, 87, 116, 286, + /* 2360 */ 281, 223, 102, 105, 251, 247, 248, 249, 250, 257, + /* 2370 */ 258, 265, 266, 234, 263, 236, 186, 332, 332, 235, + /* 2380 */ 332, 155, 332, 332, 332, 241, 240, 332, 162, 332, + /* 2390 */ 237, 238, 239, 332, 332, 332, 332, 332, 332, 332, + /* 2400 */ 332, 332, 332, 332, 158, 305, 151, 132, 332, 332, + /* 2410 */ 332, 332, 332, 184, 112, 116, 286, 281, 223, 102, + /* 2420 */ 105, 251, 247, 248, 249, 250, 257, 258, 265, 266, + /* 2430 */ 234, 263, 236, 186, 332, 332, 235, 332, 155, 332, + /* 2440 */ 332, 332, 241, 240, 332, 162, 332, 237, 238, 239, + /* 2450 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 2460 */ 332, 158, 305, 151, 132, 332, 332, 332, 332, 332, + /* 2470 */ 184, 97, 116, 286, 281, 223, 102, 105, 251, 247, + /* 2480 */ 248, 249, 250, 257, 258, 265, 266, 234, 263, 236, + /* 2490 */ 186, 332, 332, 235, 332, 155, 332, 332, 332, 241, + /* 2500 */ 240, 332, 162, 332, 237, 238, 239, 332, 332, 332, + /* 2510 */ 332, 332, 332, 332, 332, 332, 332, 332, 158, 305, + /* 2520 */ 151, 132, 332, 332, 332, 332, 332, 184, 119, 116, + /* 2530 */ 286, 281, 223, 102, 105, 251, 247, 248, 249, 250, + /* 2540 */ 257, 258, 265, 266, 234, 263, 236, 186, 332, 332, + /* 2550 */ 235, 332, 155, 332, 332, 332, 241, 240, 332, 162, + /* 2560 */ 332, 237, 238, 239, 332, 332, 332, 332, 332, 332, + /* 2570 */ 332, 332, 332, 332, 332, 158, 305, 151, 132, 332, + /* 2580 */ 332, 332, 332, 332, 184, 96, 116, 286, 281, 223, + /* 2590 */ 102, 105, 251, 247, 248, 249, 250, 257, 258, 265, + /* 2600 */ 266, 234, 263, 236, 186, 332, 332, 235, 332, 155, + /* 2610 */ 332, 332, 332, 241, 240, 332, 162, 332, 237, 238, + /* 2620 */ 239, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 2630 */ 332, 332, 158, 305, 151, 132, 332, 332, 332, 332, + /* 2640 */ 332, 184, 82, 116, 286, 281, 223, 102, 105, 251, + /* 2650 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 2660 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 2670 */ 241, 240, 332, 162, 332, 237, 238, 239, 53, 332, + /* 2680 */ 66, 332, 40, 34, 12, 143, 55, 332, 332, 158, + /* 2690 */ 305, 151, 132, 332, 54, 38, 332, 7, 184, 332, + /* 2700 */ 332, 332, 332, 19, 20, 332, 26, 332, 58, 56, + /* 2710 */ 332, 332, 332, 332, 332, 332, 306, 244, 267, 264, + /* 2720 */ 259, 260, 261, 231, 62, 332, 226, 227, 332, 332, + /* 2730 */ 332, 332, 332, 332, 60, 332, 332, 293, 150, 4, + /* 2740 */ 332, 332, 152, 332, 332, 8, 332, 332, 18, 332, + /* 2750 */ 332, 53, 332, 66, 332, 40, 34, 12, 143, 55, + /* 2760 */ 332, 332, 332, 332, 332, 332, 332, 54, 38, 332, + /* 2770 */ 27, 332, 332, 332, 332, 332, 19, 20, 332, 26, + /* 2780 */ 332, 58, 56, 332, 332, 332, 332, 332, 332, 306, + /* 2790 */ 244, 267, 264, 259, 260, 261, 231, 62, 332, 226, + /* 2800 */ 227, 332, 332, 332, 332, 332, 332, 60, 332, 332, + /* 2810 */ 293, 150, 4, 332, 332, 152, 332, 332, 8, 332, + /* 2820 */ 332, 18, 101, 116, 286, 281, 223, 102, 105, 251, + /* 2830 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 2840 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 2850 */ 241, 240, 332, 162, 332, 237, 238, 239, 53, 332, + /* 2860 */ 66, 332, 40, 34, 12, 143, 55, 332, 332, 158, + /* 2870 */ 305, 151, 132, 332, 54, 38, 332, 41, 184, 332, + /* 2880 */ 332, 332, 332, 19, 20, 332, 26, 332, 58, 56, + /* 2890 */ 332, 332, 332, 332, 332, 332, 306, 244, 267, 264, + /* 2900 */ 259, 260, 261, 231, 62, 332, 226, 227, 332, 332, + /* 2910 */ 332, 332, 332, 332, 60, 332, 332, 293, 150, 4, + /* 2920 */ 332, 332, 152, 332, 332, 8, 332, 332, 18, 332, + /* 2930 */ 332, 53, 332, 66, 332, 40, 34, 12, 143, 55, + /* 2940 */ 332, 332, 332, 332, 332, 332, 332, 54, 38, 332, + /* 2950 */ 45, 332, 332, 332, 332, 332, 19, 20, 332, 26, + /* 2960 */ 332, 58, 56, 332, 332, 332, 332, 332, 332, 306, + /* 2970 */ 244, 267, 264, 259, 260, 261, 231, 62, 332, 226, + /* 2980 */ 227, 332, 332, 332, 332, 332, 332, 60, 332, 332, + /* 2990 */ 293, 150, 4, 332, 332, 152, 332, 332, 8, 332, + /* 3000 */ 332, 18, 70, 116, 286, 281, 223, 102, 105, 251, + /* 3010 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 3020 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 3030 */ 241, 240, 332, 162, 332, 237, 238, 239, 332, 332, + /* 3040 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 158, + /* 3050 */ 305, 151, 132, 332, 332, 332, 332, 332, 184, 100, + /* 3060 */ 116, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 3070 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 332, + /* 3080 */ 332, 235, 332, 155, 332, 332, 332, 241, 240, 332, + /* 3090 */ 162, 332, 237, 238, 239, 53, 332, 66, 332, 40, + /* 3100 */ 34, 12, 143, 55, 332, 332, 158, 305, 151, 132, + /* 3110 */ 332, 54, 38, 332, 6, 184, 332, 332, 332, 332, + /* 3120 */ 19, 20, 332, 26, 332, 58, 56, 332, 332, 332, + /* 3130 */ 332, 332, 332, 306, 244, 267, 264, 259, 260, 261, + /* 3140 */ 231, 62, 332, 226, 227, 332, 332, 332, 332, 332, + /* 3150 */ 332, 60, 332, 332, 293, 150, 4, 332, 332, 152, + /* 3160 */ 332, 332, 8, 332, 332, 18, 332, 332, 53, 332, + /* 3170 */ 66, 332, 40, 34, 12, 143, 55, 332, 332, 332, + /* 3180 */ 332, 332, 332, 332, 54, 38, 332, 332, 187, 332, + /* 3190 */ 332, 332, 332, 19, 20, 332, 26, 332, 58, 56, + /* 3200 */ 332, 332, 332, 332, 332, 332, 306, 244, 267, 264, + /* 3210 */ 259, 260, 261, 231, 62, 332, 226, 227, 332, 332, + /* 3220 */ 332, 332, 332, 332, 60, 332, 332, 293, 150, 4, + /* 3230 */ 332, 332, 152, 332, 332, 8, 332, 332, 18, 332, + /* 3240 */ 332, 53, 332, 66, 332, 40, 34, 12, 143, 55, + /* 3250 */ 332, 332, 332, 332, 332, 332, 332, 54, 38, 332, + /* 3260 */ 9, 332, 332, 332, 332, 332, 19, 20, 332, 26, + /* 3270 */ 332, 58, 56, 332, 332, 332, 332, 332, 332, 306, + /* 3280 */ 244, 267, 264, 259, 260, 261, 231, 62, 332, 226, + /* 3290 */ 227, 332, 332, 332, 332, 332, 332, 60, 332, 332, + /* 3300 */ 293, 150, 4, 332, 332, 152, 332, 332, 8, 332, + /* 3310 */ 332, 18, 106, 116, 286, 281, 223, 102, 105, 251, + /* 3320 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 3330 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 3340 */ 241, 240, 332, 162, 332, 237, 238, 239, 332, 332, + /* 3350 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 158, + /* 3360 */ 305, 151, 132, 332, 332, 332, 332, 332, 184, 86, + /* 3370 */ 116, 286, 281, 223, 102, 105, 251, 247, 248, 249, + /* 3380 */ 250, 257, 258, 265, 266, 234, 263, 236, 186, 332, + /* 3390 */ 332, 235, 332, 155, 332, 332, 332, 241, 240, 332, + /* 3400 */ 162, 332, 237, 238, 239, 332, 332, 332, 332, 332, + /* 3410 */ 332, 332, 332, 332, 332, 332, 158, 305, 151, 132, + /* 3420 */ 332, 332, 332, 332, 332, 184, 120, 116, 286, 281, + /* 3430 */ 223, 102, 105, 251, 247, 248, 249, 250, 257, 258, + /* 3440 */ 265, 266, 234, 263, 236, 186, 332, 332, 235, 332, + /* 3450 */ 155, 332, 332, 332, 241, 240, 332, 162, 332, 237, + /* 3460 */ 238, 239, 332, 332, 332, 332, 332, 332, 332, 332, + /* 3470 */ 332, 332, 332, 158, 305, 151, 132, 332, 332, 332, + /* 3480 */ 332, 332, 184, 118, 116, 286, 281, 223, 102, 105, + /* 3490 */ 251, 247, 248, 249, 250, 257, 258, 265, 266, 234, + /* 3500 */ 263, 236, 186, 332, 332, 235, 332, 155, 332, 332, + /* 3510 */ 332, 241, 240, 332, 162, 332, 237, 238, 239, 332, + /* 3520 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 3530 */ 158, 305, 151, 132, 332, 332, 332, 332, 332, 184, + /* 3540 */ 89, 116, 286, 281, 223, 102, 105, 251, 247, 248, + /* 3550 */ 249, 250, 257, 258, 265, 266, 234, 263, 236, 186, + /* 3560 */ 332, 332, 235, 332, 155, 332, 332, 332, 241, 240, + /* 3570 */ 332, 162, 332, 237, 238, 239, 332, 332, 332, 332, + /* 3580 */ 332, 332, 332, 332, 332, 332, 332, 158, 305, 151, + /* 3590 */ 132, 332, 332, 332, 332, 332, 184, 79, 116, 286, + /* 3600 */ 281, 223, 102, 105, 251, 247, 248, 249, 250, 257, + /* 3610 */ 258, 265, 266, 234, 263, 236, 186, 332, 332, 235, + /* 3620 */ 332, 155, 332, 332, 332, 241, 240, 332, 162, 332, + /* 3630 */ 237, 238, 239, 53, 332, 66, 332, 40, 34, 12, + /* 3640 */ 143, 55, 332, 332, 158, 305, 151, 132, 332, 54, + /* 3650 */ 38, 332, 124, 184, 332, 332, 332, 332, 19, 20, + /* 3660 */ 332, 26, 332, 58, 56, 332, 332, 332, 332, 332, + /* 3670 */ 332, 306, 244, 267, 264, 259, 260, 261, 231, 62, + /* 3680 */ 332, 226, 227, 332, 332, 332, 332, 332, 332, 60, + /* 3690 */ 332, 332, 293, 150, 4, 332, 332, 152, 332, 332, + /* 3700 */ 8, 332, 332, 18, 332, 98, 116, 286, 281, 223, + /* 3710 */ 102, 105, 251, 247, 248, 249, 250, 257, 258, 265, + /* 3720 */ 266, 234, 263, 236, 186, 332, 332, 235, 332, 155, + /* 3730 */ 332, 332, 332, 241, 240, 332, 162, 332, 237, 238, + /* 3740 */ 239, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 3750 */ 332, 332, 158, 305, 151, 132, 332, 332, 332, 332, + /* 3760 */ 332, 184, 81, 116, 286, 281, 223, 102, 105, 251, + /* 3770 */ 247, 248, 249, 250, 257, 258, 265, 266, 234, 263, + /* 3780 */ 236, 186, 332, 332, 235, 332, 155, 332, 332, 332, + /* 3790 */ 241, 240, 332, 162, 332, 237, 238, 239, 53, 332, + /* 3800 */ 66, 332, 40, 34, 12, 143, 55, 332, 332, 158, + /* 3810 */ 305, 151, 132, 332, 54, 38, 332, 332, 184, 332, + /* 3820 */ 332, 332, 332, 19, 20, 332, 26, 332, 58, 56, + /* 3830 */ 332, 332, 332, 332, 332, 332, 306, 244, 267, 264, + /* 3840 */ 259, 260, 261, 231, 62, 332, 226, 227, 332, 148, + /* 3850 */ 136, 146, 332, 332, 60, 332, 332, 293, 150, 4, + /* 3860 */ 332, 332, 152, 332, 332, 8, 332, 1, 18, 126, + /* 3870 */ 128, 53, 415, 269, 148, 136, 146, 12, 143, 55, + /* 3880 */ 332, 332, 332, 332, 332, 332, 332, 54, 38, 332, + /* 3890 */ 332, 332, 1, 332, 126, 128, 19, 20, 269, 26, + /* 3900 */ 332, 58, 56, 332, 332, 332, 332, 332, 332, 306, + /* 3910 */ 244, 267, 264, 259, 260, 261, 231, 62, 332, 226, + /* 3920 */ 227, 332, 143, 332, 332, 332, 332, 60, 332, 332, + /* 3930 */ 293, 150, 4, 57, 7, 152, 332, 332, 8, 332, + /* 3940 */ 30, 18, 332, 66, 332, 40, 34, 332, 332, 332, + /* 3950 */ 332, 332, 332, 332, 244, 267, 264, 259, 260, 261, + /* 3960 */ 332, 332, 25, 35, 23, 36, 32, 49, 48, 332, + /* 3970 */ 311, 60, 332, 332, 293, 150, 4, 332, 332, 332, + /* 3980 */ 332, 332, 8, 332, 30, 7, 332, 66, 332, 40, + /* 3990 */ 34, 332, 163, 332, 332, 332, 332, 332, 415, 332, + /* 4000 */ 148, 136, 146, 332, 295, 332, 25, 35, 23, 36, + /* 4010 */ 32, 49, 48, 332, 311, 332, 195, 332, 1, 313, + /* 4020 */ 126, 128, 332, 332, 269, 332, 110, 111, 196, 199, + /* 4030 */ 332, 332, 212, 185, 216, 332, 194, 234, 263, 236, + /* 4040 */ 298, 30, 332, 235, 66, 332, 40, 34, 295, 241, + /* 4050 */ 240, 157, 125, 332, 237, 238, 239, 332, 332, 332, + /* 4060 */ 332, 7, 332, 25, 35, 23, 36, 32, 49, 48, + /* 4070 */ 30, 311, 332, 66, 332, 40, 34, 332, 332, 332, + /* 4080 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 4090 */ 332, 197, 25, 35, 23, 36, 32, 49, 48, 30, + /* 4100 */ 311, 332, 66, 332, 40, 34, 332, 332, 332, 332, + /* 4110 */ 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, + /* 4120 */ 203, 25, 35, 23, 36, 32, 49, 48, 30, 311, + /* 4130 */ 332, 66, 332, 40, 34, 332, 332, 332, 332, 332, + /* 4140 */ 332, 332, 332, 332, 332, 332, 332, 332, 73, 111, + /* 4150 */ 25, 35, 23, 36, 32, 49, 48, 332, 311, 234, + /* 4160 */ 263, 236, 298, 332, 332, 235, 332, 332, 332, 332, + /* 4170 */ 332, 241, 240, 332, 301, 332, 237, 238, 239, 332, + /* 4180 */ 288, 332, 30, 332, 332, 66, 332, 40, 34, 332, + /* 4190 */ 332, 332, 332, 332, 332, 143, 332, 332, 332, 332, + /* 4200 */ 332, 332, 123, 332, 25, 35, 23, 36, 32, 49, + /* 4210 */ 48, 30, 311, 332, 66, 332, 40, 34, 332, 332, + /* 4220 */ 332, 332, 332, 332, 332, 332, 332, 244, 267, 264, + /* 4230 */ 259, 260, 261, 25, 35, 23, 36, 32, 49, 48, + /* 4240 */ 30, 311, 332, 66, 60, 40, 34, 293, 150, 4, + /* 4250 */ 332, 332, 332, 332, 332, 8, 332, 332, 332, 332, + /* 4260 */ 332, 200, 25, 35, 23, 36, 32, 49, 48, 332, + /* 4270 */ 311, 332, 110, 111, 296, 332, 332, 332, 332, 332, + /* 4280 */ 332, 332, 332, 234, 263, 236, 298, 332, 332, 235, + /* 4290 */ 332, 332, 72, 111, 332, 241, 240, 332, 161, 332, + /* 4300 */ 237, 238, 239, 234, 263, 236, 298, 332, 379, 235, + /* 4310 */ 379, 379, 379, 332, 332, 241, 240, 332, 301, 332, + /* 4320 */ 237, 238, 239, 332, 110, 111, 332, 332, 379, 332, + /* 4330 */ 379, 379, 332, 332, 379, 234, 263, 236, 298, 30, + /* 4340 */ 332, 235, 66, 332, 40, 34, 332, 241, 240, 332, + /* 4350 */ 160, 332, 237, 238, 239, 332, 332, 332, 332, 332, + /* 4360 */ 332, 25, 35, 23, 36, 32, 49, 48, 66, 311, + /* 4370 */ 40, 34, 332, 332, 332, 332, 332, 332, 39, 332, + /* 4380 */ 332, 332, 332, 332, 332, 332, 332, 25, 35, 23, + /* 4390 */ 36, 32, 49, 48, 66, 311, 40, 34, 332, 332, + /* 4400 */ 332, 332, 332, 332, 29, 332, 332, 332, 332, 66, + /* 4410 */ 332, 40, 34, 25, 35, 23, 36, 32, 49, 48, + /* 4420 */ 332, 311, 332, 332, 332, 332, 332, 332, 25, 35, + /* 4430 */ 23, 36, 32, 49, 48, 332, 311, 59, 7, 332, + /* 4440 */ 332, 332, 332, 332, 332, 195, 332, 332, 332, 332, + /* 4450 */ 332, 379, 332, 379, 379, 379, 332, 196, 199, 332, + /* 4460 */ 332, 212, 185, 216, 332, 332, 332, 332, 332, 332, + /* 4470 */ 332, 379, 332, 379, 379, 332, 332, 379, 332, 332, + /* 4480 */ 141, + ); + static public $yy_lookahead = array( + /* 0 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + /* 10 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + /* 20 */ 95, 96, 97, 98, 50, 51, 101, 29, 103, 31, + /* 30 */ 13, 14, 107, 108, 77, 110, 3, 112, 113, 114, + /* 40 */ 23, 24, 25, 26, 27, 28, 29, 126, 31, 128, + /* 50 */ 129, 126, 127, 128, 129, 22, 54, 39, 56, 57, + /* 60 */ 135, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 70 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 80 */ 98, 1, 21, 101, 4, 103, 6, 7, 70, 107, + /* 90 */ 108, 109, 110, 41, 112, 113, 114, 24, 25, 26, + /* 100 */ 27, 28, 29, 121, 31, 123, 73, 15, 126, 127, + /* 110 */ 128, 129, 27, 28, 29, 22, 31, 135, 79, 80, + /* 120 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + /* 130 */ 91, 92, 93, 94, 95, 96, 97, 98, 67, 68, + /* 140 */ 101, 41, 103, 52, 95, 53, 107, 108, 109, 110, + /* 150 */ 101, 112, 113, 114, 105, 106, 107, 108, 58, 95, + /* 160 */ 121, 49, 123, 63, 52, 126, 127, 128, 129, 11, + /* 170 */ 12, 107, 108, 104, 135, 79, 80, 81, 82, 83, + /* 180 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 190 */ 94, 95, 96, 97, 98, 131, 132, 101, 126, 103, + /* 200 */ 128, 129, 2, 107, 108, 109, 110, 77, 112, 113, + /* 210 */ 114, 22, 25, 26, 27, 28, 29, 121, 31, 123, + /* 220 */ 77, 21, 126, 127, 128, 129, 77, 77, 39, 77, + /* 230 */ 22, 135, 79, 80, 81, 82, 83, 84, 85, 86, + /* 240 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 250 */ 97, 98, 133, 134, 101, 21, 103, 133, 134, 77, + /* 260 */ 107, 108, 109, 110, 3, 112, 113, 114, 26, 27, + /* 270 */ 28, 29, 95, 31, 121, 126, 123, 128, 129, 126, + /* 280 */ 127, 128, 129, 77, 107, 108, 52, 67, 135, 79, + /* 290 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 300 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 132, + /* 310 */ 70, 101, 17, 103, 39, 20, 39, 107, 108, 109, + /* 320 */ 110, 15, 112, 113, 114, 22, 21, 32, 33, 16, + /* 330 */ 77, 121, 126, 123, 128, 129, 126, 127, 128, 129, + /* 340 */ 35, 52, 39, 95, 39, 135, 79, 80, 81, 82, + /* 350 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 360 */ 93, 94, 95, 96, 97, 98, 39, 55, 101, 41, + /* 370 */ 103, 95, 120, 34, 107, 108, 103, 110, 95, 112, + /* 380 */ 113, 114, 125, 116, 117, 77, 58, 77, 130, 122, + /* 390 */ 62, 63, 73, 126, 127, 128, 129, 31, 77, 77, + /* 400 */ 134, 115, 135, 79, 80, 81, 82, 83, 84, 85, + /* 410 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + /* 420 */ 96, 97, 98, 77, 115, 101, 52, 103, 95, 104, + /* 430 */ 13, 107, 108, 109, 110, 120, 112, 113, 114, 21, + /* 440 */ 23, 24, 25, 26, 27, 28, 29, 123, 31, 120, + /* 450 */ 126, 127, 128, 129, 104, 95, 104, 39, 76, 135, + /* 460 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 470 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 480 */ 98, 77, 64, 101, 104, 103, 21, 22, 14, 107, + /* 490 */ 108, 104, 110, 136, 112, 113, 114, 23, 24, 25, + /* 500 */ 26, 27, 28, 29, 39, 31, 136, 136, 126, 127, + /* 510 */ 128, 129, 136, 136, 136, 136, 136, 135, 79, 80, + /* 520 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + /* 530 */ 91, 92, 93, 94, 95, 96, 97, 98, 136, 136, + /* 540 */ 101, 136, 103, 136, 136, 136, 107, 108, 109, 110, + /* 550 */ 136, 112, 113, 114, 136, 23, 24, 25, 26, 27, + /* 560 */ 28, 29, 123, 31, 136, 126, 127, 128, 129, 136, + /* 570 */ 136, 136, 136, 76, 135, 78, 79, 80, 81, 82, + /* 580 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 590 */ 93, 94, 95, 96, 97, 98, 77, 136, 101, 136, + /* 600 */ 103, 21, 22, 14, 107, 108, 136, 110, 136, 112, + /* 610 */ 113, 114, 23, 24, 25, 26, 27, 28, 29, 39, + /* 620 */ 31, 136, 136, 126, 127, 128, 129, 136, 136, 111, + /* 630 */ 111, 136, 135, 115, 115, 136, 136, 119, 119, 76, + /* 640 */ 136, 78, 79, 80, 81, 82, 83, 84, 85, 86, + /* 650 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 660 */ 97, 98, 136, 77, 101, 136, 103, 136, 136, 21, + /* 670 */ 107, 108, 136, 110, 136, 112, 113, 114, 2, 136, + /* 680 */ 4, 136, 6, 7, 8, 9, 10, 39, 136, 126, + /* 690 */ 127, 128, 129, 136, 18, 19, 136, 111, 135, 136, + /* 700 */ 52, 115, 136, 27, 28, 119, 30, 122, 32, 33, + /* 710 */ 136, 126, 64, 128, 129, 136, 40, 41, 42, 43, + /* 720 */ 44, 45, 46, 47, 48, 136, 50, 51, 111, 53, + /* 730 */ 136, 136, 115, 136, 58, 136, 119, 61, 62, 63, + /* 740 */ 122, 65, 66, 136, 126, 69, 128, 129, 72, 77, + /* 750 */ 136, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 760 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 770 */ 98, 21, 22, 101, 136, 103, 3, 136, 136, 107, + /* 780 */ 108, 95, 110, 136, 112, 113, 114, 101, 102, 39, + /* 790 */ 136, 105, 106, 107, 108, 22, 136, 136, 126, 127, + /* 800 */ 128, 129, 136, 136, 136, 136, 136, 135, 78, 79, + /* 810 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 820 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 136, + /* 830 */ 136, 101, 136, 103, 136, 83, 136, 107, 108, 136, + /* 840 */ 110, 136, 112, 113, 114, 136, 73, 95, 96, 136, + /* 850 */ 136, 99, 100, 101, 136, 136, 126, 127, 128, 129, + /* 860 */ 136, 136, 136, 136, 136, 135, 79, 80, 81, 82, + /* 870 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 880 */ 93, 94, 95, 96, 97, 98, 136, 21, 101, 136, + /* 890 */ 103, 136, 136, 136, 107, 108, 136, 110, 136, 112, + /* 900 */ 113, 114, 2, 136, 4, 39, 6, 7, 8, 9, + /* 910 */ 10, 124, 136, 126, 127, 128, 129, 136, 18, 19, + /* 920 */ 136, 21, 135, 136, 136, 59, 136, 27, 28, 136, + /* 930 */ 30, 136, 32, 33, 136, 35, 136, 136, 136, 136, + /* 940 */ 40, 41, 42, 43, 44, 45, 46, 47, 48, 136, + /* 950 */ 50, 51, 95, 41, 42, 43, 41, 136, 58, 47, + /* 960 */ 136, 61, 62, 63, 107, 108, 66, 136, 136, 69, + /* 970 */ 113, 136, 72, 58, 62, 2, 136, 4, 63, 6, + /* 980 */ 7, 8, 9, 10, 136, 136, 71, 136, 131, 132, + /* 990 */ 136, 18, 19, 136, 21, 136, 136, 136, 136, 136, + /* 1000 */ 27, 28, 136, 30, 136, 32, 33, 136, 136, 136, + /* 1010 */ 136, 136, 136, 40, 41, 42, 43, 44, 45, 46, + /* 1020 */ 47, 48, 136, 50, 51, 136, 136, 136, 136, 136, + /* 1030 */ 136, 58, 136, 136, 61, 62, 63, 64, 136, 66, + /* 1040 */ 136, 136, 69, 136, 136, 72, 79, 80, 81, 82, + /* 1050 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 1060 */ 93, 94, 95, 96, 97, 98, 136, 136, 101, 136, + /* 1070 */ 103, 136, 136, 136, 107, 108, 136, 110, 136, 112, + /* 1080 */ 113, 114, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1090 */ 136, 136, 136, 126, 127, 128, 129, 136, 136, 136, + /* 1100 */ 136, 136, 135, 79, 80, 81, 82, 83, 84, 85, + /* 1110 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + /* 1120 */ 96, 97, 98, 136, 136, 101, 136, 103, 136, 83, + /* 1130 */ 136, 107, 108, 136, 110, 136, 112, 113, 114, 136, + /* 1140 */ 136, 95, 96, 136, 136, 99, 100, 101, 136, 136, + /* 1150 */ 126, 127, 128, 129, 136, 136, 136, 136, 136, 135, + /* 1160 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 1170 */ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + /* 1180 */ 136, 136, 101, 136, 103, 136, 136, 136, 107, 108, + /* 1190 */ 136, 110, 136, 112, 113, 114, 136, 136, 136, 136, + /* 1200 */ 136, 136, 136, 136, 136, 136, 136, 126, 127, 128, + /* 1210 */ 129, 136, 136, 136, 136, 136, 135, 79, 80, 81, + /* 1220 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + /* 1230 */ 92, 93, 94, 95, 96, 97, 98, 136, 136, 101, + /* 1240 */ 136, 103, 136, 136, 136, 107, 108, 136, 110, 136, + /* 1250 */ 112, 113, 114, 136, 136, 136, 136, 136, 136, 136, + /* 1260 */ 136, 136, 136, 136, 126, 127, 128, 129, 136, 136, + /* 1270 */ 136, 136, 136, 135, 79, 80, 81, 82, 83, 84, + /* 1280 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + /* 1290 */ 95, 96, 97, 98, 136, 136, 101, 136, 103, 136, + /* 1300 */ 136, 136, 107, 108, 136, 110, 136, 112, 113, 114, + /* 1310 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1320 */ 136, 126, 127, 128, 129, 136, 136, 136, 136, 136, + /* 1330 */ 135, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 1340 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 1350 */ 98, 136, 136, 101, 136, 103, 136, 136, 136, 107, + /* 1360 */ 108, 136, 110, 136, 112, 113, 114, 136, 136, 136, + /* 1370 */ 136, 136, 136, 136, 136, 136, 136, 136, 126, 127, + /* 1380 */ 128, 129, 136, 136, 136, 136, 136, 135, 79, 80, + /* 1390 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + /* 1400 */ 91, 92, 93, 94, 95, 96, 97, 98, 136, 136, + /* 1410 */ 101, 136, 103, 136, 136, 136, 107, 108, 136, 110, + /* 1420 */ 136, 112, 113, 114, 136, 136, 136, 136, 136, 136, + /* 1430 */ 136, 136, 136, 136, 136, 126, 127, 128, 129, 136, + /* 1440 */ 136, 136, 136, 136, 135, 79, 80, 81, 82, 83, + /* 1450 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 1460 */ 94, 95, 96, 97, 98, 136, 136, 101, 136, 103, + /* 1470 */ 136, 136, 136, 107, 108, 136, 110, 136, 112, 113, + /* 1480 */ 114, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1490 */ 136, 136, 126, 127, 128, 129, 136, 136, 136, 136, + /* 1500 */ 136, 135, 79, 80, 81, 82, 83, 84, 85, 86, + /* 1510 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 1520 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 1530 */ 107, 108, 136, 110, 136, 112, 113, 114, 136, 136, + /* 1540 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 126, + /* 1550 */ 127, 128, 129, 136, 136, 136, 136, 136, 135, 79, + /* 1560 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 1570 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 136, + /* 1580 */ 136, 101, 136, 103, 136, 136, 136, 107, 108, 136, + /* 1590 */ 110, 136, 112, 113, 114, 136, 136, 136, 136, 136, + /* 1600 */ 136, 136, 136, 136, 136, 136, 126, 127, 128, 129, + /* 1610 */ 136, 136, 136, 136, 136, 135, 79, 80, 81, 82, + /* 1620 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 1630 */ 93, 94, 95, 96, 97, 98, 136, 136, 101, 136, + /* 1640 */ 103, 136, 136, 136, 107, 108, 136, 110, 136, 112, + /* 1650 */ 113, 114, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1660 */ 136, 136, 136, 126, 127, 128, 129, 136, 136, 136, + /* 1670 */ 136, 136, 135, 79, 80, 81, 82, 83, 84, 85, + /* 1680 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + /* 1690 */ 96, 97, 98, 136, 136, 101, 136, 103, 136, 136, + /* 1700 */ 136, 107, 108, 136, 110, 136, 112, 113, 114, 136, + /* 1710 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1720 */ 126, 127, 128, 129, 136, 136, 136, 136, 136, 135, + /* 1730 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 1740 */ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + /* 1750 */ 136, 136, 101, 136, 103, 136, 136, 136, 107, 108, + /* 1760 */ 136, 110, 136, 112, 113, 114, 136, 136, 136, 136, + /* 1770 */ 136, 136, 136, 136, 136, 136, 136, 126, 127, 128, + /* 1780 */ 129, 136, 136, 136, 136, 136, 135, 79, 80, 81, + /* 1790 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + /* 1800 */ 92, 93, 94, 95, 96, 97, 98, 136, 136, 101, + /* 1810 */ 136, 103, 136, 136, 136, 107, 108, 136, 110, 136, + /* 1820 */ 112, 113, 114, 136, 136, 136, 136, 136, 136, 136, + /* 1830 */ 136, 136, 136, 136, 126, 127, 128, 129, 136, 136, + /* 1840 */ 136, 136, 136, 135, 79, 80, 81, 82, 83, 84, + /* 1850 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + /* 1860 */ 95, 96, 97, 98, 136, 136, 101, 136, 103, 136, + /* 1870 */ 136, 136, 107, 108, 136, 110, 136, 112, 113, 114, + /* 1880 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 1890 */ 136, 126, 127, 128, 129, 136, 136, 136, 136, 136, + /* 1900 */ 135, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 1910 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 1920 */ 98, 136, 136, 101, 136, 103, 136, 136, 136, 107, + /* 1930 */ 108, 136, 110, 136, 112, 113, 114, 136, 136, 136, + /* 1940 */ 136, 136, 136, 136, 136, 136, 136, 136, 126, 127, + /* 1950 */ 128, 129, 136, 136, 136, 136, 136, 135, 79, 80, + /* 1960 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + /* 1970 */ 91, 92, 93, 94, 95, 96, 97, 98, 136, 136, + /* 1980 */ 101, 136, 103, 136, 136, 136, 107, 108, 136, 110, + /* 1990 */ 136, 112, 113, 114, 136, 136, 136, 136, 136, 136, + /* 2000 */ 136, 136, 136, 136, 136, 126, 127, 128, 129, 136, + /* 2010 */ 136, 136, 136, 136, 135, 79, 80, 81, 82, 83, + /* 2020 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 2030 */ 94, 95, 96, 97, 98, 136, 136, 101, 136, 103, + /* 2040 */ 136, 136, 136, 107, 108, 136, 110, 136, 112, 113, + /* 2050 */ 114, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 2060 */ 136, 136, 126, 127, 128, 129, 136, 136, 136, 136, + /* 2070 */ 136, 135, 79, 80, 81, 82, 83, 84, 85, 86, + /* 2080 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 2090 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 2100 */ 107, 108, 136, 110, 136, 112, 113, 114, 136, 136, + /* 2110 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 126, + /* 2120 */ 127, 128, 129, 136, 136, 136, 136, 136, 135, 79, + /* 2130 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 2140 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 136, + /* 2150 */ 136, 101, 136, 103, 136, 136, 136, 107, 108, 136, + /* 2160 */ 110, 136, 112, 113, 114, 136, 136, 136, 136, 136, + /* 2170 */ 136, 136, 136, 136, 136, 136, 126, 127, 128, 129, + /* 2180 */ 136, 136, 136, 136, 136, 135, 79, 80, 81, 82, + /* 2190 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 2200 */ 93, 94, 95, 96, 97, 98, 136, 136, 101, 136, + /* 2210 */ 103, 136, 136, 136, 107, 108, 136, 110, 136, 112, + /* 2220 */ 113, 114, 136, 136, 136, 136, 136, 136, 136, 136, + /* 2230 */ 136, 136, 136, 126, 127, 128, 129, 136, 136, 136, + /* 2240 */ 136, 136, 135, 79, 80, 81, 82, 83, 84, 85, + /* 2250 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + /* 2260 */ 96, 97, 98, 136, 136, 101, 136, 103, 136, 136, + /* 2270 */ 136, 107, 108, 136, 110, 136, 112, 113, 114, 136, + /* 2280 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 2290 */ 126, 127, 128, 129, 136, 136, 136, 136, 136, 135, + /* 2300 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 2310 */ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + /* 2320 */ 136, 136, 101, 136, 103, 136, 136, 136, 107, 108, + /* 2330 */ 136, 110, 136, 112, 113, 114, 136, 136, 136, 136, + /* 2340 */ 136, 136, 136, 136, 136, 136, 136, 126, 127, 128, + /* 2350 */ 129, 136, 136, 136, 136, 136, 135, 79, 80, 81, + /* 2360 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + /* 2370 */ 92, 93, 94, 95, 96, 97, 98, 136, 136, 101, + /* 2380 */ 136, 103, 136, 136, 136, 107, 108, 136, 110, 136, + /* 2390 */ 112, 113, 114, 136, 136, 136, 136, 136, 136, 136, + /* 2400 */ 136, 136, 136, 136, 126, 127, 128, 129, 136, 136, + /* 2410 */ 136, 136, 136, 135, 79, 80, 81, 82, 83, 84, + /* 2420 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + /* 2430 */ 95, 96, 97, 98, 136, 136, 101, 136, 103, 136, + /* 2440 */ 136, 136, 107, 108, 136, 110, 136, 112, 113, 114, + /* 2450 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 2460 */ 136, 126, 127, 128, 129, 136, 136, 136, 136, 136, + /* 2470 */ 135, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 2480 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + /* 2490 */ 98, 136, 136, 101, 136, 103, 136, 136, 136, 107, + /* 2500 */ 108, 136, 110, 136, 112, 113, 114, 136, 136, 136, + /* 2510 */ 136, 136, 136, 136, 136, 136, 136, 136, 126, 127, + /* 2520 */ 128, 129, 136, 136, 136, 136, 136, 135, 79, 80, + /* 2530 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + /* 2540 */ 91, 92, 93, 94, 95, 96, 97, 98, 136, 136, + /* 2550 */ 101, 136, 103, 136, 136, 136, 107, 108, 136, 110, + /* 2560 */ 136, 112, 113, 114, 136, 136, 136, 136, 136, 136, + /* 2570 */ 136, 136, 136, 136, 136, 126, 127, 128, 129, 136, + /* 2580 */ 136, 136, 136, 136, 135, 79, 80, 81, 82, 83, + /* 2590 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 2600 */ 94, 95, 96, 97, 98, 136, 136, 101, 136, 103, + /* 2610 */ 136, 136, 136, 107, 108, 136, 110, 136, 112, 113, + /* 2620 */ 114, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 2630 */ 136, 136, 126, 127, 128, 129, 136, 136, 136, 136, + /* 2640 */ 136, 135, 79, 80, 81, 82, 83, 84, 85, 86, + /* 2650 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 2660 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 2670 */ 107, 108, 136, 110, 136, 112, 113, 114, 2, 136, + /* 2680 */ 4, 136, 6, 7, 8, 9, 10, 136, 136, 126, + /* 2690 */ 127, 128, 129, 136, 18, 19, 136, 21, 135, 136, + /* 2700 */ 136, 136, 136, 27, 28, 136, 30, 136, 32, 33, + /* 2710 */ 136, 136, 136, 136, 136, 136, 40, 41, 42, 43, + /* 2720 */ 44, 45, 46, 47, 48, 136, 50, 51, 136, 136, + /* 2730 */ 136, 136, 136, 136, 58, 136, 136, 61, 62, 63, + /* 2740 */ 136, 136, 66, 136, 136, 69, 136, 136, 72, 136, + /* 2750 */ 136, 2, 136, 4, 136, 6, 7, 8, 9, 10, + /* 2760 */ 136, 136, 136, 136, 136, 136, 136, 18, 19, 136, + /* 2770 */ 21, 136, 136, 136, 136, 136, 27, 28, 136, 30, + /* 2780 */ 136, 32, 33, 136, 136, 136, 136, 136, 136, 40, + /* 2790 */ 41, 42, 43, 44, 45, 46, 47, 48, 136, 50, + /* 2800 */ 51, 136, 136, 136, 136, 136, 136, 58, 136, 136, + /* 2810 */ 61, 62, 63, 136, 136, 66, 136, 136, 69, 136, + /* 2820 */ 136, 72, 79, 80, 81, 82, 83, 84, 85, 86, + /* 2830 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 2840 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 2850 */ 107, 108, 136, 110, 136, 112, 113, 114, 2, 136, + /* 2860 */ 4, 136, 6, 7, 8, 9, 10, 136, 136, 126, + /* 2870 */ 127, 128, 129, 136, 18, 19, 136, 21, 135, 136, + /* 2880 */ 136, 136, 136, 27, 28, 136, 30, 136, 32, 33, + /* 2890 */ 136, 136, 136, 136, 136, 136, 40, 41, 42, 43, + /* 2900 */ 44, 45, 46, 47, 48, 136, 50, 51, 136, 136, + /* 2910 */ 136, 136, 136, 136, 58, 136, 136, 61, 62, 63, + /* 2920 */ 136, 136, 66, 136, 136, 69, 136, 136, 72, 136, + /* 2930 */ 136, 2, 136, 4, 136, 6, 7, 8, 9, 10, + /* 2940 */ 136, 136, 136, 136, 136, 136, 136, 18, 19, 136, + /* 2950 */ 21, 136, 136, 136, 136, 136, 27, 28, 136, 30, + /* 2960 */ 136, 32, 33, 136, 136, 136, 136, 136, 136, 40, + /* 2970 */ 41, 42, 43, 44, 45, 46, 47, 48, 136, 50, + /* 2980 */ 51, 136, 136, 136, 136, 136, 136, 58, 136, 136, + /* 2990 */ 61, 62, 63, 136, 136, 66, 136, 136, 69, 136, + /* 3000 */ 136, 72, 79, 80, 81, 82, 83, 84, 85, 86, + /* 3010 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 3020 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 3030 */ 107, 108, 136, 110, 136, 112, 113, 114, 136, 136, + /* 3040 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 126, + /* 3050 */ 127, 128, 129, 136, 136, 136, 136, 136, 135, 79, + /* 3060 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 3070 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 136, + /* 3080 */ 136, 101, 136, 103, 136, 136, 136, 107, 108, 136, + /* 3090 */ 110, 136, 112, 113, 114, 2, 136, 4, 136, 6, + /* 3100 */ 7, 8, 9, 10, 136, 136, 126, 127, 128, 129, + /* 3110 */ 136, 18, 19, 136, 21, 135, 136, 136, 136, 136, + /* 3120 */ 27, 28, 136, 30, 136, 32, 33, 136, 136, 136, + /* 3130 */ 136, 136, 136, 40, 41, 42, 43, 44, 45, 46, + /* 3140 */ 47, 48, 136, 50, 51, 136, 136, 136, 136, 136, + /* 3150 */ 136, 58, 136, 136, 61, 62, 63, 136, 136, 66, + /* 3160 */ 136, 136, 69, 136, 136, 72, 136, 136, 2, 136, + /* 3170 */ 4, 136, 6, 7, 8, 9, 10, 136, 136, 136, + /* 3180 */ 136, 136, 136, 136, 18, 19, 136, 136, 22, 136, + /* 3190 */ 136, 136, 136, 27, 28, 136, 30, 136, 32, 33, + /* 3200 */ 136, 136, 136, 136, 136, 136, 40, 41, 42, 43, + /* 3210 */ 44, 45, 46, 47, 48, 136, 50, 51, 136, 136, + /* 3220 */ 136, 136, 136, 136, 58, 136, 136, 61, 62, 63, + /* 3230 */ 136, 136, 66, 136, 136, 69, 136, 136, 72, 136, + /* 3240 */ 136, 2, 136, 4, 136, 6, 7, 8, 9, 10, + /* 3250 */ 136, 136, 136, 136, 136, 136, 136, 18, 19, 136, + /* 3260 */ 21, 136, 136, 136, 136, 136, 27, 28, 136, 30, + /* 3270 */ 136, 32, 33, 136, 136, 136, 136, 136, 136, 40, + /* 3280 */ 41, 42, 43, 44, 45, 46, 47, 48, 136, 50, + /* 3290 */ 51, 136, 136, 136, 136, 136, 136, 58, 136, 136, + /* 3300 */ 61, 62, 63, 136, 136, 66, 136, 136, 69, 136, + /* 3310 */ 136, 72, 79, 80, 81, 82, 83, 84, 85, 86, + /* 3320 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 3330 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 3340 */ 107, 108, 136, 110, 136, 112, 113, 114, 136, 136, + /* 3350 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 126, + /* 3360 */ 127, 128, 129, 136, 136, 136, 136, 136, 135, 79, + /* 3370 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 3380 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 136, + /* 3390 */ 136, 101, 136, 103, 136, 136, 136, 107, 108, 136, + /* 3400 */ 110, 136, 112, 113, 114, 136, 136, 136, 136, 136, + /* 3410 */ 136, 136, 136, 136, 136, 136, 126, 127, 128, 129, + /* 3420 */ 136, 136, 136, 136, 136, 135, 79, 80, 81, 82, + /* 3430 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 3440 */ 93, 94, 95, 96, 97, 98, 136, 136, 101, 136, + /* 3450 */ 103, 136, 136, 136, 107, 108, 136, 110, 136, 112, + /* 3460 */ 113, 114, 136, 136, 136, 136, 136, 136, 136, 136, + /* 3470 */ 136, 136, 136, 126, 127, 128, 129, 136, 136, 136, + /* 3480 */ 136, 136, 135, 79, 80, 81, 82, 83, 84, 85, + /* 3490 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + /* 3500 */ 96, 97, 98, 136, 136, 101, 136, 103, 136, 136, + /* 3510 */ 136, 107, 108, 136, 110, 136, 112, 113, 114, 136, + /* 3520 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 3530 */ 126, 127, 128, 129, 136, 136, 136, 136, 136, 135, + /* 3540 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 3550 */ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + /* 3560 */ 136, 136, 101, 136, 103, 136, 136, 136, 107, 108, + /* 3570 */ 136, 110, 136, 112, 113, 114, 136, 136, 136, 136, + /* 3580 */ 136, 136, 136, 136, 136, 136, 136, 126, 127, 128, + /* 3590 */ 129, 136, 136, 136, 136, 136, 135, 79, 80, 81, + /* 3600 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + /* 3610 */ 92, 93, 94, 95, 96, 97, 98, 136, 136, 101, + /* 3620 */ 136, 103, 136, 136, 136, 107, 108, 136, 110, 136, + /* 3630 */ 112, 113, 114, 2, 136, 4, 136, 6, 7, 8, + /* 3640 */ 9, 10, 136, 136, 126, 127, 128, 129, 136, 18, + /* 3650 */ 19, 136, 21, 135, 136, 136, 136, 136, 27, 28, + /* 3660 */ 136, 30, 136, 32, 33, 136, 136, 136, 136, 136, + /* 3670 */ 136, 40, 41, 42, 43, 44, 45, 46, 47, 48, + /* 3680 */ 136, 50, 51, 136, 136, 136, 136, 136, 136, 58, + /* 3690 */ 136, 136, 61, 62, 63, 136, 136, 66, 136, 136, + /* 3700 */ 69, 136, 136, 72, 136, 79, 80, 81, 82, 83, + /* 3710 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 3720 */ 94, 95, 96, 97, 98, 136, 136, 101, 136, 103, + /* 3730 */ 136, 136, 136, 107, 108, 136, 110, 136, 112, 113, + /* 3740 */ 114, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 3750 */ 136, 136, 126, 127, 128, 129, 136, 136, 136, 136, + /* 3760 */ 136, 135, 79, 80, 81, 82, 83, 84, 85, 86, + /* 3770 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + /* 3780 */ 97, 98, 136, 136, 101, 136, 103, 136, 136, 136, + /* 3790 */ 107, 108, 136, 110, 136, 112, 113, 114, 2, 136, + /* 3800 */ 4, 136, 6, 7, 8, 9, 10, 136, 136, 126, + /* 3810 */ 127, 128, 129, 136, 18, 19, 136, 136, 135, 136, + /* 3820 */ 136, 136, 136, 27, 28, 136, 30, 136, 32, 33, + /* 3830 */ 136, 136, 136, 136, 136, 136, 40, 41, 42, 43, + /* 3840 */ 44, 45, 46, 47, 48, 136, 50, 51, 136, 36, + /* 3850 */ 37, 38, 136, 136, 58, 136, 136, 61, 62, 63, + /* 3860 */ 136, 136, 66, 136, 136, 69, 136, 54, 72, 56, + /* 3870 */ 57, 2, 34, 60, 36, 37, 38, 8, 9, 10, + /* 3880 */ 136, 136, 136, 136, 136, 136, 136, 18, 19, 136, + /* 3890 */ 136, 136, 54, 136, 56, 57, 27, 28, 60, 30, + /* 3900 */ 136, 32, 33, 136, 136, 136, 136, 136, 136, 40, + /* 3910 */ 41, 42, 43, 44, 45, 46, 47, 48, 136, 50, + /* 3920 */ 51, 136, 9, 136, 136, 136, 136, 58, 136, 136, + /* 3930 */ 61, 62, 63, 20, 21, 66, 136, 136, 69, 136, + /* 3940 */ 1, 72, 136, 4, 136, 6, 7, 136, 136, 136, + /* 3950 */ 136, 136, 136, 136, 41, 42, 43, 44, 45, 46, + /* 3960 */ 136, 136, 23, 24, 25, 26, 27, 28, 29, 136, + /* 3970 */ 31, 58, 136, 136, 61, 62, 63, 136, 136, 136, + /* 3980 */ 136, 136, 69, 136, 1, 21, 136, 4, 136, 6, + /* 3990 */ 7, 136, 53, 136, 136, 136, 136, 136, 34, 136, + /* 4000 */ 36, 37, 38, 136, 65, 136, 23, 24, 25, 26, + /* 4010 */ 27, 28, 29, 136, 31, 136, 83, 136, 54, 77, + /* 4020 */ 56, 57, 136, 136, 60, 136, 84, 85, 95, 96, + /* 4030 */ 136, 136, 99, 100, 101, 136, 53, 95, 96, 97, + /* 4040 */ 98, 1, 136, 101, 4, 136, 6, 7, 65, 107, + /* 4050 */ 108, 118, 110, 136, 112, 113, 114, 136, 136, 136, + /* 4060 */ 136, 21, 136, 23, 24, 25, 26, 27, 28, 29, + /* 4070 */ 1, 31, 136, 4, 136, 6, 7, 136, 136, 136, + /* 4080 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 4090 */ 136, 22, 23, 24, 25, 26, 27, 28, 29, 1, + /* 4100 */ 31, 136, 4, 136, 6, 7, 136, 136, 136, 136, + /* 4110 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + /* 4120 */ 22, 23, 24, 25, 26, 27, 28, 29, 1, 31, + /* 4130 */ 136, 4, 136, 6, 7, 136, 136, 136, 136, 136, + /* 4140 */ 136, 136, 136, 136, 136, 136, 136, 136, 84, 85, + /* 4150 */ 23, 24, 25, 26, 27, 28, 29, 136, 31, 95, + /* 4160 */ 96, 97, 98, 136, 136, 101, 136, 136, 136, 136, + /* 4170 */ 136, 107, 108, 136, 110, 136, 112, 113, 114, 136, + /* 4180 */ 53, 136, 1, 136, 136, 4, 136, 6, 7, 136, + /* 4190 */ 136, 136, 136, 136, 136, 9, 136, 136, 136, 136, + /* 4200 */ 136, 136, 21, 136, 23, 24, 25, 26, 27, 28, + /* 4210 */ 29, 1, 31, 136, 4, 136, 6, 7, 136, 136, + /* 4220 */ 136, 136, 136, 136, 136, 136, 136, 41, 42, 43, + /* 4230 */ 44, 45, 46, 23, 24, 25, 26, 27, 28, 29, + /* 4240 */ 1, 31, 136, 4, 58, 6, 7, 61, 62, 63, + /* 4250 */ 136, 136, 136, 136, 136, 69, 136, 136, 136, 136, + /* 4260 */ 136, 22, 23, 24, 25, 26, 27, 28, 29, 136, + /* 4270 */ 31, 136, 84, 85, 64, 136, 136, 136, 136, 136, + /* 4280 */ 136, 136, 136, 95, 96, 97, 98, 136, 136, 101, + /* 4290 */ 136, 136, 84, 85, 136, 107, 108, 136, 110, 136, + /* 4300 */ 112, 113, 114, 95, 96, 97, 98, 136, 34, 101, + /* 4310 */ 36, 37, 38, 136, 136, 107, 108, 136, 110, 136, + /* 4320 */ 112, 113, 114, 136, 84, 85, 136, 136, 54, 136, + /* 4330 */ 56, 57, 136, 136, 60, 95, 96, 97, 98, 1, + /* 4340 */ 136, 101, 4, 136, 6, 7, 136, 107, 108, 136, + /* 4350 */ 110, 136, 112, 113, 114, 136, 136, 136, 136, 136, + /* 4360 */ 136, 23, 24, 25, 26, 27, 28, 29, 4, 31, + /* 4370 */ 6, 7, 136, 136, 136, 136, 136, 136, 14, 136, + /* 4380 */ 136, 136, 136, 136, 136, 136, 136, 23, 24, 25, + /* 4390 */ 26, 27, 28, 29, 4, 31, 6, 7, 136, 136, + /* 4400 */ 136, 136, 136, 136, 14, 136, 136, 136, 136, 4, + /* 4410 */ 136, 6, 7, 23, 24, 25, 26, 27, 28, 29, + /* 4420 */ 136, 31, 136, 136, 136, 136, 136, 136, 23, 24, + /* 4430 */ 25, 26, 27, 28, 29, 136, 31, 20, 21, 136, + /* 4440 */ 136, 136, 136, 136, 136, 83, 136, 136, 136, 136, + /* 4450 */ 136, 34, 136, 36, 37, 38, 136, 95, 96, 136, + /* 4460 */ 136, 99, 100, 101, 136, 136, 136, 136, 136, 136, + /* 4470 */ 136, 54, 136, 56, 57, 136, 136, 60, 136, 136, + /* 4480 */ 118, +); + const YY_SHIFT_USE_DFLT = -27; + const YY_SHIFT_MAX = 186; + static public $yy_shift_ofst = array( + /* 0 */ 2676, 676, 973, 900, 973, 3093, 3093, 3166, 3239, 3796, + /* 10 */ 3796, 3796, 2676, 3796, 3796, 2749, 2929, 2856, 3631, 3796, + /* 20 */ 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, + /* 30 */ 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, + /* 40 */ 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, 3796, + /* 50 */ 3796, 3796, 3796, 3796, 3869, 3913, 4186, 4186, 4186, 4186, + /* 60 */ 912, 912, 328, 912, 912, 328, 915, 100, 3939, 3983, + /* 70 */ 4040, 4040, 3964, 3964, 100, 4239, 4069, 4210, 4098, 4181, + /* 80 */ 4127, 4338, 4338, 4338, 4338, 4338, 4338, 4390, 4338, 4338, + /* 90 */ 4364, 4338, 4405, 4405, 4405, 17, 417, 589, 474, 532, + /* 100 */ 532, 532, 3838, 532, 532, 3838, 532, 532, 532, 73, + /* 110 */ 3813, 3813, 187, 242, 85, 80, 80, -2, -2, -2, + /* 120 */ -2, 366, 366, 319, 319, 4417, 2, 773, 2, 33, + /* 130 */ 200, 234, 158, 71, -26, 339, 52, 52, 61, 61, + /* 140 */ 374, 91, 339, 339, 374, 374, 52, 374, 52, 61, + /* 150 */ 52, 61, 61, 61, 61, 61, 52, 91, 61, 61, + /* 160 */ 4274, 4274, 295, 648, 580, 866, 750, 418, 465, 305, + /* 170 */ 112, 18, 303, 92, 189, 93, 289, 327, 208, 240, + /* 180 */ 312, 275, 277, 220, 261, 313, 306, +); + const YY_REDUCE_USE_DFLT = -80; + const YY_REDUCE_MAX = 159; + static public $yy_reduce_ofst = array( + /* 0 */ -75, 267, 210, -18, 39, 153, 96, 563, 382, 497, + /* 10 */ 439, 324, 672, 730, 787, 2743, 3290, 3233, 3518, 3404, + /* 20 */ 3347, 3683, 3626, 2107, 1366, 1024, 1594, 1423, 1309, 1252, + /* 30 */ 1138, 1195, 2449, 2221, 2278, 2335, 1708, 2050, 1765, 1879, + /* 40 */ 1993, 1936, 1822, 2392, 2164, 1651, 967, 1480, 1537, 1081, + /* 50 */ 3461, 2506, 2563, 2923, 2980, 3942, 4188, 4208, 4240, 4064, + /* 60 */ 4362, 3933, 686, 752, 1046, 49, 857, 64, 585, 618, + /* 70 */ 149, 206, 586, 519, 177, -79, -79, -79, -79, -79, + /* 80 */ -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + /* 90 */ -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + /* 100 */ -79, -79, 617, -79, -79, 518, -79, -79, -79, -79, + /* 110 */ 617, 518, -79, -79, -79, 72, 72, -79, -79, -79, + /* 120 */ -79, -79, -79, 119, 124, 321, 286, 266, 309, 266, + /* 130 */ 322, 310, 258, 257, 273, 252, 283, 248, 308, 346, + /* 140 */ 387, 380, 329, 315, 325, 350, 360, 352, 333, 404, + /* 150 */ 248, 143, 150, 152, 130, -43, 276, 69, 182, 253, +); + static public $yyExpectedTokens = array( + /* 0 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 1 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 53, 58, 61, 62, 63, 65, 66, 69, 72, ), + /* 2 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 64, 66, 69, 72, ), + /* 3 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 35, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 4 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 64, 66, 69, 72, ), + /* 5 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 6 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 7 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 22, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 8 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 9 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 10 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 11 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 12 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 13 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 14 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 15 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 16 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 17 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 18 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 21, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 19 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 20 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 21 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 22 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 23 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 24 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 25 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 26 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 27 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 28 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 29 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 30 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 31 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 32 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 33 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 34 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 35 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 36 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 37 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 38 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 39 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 40 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 41 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 42 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 43 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 44 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 45 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 46 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 47 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 48 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 49 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 50 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 51 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 52 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 53 */ array(2, 4, 6, 7, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 54 */ array(2, 8, 9, 10, 18, 19, 27, 28, 30, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 58, 61, 62, 63, 66, 69, 72, ), + /* 55 */ array(9, 20, 21, 41, 42, 43, 44, 45, 46, 58, 61, 62, 63, 69, ), + /* 56 */ array(9, 41, 42, 43, 44, 45, 46, 58, 61, 62, 63, 69, ), + /* 57 */ array(9, 41, 42, 43, 44, 45, 46, 58, 61, 62, 63, 69, ), + /* 58 */ array(9, 41, 42, 43, 44, 45, 46, 58, 61, 62, 63, 69, ), + /* 59 */ array(9, 41, 42, 43, 44, 45, 46, 58, 61, 62, 63, 69, ), + /* 60 */ array(41, 42, 43, 47, 62, ), + /* 61 */ array(41, 42, 43, 47, 62, ), + /* 62 */ array(41, 58, 62, 63, ), + /* 63 */ array(41, 42, 43, 47, 62, ), + /* 64 */ array(41, 42, 43, 47, 62, ), + /* 65 */ array(41, 58, 62, 63, ), + /* 66 */ array(41, 58, 63, 71, ), + /* 67 */ array(41, 58, 63, ), + /* 68 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, 53, 65, ), + /* 69 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, 53, 65, ), + /* 70 */ array(1, 4, 6, 7, 21, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 71 */ array(1, 4, 6, 7, 21, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 72 */ array(21, 34, 36, 37, 38, 54, 56, 57, 60, ), + /* 73 */ array(21, 34, 36, 37, 38, 54, 56, 57, 60, ), + /* 74 */ array(41, 58, 63, ), + /* 75 */ array(1, 4, 6, 7, 22, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 76 */ array(1, 4, 6, 7, 22, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 77 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, 64, ), + /* 78 */ array(1, 4, 6, 7, 22, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 79 */ array(1, 4, 6, 7, 21, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 80 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, 53, ), + /* 81 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 82 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 83 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 84 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 85 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 86 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 87 */ array(4, 6, 7, 14, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 88 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 89 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 90 */ array(4, 6, 7, 14, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 91 */ array(1, 4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 92 */ array(4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 93 */ array(4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 94 */ array(4, 6, 7, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 95 */ array(13, 14, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 96 */ array(13, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 97 */ array(14, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 98 */ array(14, 23, 24, 25, 26, 27, 28, 29, 31, ), + /* 99 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 100 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 101 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 102 */ array(34, 36, 37, 38, 54, 56, 57, 60, ), + /* 103 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 104 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 105 */ array(34, 36, 37, 38, 54, 56, 57, 60, ), + /* 106 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 107 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 108 */ array(23, 24, 25, 26, 27, 28, 29, 31, ), + /* 109 */ array(24, 25, 26, 27, 28, 29, 31, ), + /* 110 */ array(36, 37, 38, 54, 56, 57, 60, ), + /* 111 */ array(36, 37, 38, 54, 56, 57, 60, ), + /* 112 */ array(25, 26, 27, 28, 29, 31, ), + /* 113 */ array(26, 27, 28, 29, 31, ), + /* 114 */ array(27, 28, 29, 31, ), + /* 115 */ array(1, 4, 6, 7, ), + /* 116 */ array(1, 4, 6, 7, ), + /* 117 */ array(29, 31, ), + /* 118 */ array(29, 31, ), + /* 119 */ array(29, 31, ), + /* 120 */ array(29, 31, ), + /* 121 */ array(31, ), + /* 122 */ array(31, ), + /* 123 */ array(73, ), + /* 124 */ array(73, ), + /* 125 */ array(20, 21, 34, 36, 37, 38, 54, 56, 57, 60, ), + /* 126 */ array(54, 56, 57, ), + /* 127 */ array(3, 22, 73, ), + /* 128 */ array(54, 56, 57, ), + /* 129 */ array(3, 22, 73, ), + /* 130 */ array(2, 21, ), + /* 131 */ array(21, 52, ), + /* 132 */ array(11, 12, ), + /* 133 */ array(67, 68, ), + /* 134 */ array(50, 51, ), + /* 135 */ array(34, ), + /* 136 */ array(41, ), + /* 137 */ array(41, ), + /* 138 */ array(21, ), + /* 139 */ array(21, ), + /* 140 */ array(52, ), + /* 141 */ array(52, ), + /* 142 */ array(34, ), + /* 143 */ array(34, ), + /* 144 */ array(52, ), + /* 145 */ array(52, ), + /* 146 */ array(41, ), + /* 147 */ array(52, ), + /* 148 */ array(41, ), + /* 149 */ array(21, ), + /* 150 */ array(41, ), + /* 151 */ array(21, ), + /* 152 */ array(21, ), + /* 153 */ array(21, ), + /* 154 */ array(21, ), + /* 155 */ array(21, ), + /* 156 */ array(41, ), + /* 157 */ array(52, ), + /* 158 */ array(21, ), + /* 159 */ array(21, ), + /* 160 */ array(34, 36, 37, 38, 54, 56, 57, 60, ), + /* 161 */ array(34, 36, 37, 38, 54, 56, 57, 60, ), + /* 162 */ array(17, 20, 32, 33, ), + /* 163 */ array(21, 39, 52, 64, ), + /* 164 */ array(21, 22, 39, ), + /* 165 */ array(21, 39, 59, ), + /* 166 */ array(21, 22, 39, ), + /* 167 */ array(21, 39, 64, ), + /* 168 */ array(21, 22, 39, ), + /* 169 */ array(21, 35, 39, ), + /* 170 */ array(49, 52, ), + /* 171 */ array(39, 70, ), + /* 172 */ array(22, 39, ), + /* 173 */ array(15, 53, ), + /* 174 */ array(22, 39, ), + /* 175 */ array(22, ), + /* 176 */ array(52, ), + /* 177 */ array(39, ), + /* 178 */ array(22, ), + /* 179 */ array(70, ), + /* 180 */ array(55, ), + /* 181 */ array(39, ), + /* 182 */ array(39, ), + /* 183 */ array(67, ), + /* 184 */ array(3, ), + /* 185 */ array(16, ), + /* 186 */ array(15, ), + /* 187 */ array(), + /* 188 */ array(), + /* 189 */ array(), + /* 190 */ array(), + /* 191 */ array(), + /* 192 */ array(), + /* 193 */ array(), + /* 194 */ array(), + /* 195 */ array(), + /* 196 */ array(), + /* 197 */ array(), + /* 198 */ array(), + /* 199 */ array(), + /* 200 */ array(), + /* 201 */ array(), + /* 202 */ array(), + /* 203 */ array(), + /* 204 */ array(), + /* 205 */ array(), + /* 206 */ array(), + /* 207 */ array(), + /* 208 */ array(), + /* 209 */ array(), + /* 210 */ array(), + /* 211 */ array(), + /* 212 */ array(), + /* 213 */ array(), + /* 214 */ array(), + /* 215 */ array(), + /* 216 */ array(), + /* 217 */ array(), + /* 218 */ array(), + /* 219 */ array(), + /* 220 */ array(), + /* 221 */ array(), + /* 222 */ array(), + /* 223 */ array(), + /* 224 */ array(), + /* 225 */ array(), + /* 226 */ array(), + /* 227 */ array(), + /* 228 */ array(), + /* 229 */ array(), + /* 230 */ array(), + /* 231 */ array(), + /* 232 */ array(), + /* 233 */ array(), + /* 234 */ array(), + /* 235 */ array(), + /* 236 */ array(), + /* 237 */ array(), + /* 238 */ array(), + /* 239 */ array(), + /* 240 */ array(), + /* 241 */ array(), + /* 242 */ array(), + /* 243 */ array(), + /* 244 */ array(), + /* 245 */ array(), + /* 246 */ array(), + /* 247 */ array(), + /* 248 */ array(), + /* 249 */ array(), + /* 250 */ array(), + /* 251 */ array(), + /* 252 */ array(), + /* 253 */ array(), + /* 254 */ array(), + /* 255 */ array(), + /* 256 */ array(), + /* 257 */ array(), + /* 258 */ array(), + /* 259 */ array(), + /* 260 */ array(), + /* 261 */ array(), + /* 262 */ array(), + /* 263 */ array(), + /* 264 */ array(), + /* 265 */ array(), + /* 266 */ array(), + /* 267 */ array(), + /* 268 */ array(), + /* 269 */ array(), + /* 270 */ array(), + /* 271 */ array(), + /* 272 */ array(), + /* 273 */ array(), + /* 274 */ array(), + /* 275 */ array(), + /* 276 */ array(), + /* 277 */ array(), + /* 278 */ array(), + /* 279 */ array(), + /* 280 */ array(), + /* 281 */ array(), + /* 282 */ array(), + /* 283 */ array(), + /* 284 */ array(), + /* 285 */ array(), + /* 286 */ array(), + /* 287 */ array(), + /* 288 */ array(), + /* 289 */ array(), + /* 290 */ array(), + /* 291 */ array(), + /* 292 */ array(), + /* 293 */ array(), + /* 294 */ array(), + /* 295 */ array(), + /* 296 */ array(), + /* 297 */ array(), + /* 298 */ array(), + /* 299 */ array(), + /* 300 */ array(), + /* 301 */ array(), + /* 302 */ array(), + /* 303 */ array(), + /* 304 */ array(), + /* 305 */ array(), + /* 306 */ array(), + /* 307 */ array(), + /* 308 */ array(), + /* 309 */ array(), + /* 310 */ array(), + /* 311 */ array(), + /* 312 */ array(), + /* 313 */ array(), +); + static public $yy_default = array( + /* 0 */ 314, 508, 508, 508, 508, 508, 508, 508, 508, 508, + /* 10 */ 508, 363, 508, 319, 508, 508, 508, 508, 508, 508, + /* 20 */ 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + /* 30 */ 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + /* 40 */ 508, 508, 508, 508, 508, 508, 508, 428, 508, 508, + /* 50 */ 508, 508, 508, 508, 356, 403, 508, 508, 508, 508, + /* 60 */ 398, 398, 364, 508, 363, 508, 508, 508, 435, 395, + /* 70 */ 508, 508, 405, 409, 508, 508, 508, 508, 508, 508, + /* 80 */ 435, 438, 488, 369, 489, 427, 349, 449, 320, 429, + /* 90 */ 447, 437, 448, 450, 456, 469, 471, 473, 470, 475, + /* 100 */ 355, 346, 326, 472, 507, 327, 505, 474, 444, 503, + /* 110 */ 415, 415, 502, 504, 501, 321, 508, 499, 492, 498, + /* 120 */ 491, 500, 490, 508, 508, 407, 508, 508, 508, 508, + /* 130 */ 508, 508, 508, 439, 508, 508, 508, 508, 508, 508, + /* 140 */ 362, 362, 508, 413, 362, 362, 390, 362, 508, 508, + /* 150 */ 420, 508, 508, 508, 508, 508, 508, 362, 508, 508, + /* 160 */ 494, 493, 379, 425, 508, 508, 508, 508, 508, 508, + /* 170 */ 508, 508, 508, 367, 508, 508, 467, 482, 508, 508, + /* 180 */ 508, 508, 315, 440, 486, 348, 382, 337, 466, 358, + /* 190 */ 396, 316, 406, 397, 425, 351, 352, 506, 402, 353, + /* 200 */ 350, 460, 400, 347, 401, 417, 371, 373, 468, 372, + /* 210 */ 464, 318, 399, 368, 465, 366, 354, 462, 463, 365, + /* 220 */ 370, 418, 392, 324, 457, 359, 360, 361, 452, 338, + /* 230 */ 461, 357, 387, 317, 375, 378, 383, 384, 385, 386, + /* 240 */ 381, 380, 495, 496, 339, 458, 453, 329, 330, 331, + /* 250 */ 332, 328, 412, 389, 377, 393, 394, 333, 334, 343, + /* 260 */ 344, 345, 388, 342, 341, 335, 336, 340, 411, 416, + /* 270 */ 480, 478, 479, 455, 483, 487, 481, 391, 484, 485, + /* 280 */ 422, 323, 432, 430, 434, 433, 322, 423, 374, 431, + /* 290 */ 436, 477, 476, 419, 421, 424, 426, 414, 382, 408, + /* 300 */ 410, 379, 442, 441, 451, 454, 325, 459, 446, 445, + /* 310 */ 443, 497, 376, 404, +); +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ + const YYNOCODE = 137; + const YYSTACKDEPTH = 100; + const YYNSTATE = 314; + const YYNRULE = 194; + const YYERRORSYMBOL = 74; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 0; + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = ''; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx = -1; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + static public $yyTokenName = array( + '$', 'YY_POST_IF', 'YY_IF', 'YY_ELSE', + 'YY_FOR', 'YY_DO', 'YY_WHILE', 'YY_UNTIL', + 'YY_LOOP', 'YY_SUPER', 'YY_CLASS', 'YY_FORIN', + 'YY_FOROF', 'YY_BY', 'YY_WHEN', 'YY_EQUALS', + 'YY_COLON', 'YY_COMPOUND_ASSIGN', 'YY_RETURN', 'YY_THROW', + 'YY_EXTENDS', 'YY_INDENT', 'YY_OUTDENT', 'YY_LOGIC', + 'YY_COMPARE', 'YY_RELATION', 'YY_SHIFT', 'YY_PLUS', + 'YY_MINUS', 'YY_MATH', 'YY_UNARY', 'YY_EXISTENTIAL', + 'YY_INCREMENT', 'YY_DECREMENT', 'YY_CALL_START', 'YY_CALL_END', + 'YY_ACCESSOR', 'YY_EXISTENTIAL_ACCESSOR', 'YY_PROTOTYPE', 'YY_TERMINATOR', + 'YY_STATEMENT', 'YY_IDENTIFIER', 'YY_NUMBER', 'YY_STRING', + 'YY_JS', 'YY_REGEX', 'YY_BOOL', 'YY_HERECOMMENT', + 'YY_PARAM_START', 'YY_PARAM_END', 'YY_FUNC', 'YY_BOUND_FUNC', + 'YY_COMMA', 'YY_RANGE_EXCLUSIVE', 'YY_INDEX_START', 'YY_INDEX_END', + 'YY_INDEX_SOAK', 'YY_INDEX_PROTO', 'YY_OBJECT_START', 'YY_OBJECT_END', + 'YY_FUNC_EXIST', 'YY_THIS', 'YY_AT_SIGN', 'YY_ARRAY_START', + 'YY_ARRAY_END', 'YY_RANGE_INCLUSIVE', 'YY_TRY', 'YY_FINALLY', + 'YY_CATCH', 'YY_PAREN_START', 'YY_PAREN_END', 'YY_OWN', + 'YY_SWITCH', 'YY_LEADING_WHEN', 'error', 'root', + 'body', 'block', 'line', 'expression', + 'statement', 'return', 'throw', 'comment', + 'value', 'invocation', 'code', 'operation', + 'assign', 'if', 'try', 'while', + 'for', 'switch', 'class', 'identifier', + 'alphanumeric', 'literal', 'assignable', 'assignObj', + 'objAssignable', 'thisProperty', 'paramList', 'funcGlyph', + 'optComma', 'param', 'paramVar', 'array', + 'object', 'splat', 'simpleAssignable', 'accessor', + 'parenthetical', 'range', 'this', 'index', + 'indexValue', 'slice', 'assignList', 'optFuncExist', + 'arguments', 'argList', 'rangeDots', 'arg', + 'simpleArgs', 'catch', 'whileSource', 'loop', + 'forBody', 'forStart', 'forSource', 'forVariables', + 'forValue', 'whens', 'when', 'ifBlock', + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( + /* 0 */ "root ::=", + /* 1 */ "root ::= body", + /* 2 */ "root ::= block YY_TERMINATOR", + /* 3 */ "body ::= line", + /* 4 */ "body ::= body YY_TERMINATOR line", + /* 5 */ "body ::= body YY_TERMINATOR", + /* 6 */ "line ::= expression", + /* 7 */ "line ::= statement", + /* 8 */ "statement ::= return", + /* 9 */ "statement ::= throw", + /* 10 */ "statement ::= comment", + /* 11 */ "statement ::= YY_STATEMENT", + /* 12 */ "expression ::= value", + /* 13 */ "expression ::= invocation", + /* 14 */ "expression ::= code", + /* 15 */ "expression ::= operation", + /* 16 */ "expression ::= assign", + /* 17 */ "expression ::= if", + /* 18 */ "expression ::= try", + /* 19 */ "expression ::= while", + /* 20 */ "expression ::= for", + /* 21 */ "expression ::= switch", + /* 22 */ "expression ::= class", + /* 23 */ "block ::= YY_INDENT YY_OUTDENT", + /* 24 */ "block ::= YY_INDENT body YY_OUTDENT", + /* 25 */ "identifier ::= YY_IDENTIFIER", + /* 26 */ "alphanumeric ::= YY_NUMBER", + /* 27 */ "alphanumeric ::= YY_STRING", + /* 28 */ "literal ::= alphanumeric", + /* 29 */ "literal ::= YY_JS", + /* 30 */ "literal ::= YY_REGEX", + /* 31 */ "literal ::= YY_BOOL", + /* 32 */ "assign ::= assignable YY_EQUALS expression", + /* 33 */ "assign ::= assignable YY_EQUALS YY_INDENT expression YY_OUTDENT", + /* 34 */ "assignObj ::= objAssignable", + /* 35 */ "assignObj ::= objAssignable YY_COLON expression", + /* 36 */ "assignObj ::= objAssignable YY_COLON YY_INDENT expression YY_OUTDENT", + /* 37 */ "assignObj ::= comment", + /* 38 */ "objAssignable ::= identifier", + /* 39 */ "objAssignable ::= alphanumeric", + /* 40 */ "objAssignable ::= thisProperty", + /* 41 */ "return ::= YY_RETURN expression", + /* 42 */ "return ::= YY_RETURN", + /* 43 */ "comment ::= YY_HERECOMMENT", + /* 44 */ "code ::= YY_PARAM_START paramList YY_PARAM_END funcGlyph block", + /* 45 */ "code ::= funcGlyph block", + /* 46 */ "funcGlyph ::= YY_FUNC", + /* 47 */ "funcGlyph ::= YY_BOUND_FUNC", + /* 48 */ "optComma ::=", + /* 49 */ "optComma ::= YY_COMMA", + /* 50 */ "paramList ::=", + /* 51 */ "paramList ::= param", + /* 52 */ "paramList ::= paramList YY_COMMA param", + /* 53 */ "param ::= paramVar", + /* 54 */ "param ::= paramVar YY_RANGE_EXCLUSIVE", + /* 55 */ "param ::= paramVar YY_EQUALS expression", + /* 56 */ "paramVar ::= identifier", + /* 57 */ "paramVar ::= thisProperty", + /* 58 */ "paramVar ::= array", + /* 59 */ "paramVar ::= object", + /* 60 */ "splat ::= expression YY_RANGE_EXCLUSIVE", + /* 61 */ "simpleAssignable ::= identifier", + /* 62 */ "simpleAssignable ::= value accessor", + /* 63 */ "simpleAssignable ::= invocation accessor", + /* 64 */ "simpleAssignable ::= thisProperty", + /* 65 */ "assignable ::= simpleAssignable", + /* 66 */ "assignable ::= array", + /* 67 */ "assignable ::= object", + /* 68 */ "value ::= assignable", + /* 69 */ "value ::= literal", + /* 70 */ "value ::= parenthetical", + /* 71 */ "value ::= range", + /* 72 */ "value ::= this", + /* 73 */ "accessor ::= YY_ACCESSOR identifier", + /* 74 */ "accessor ::= YY_EXISTENTIAL_ACCESSOR identifier", + /* 75 */ "accessor ::= YY_PROTOTYPE identifier", + /* 76 */ "accessor ::= YY_PROTOTYPE", + /* 77 */ "accessor ::= index", + /* 78 */ "index ::= YY_INDEX_START indexValue YY_INDEX_END", + /* 79 */ "index ::= YY_INDEX_SOAK index", + /* 80 */ "index ::= YY_INDEX_PROTO index", + /* 81 */ "indexValue ::= expression", + /* 82 */ "indexValue ::= slice", + /* 83 */ "object ::= YY_OBJECT_START assignList optComma YY_OBJECT_END", + /* 84 */ "assignList ::=", + /* 85 */ "assignList ::= assignObj", + /* 86 */ "assignList ::= assignList YY_COMMA assignObj", + /* 87 */ "assignList ::= assignList optComma YY_TERMINATOR assignObj", + /* 88 */ "assignList ::= assignList optComma YY_INDENT assignList optComma YY_OUTDENT", + /* 89 */ "class ::= YY_CLASS", + /* 90 */ "class ::= YY_CLASS block", + /* 91 */ "class ::= YY_CLASS YY_EXTENDS value", + /* 92 */ "class ::= YY_CLASS YY_EXTENDS value block", + /* 93 */ "class ::= YY_CLASS simpleAssignable", + /* 94 */ "class ::= YY_CLASS simpleAssignable block", + /* 95 */ "class ::= YY_CLASS simpleAssignable YY_EXTENDS value", + /* 96 */ "class ::= YY_CLASS simpleAssignable YY_EXTENDS value block", + /* 97 */ "invocation ::= value optFuncExist arguments", + /* 98 */ "invocation ::= invocation optFuncExist arguments", + /* 99 */ "invocation ::= YY_SUPER", + /* 100 */ "invocation ::= YY_SUPER arguments", + /* 101 */ "optFuncExist ::=", + /* 102 */ "optFuncExist ::= YY_FUNC_EXIST", + /* 103 */ "arguments ::= YY_CALL_START YY_CALL_END", + /* 104 */ "arguments ::= YY_CALL_START argList optComma YY_CALL_END", + /* 105 */ "this ::= YY_THIS", + /* 106 */ "this ::= YY_AT_SIGN", + /* 107 */ "thisProperty ::= YY_AT_SIGN identifier", + /* 108 */ "array ::= YY_ARRAY_START YY_ARRAY_END", + /* 109 */ "array ::= YY_ARRAY_START argList optComma YY_ARRAY_END", + /* 110 */ "rangeDots ::= YY_RANGE_INCLUSIVE", + /* 111 */ "rangeDots ::= YY_RANGE_EXCLUSIVE", + /* 112 */ "range ::= YY_ARRAY_START expression rangeDots expression YY_ARRAY_END", + /* 113 */ "slice ::= expression rangeDots expression", + /* 114 */ "slice ::= expression rangeDots", + /* 115 */ "slice ::= rangeDots expression", + /* 116 */ "argList ::= arg", + /* 117 */ "argList ::= argList YY_COMMA arg", + /* 118 */ "argList ::= argList optComma YY_TERMINATOR arg", + /* 119 */ "argList ::= YY_INDENT argList optComma YY_OUTDENT", + /* 120 */ "argList ::= argList optComma YY_INDENT argList optComma YY_OUTDENT", + /* 121 */ "arg ::= expression", + /* 122 */ "arg ::= splat", + /* 123 */ "simpleArgs ::= expression", + /* 124 */ "simpleArgs ::= simpleArgs YY_COMMA expression", + /* 125 */ "try ::= YY_TRY block", + /* 126 */ "try ::= YY_TRY block catch", + /* 127 */ "try ::= YY_TRY block YY_FINALLY block", + /* 128 */ "try ::= YY_TRY block catch YY_FINALLY block", + /* 129 */ "catch ::= YY_CATCH identifier block", + /* 130 */ "throw ::= YY_THROW expression", + /* 131 */ "parenthetical ::= YY_PAREN_START body YY_PAREN_END", + /* 132 */ "parenthetical ::= YY_PAREN_START YY_INDENT body YY_OUTDENT YY_PAREN_END", + /* 133 */ "whileSource ::= YY_WHILE expression", + /* 134 */ "whileSource ::= YY_WHILE expression YY_WHEN expression", + /* 135 */ "whileSource ::= YY_UNTIL expression", + /* 136 */ "whileSource ::= YY_UNTIL expression YY_WHEN expression", + /* 137 */ "while ::= whileSource block", + /* 138 */ "while ::= statement whileSource", + /* 139 */ "while ::= expression whileSource", + /* 140 */ "while ::= loop", + /* 141 */ "loop ::= YY_LOOP block", + /* 142 */ "loop ::= YY_LOOP expression", + /* 143 */ "for ::= statement forBody", + /* 144 */ "for ::= expression forBody", + /* 145 */ "for ::= forBody block", + /* 146 */ "forBody ::= YY_FOR range", + /* 147 */ "forBody ::= forStart forSource", + /* 148 */ "forStart ::= YY_FOR forVariables", + /* 149 */ "forStart ::= YY_FOR YY_OWN forVariables", + /* 150 */ "forValue ::= identifier", + /* 151 */ "forValue ::= array", + /* 152 */ "forValue ::= object", + /* 153 */ "forVariables ::= forValue", + /* 154 */ "forVariables ::= forValue YY_COMMA forValue", + /* 155 */ "forSource ::= YY_FORIN expression", + /* 156 */ "forSource ::= YY_FOROF expression", + /* 157 */ "forSource ::= YY_FORIN expression YY_WHEN expression", + /* 158 */ "forSource ::= YY_FOROF expression YY_WHEN expression", + /* 159 */ "forSource ::= YY_FORIN expression YY_BY expression", + /* 160 */ "forSource ::= YY_FORIN expression YY_WHEN expression YY_BY expression", + /* 161 */ "forSource ::= YY_FORIN expression YY_BY expression YY_WHEN expression", + /* 162 */ "switch ::= YY_SWITCH expression YY_INDENT whens YY_OUTDENT", + /* 163 */ "switch ::= YY_SWITCH expression YY_INDENT whens YY_ELSE block YY_OUTDENT", + /* 164 */ "switch ::= YY_SWITCH YY_INDENT whens YY_OUTDENT", + /* 165 */ "switch ::= YY_SWITCH YY_INDENT whens YY_ELSE block YY_OUTDENT", + /* 166 */ "whens ::= when", + /* 167 */ "whens ::= whens when", + /* 168 */ "when ::= YY_LEADING_WHEN simpleArgs block", + /* 169 */ "when ::= YY_LEADING_WHEN simpleArgs block YY_TERMINATOR", + /* 170 */ "ifBlock ::= YY_IF expression block", + /* 171 */ "ifBlock ::= ifBlock YY_ELSE YY_IF expression block", + /* 172 */ "if ::= ifBlock", + /* 173 */ "if ::= ifBlock YY_ELSE block", + /* 174 */ "if ::= statement YY_POST_IF expression", + /* 175 */ "if ::= expression YY_POST_IF expression", + /* 176 */ "operation ::= YY_UNARY expression", + /* 177 */ "operation ::= YY_MINUS expression", + /* 178 */ "operation ::= YY_PLUS expression", + /* 179 */ "operation ::= YY_DECREMENT simpleAssignable", + /* 180 */ "operation ::= YY_INCREMENT simpleAssignable", + /* 181 */ "operation ::= simpleAssignable YY_DECREMENT", + /* 182 */ "operation ::= simpleAssignable YY_INCREMENT", + /* 183 */ "operation ::= expression YY_EXISTENTIAL", + /* 184 */ "operation ::= expression YY_PLUS expression", + /* 185 */ "operation ::= expression YY_MINUS expression", + /* 186 */ "operation ::= expression YY_MATH expression", + /* 187 */ "operation ::= expression YY_SHIFT expression", + /* 188 */ "operation ::= expression YY_COMPARE expression", + /* 189 */ "operation ::= expression YY_LOGIC expression", + /* 190 */ "operation ::= expression YY_RELATION expression", + /* 191 */ "operation ::= simpleAssignable YY_COMPOUND_ASSIGN expression", + /* 192 */ "operation ::= simpleAssignable YY_COMPOUND_ASSIGN YY_INDENT expression YY_OUTDENT", + /* 193 */ "operation ::= simpleAssignable YY_EXTENDS expression", + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + static function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count(self::$yyTokenName)) { + return self::$yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param yyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . self::tokenName($yytos->major) . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + self::tokenName($iLookAhead) . " => " . + self::tokenName($iFallback) . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor, $generated = FALSE) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ + return; + } + $yytos = new yyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + $yytos->generated = $generated; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for ($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + self::tokenName($this->yystack[$i]->major)); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + * <pre> + * array( + * array( + * int $lhs; Symbol on the left-hand side of the rule + * int $nrhs; Number of right-hand side symbols in the rule + * ),... + * ); + * </pre> + */ + static public $yyRuleInfo = array( + array( 'lhs' => 75, 'rhs' => 0 ), + array( 'lhs' => 75, 'rhs' => 1 ), + array( 'lhs' => 75, 'rhs' => 2 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 3 ), + array( 'lhs' => 76, 'rhs' => 2 ), + array( 'lhs' => 78, 'rhs' => 1 ), + array( 'lhs' => 78, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 77, 'rhs' => 2 ), + array( 'lhs' => 77, 'rhs' => 3 ), + array( 'lhs' => 95, 'rhs' => 1 ), + array( 'lhs' => 96, 'rhs' => 1 ), + array( 'lhs' => 96, 'rhs' => 1 ), + array( 'lhs' => 97, 'rhs' => 1 ), + array( 'lhs' => 97, 'rhs' => 1 ), + array( 'lhs' => 97, 'rhs' => 1 ), + array( 'lhs' => 97, 'rhs' => 1 ), + array( 'lhs' => 88, 'rhs' => 3 ), + array( 'lhs' => 88, 'rhs' => 5 ), + array( 'lhs' => 99, 'rhs' => 1 ), + array( 'lhs' => 99, 'rhs' => 3 ), + array( 'lhs' => 99, 'rhs' => 5 ), + array( 'lhs' => 99, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 100, 'rhs' => 1 ), + array( 'lhs' => 81, 'rhs' => 2 ), + array( 'lhs' => 81, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 86, 'rhs' => 5 ), + array( 'lhs' => 86, 'rhs' => 2 ), + array( 'lhs' => 103, 'rhs' => 1 ), + array( 'lhs' => 103, 'rhs' => 1 ), + array( 'lhs' => 104, 'rhs' => 0 ), + array( 'lhs' => 104, 'rhs' => 1 ), + array( 'lhs' => 102, 'rhs' => 0 ), + array( 'lhs' => 102, 'rhs' => 1 ), + array( 'lhs' => 102, 'rhs' => 3 ), + array( 'lhs' => 105, 'rhs' => 1 ), + array( 'lhs' => 105, 'rhs' => 2 ), + array( 'lhs' => 105, 'rhs' => 3 ), + array( 'lhs' => 106, 'rhs' => 1 ), + array( 'lhs' => 106, 'rhs' => 1 ), + array( 'lhs' => 106, 'rhs' => 1 ), + array( 'lhs' => 106, 'rhs' => 1 ), + array( 'lhs' => 109, 'rhs' => 2 ), + array( 'lhs' => 110, 'rhs' => 1 ), + array( 'lhs' => 110, 'rhs' => 2 ), + array( 'lhs' => 110, 'rhs' => 2 ), + array( 'lhs' => 110, 'rhs' => 1 ), + array( 'lhs' => 98, 'rhs' => 1 ), + array( 'lhs' => 98, 'rhs' => 1 ), + array( 'lhs' => 98, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 111, 'rhs' => 2 ), + array( 'lhs' => 111, 'rhs' => 2 ), + array( 'lhs' => 111, 'rhs' => 2 ), + array( 'lhs' => 111, 'rhs' => 1 ), + array( 'lhs' => 111, 'rhs' => 1 ), + array( 'lhs' => 115, 'rhs' => 3 ), + array( 'lhs' => 115, 'rhs' => 2 ), + array( 'lhs' => 115, 'rhs' => 2 ), + array( 'lhs' => 116, 'rhs' => 1 ), + array( 'lhs' => 116, 'rhs' => 1 ), + array( 'lhs' => 108, 'rhs' => 4 ), + array( 'lhs' => 118, 'rhs' => 0 ), + array( 'lhs' => 118, 'rhs' => 1 ), + array( 'lhs' => 118, 'rhs' => 3 ), + array( 'lhs' => 118, 'rhs' => 4 ), + array( 'lhs' => 118, 'rhs' => 6 ), + array( 'lhs' => 94, 'rhs' => 1 ), + array( 'lhs' => 94, 'rhs' => 2 ), + array( 'lhs' => 94, 'rhs' => 3 ), + array( 'lhs' => 94, 'rhs' => 4 ), + array( 'lhs' => 94, 'rhs' => 2 ), + array( 'lhs' => 94, 'rhs' => 3 ), + array( 'lhs' => 94, 'rhs' => 4 ), + array( 'lhs' => 94, 'rhs' => 5 ), + array( 'lhs' => 85, 'rhs' => 3 ), + array( 'lhs' => 85, 'rhs' => 3 ), + array( 'lhs' => 85, 'rhs' => 1 ), + array( 'lhs' => 85, 'rhs' => 2 ), + array( 'lhs' => 119, 'rhs' => 0 ), + array( 'lhs' => 119, 'rhs' => 1 ), + array( 'lhs' => 120, 'rhs' => 2 ), + array( 'lhs' => 120, 'rhs' => 4 ), + array( 'lhs' => 114, 'rhs' => 1 ), + array( 'lhs' => 114, 'rhs' => 1 ), + array( 'lhs' => 101, 'rhs' => 2 ), + array( 'lhs' => 107, 'rhs' => 2 ), + array( 'lhs' => 107, 'rhs' => 4 ), + array( 'lhs' => 122, 'rhs' => 1 ), + array( 'lhs' => 122, 'rhs' => 1 ), + array( 'lhs' => 113, 'rhs' => 5 ), + array( 'lhs' => 117, 'rhs' => 3 ), + array( 'lhs' => 117, 'rhs' => 2 ), + array( 'lhs' => 117, 'rhs' => 2 ), + array( 'lhs' => 121, 'rhs' => 1 ), + array( 'lhs' => 121, 'rhs' => 3 ), + array( 'lhs' => 121, 'rhs' => 4 ), + array( 'lhs' => 121, 'rhs' => 4 ), + array( 'lhs' => 121, 'rhs' => 6 ), + array( 'lhs' => 123, 'rhs' => 1 ), + array( 'lhs' => 123, 'rhs' => 1 ), + array( 'lhs' => 124, 'rhs' => 1 ), + array( 'lhs' => 124, 'rhs' => 3 ), + array( 'lhs' => 90, 'rhs' => 2 ), + array( 'lhs' => 90, 'rhs' => 3 ), + array( 'lhs' => 90, 'rhs' => 4 ), + array( 'lhs' => 90, 'rhs' => 5 ), + array( 'lhs' => 125, 'rhs' => 3 ), + array( 'lhs' => 82, 'rhs' => 2 ), + array( 'lhs' => 112, 'rhs' => 3 ), + array( 'lhs' => 112, 'rhs' => 5 ), + array( 'lhs' => 126, 'rhs' => 2 ), + array( 'lhs' => 126, 'rhs' => 4 ), + array( 'lhs' => 126, 'rhs' => 2 ), + array( 'lhs' => 126, 'rhs' => 4 ), + array( 'lhs' => 91, 'rhs' => 2 ), + array( 'lhs' => 91, 'rhs' => 2 ), + array( 'lhs' => 91, 'rhs' => 2 ), + array( 'lhs' => 91, 'rhs' => 1 ), + array( 'lhs' => 127, 'rhs' => 2 ), + array( 'lhs' => 127, 'rhs' => 2 ), + array( 'lhs' => 92, 'rhs' => 2 ), + array( 'lhs' => 92, 'rhs' => 2 ), + array( 'lhs' => 92, 'rhs' => 2 ), + array( 'lhs' => 128, 'rhs' => 2 ), + array( 'lhs' => 128, 'rhs' => 2 ), + array( 'lhs' => 129, 'rhs' => 2 ), + array( 'lhs' => 129, 'rhs' => 3 ), + array( 'lhs' => 132, 'rhs' => 1 ), + array( 'lhs' => 132, 'rhs' => 1 ), + array( 'lhs' => 132, 'rhs' => 1 ), + array( 'lhs' => 131, 'rhs' => 1 ), + array( 'lhs' => 131, 'rhs' => 3 ), + array( 'lhs' => 130, 'rhs' => 2 ), + array( 'lhs' => 130, 'rhs' => 2 ), + array( 'lhs' => 130, 'rhs' => 4 ), + array( 'lhs' => 130, 'rhs' => 4 ), + array( 'lhs' => 130, 'rhs' => 4 ), + array( 'lhs' => 130, 'rhs' => 6 ), + array( 'lhs' => 130, 'rhs' => 6 ), + array( 'lhs' => 93, 'rhs' => 5 ), + array( 'lhs' => 93, 'rhs' => 7 ), + array( 'lhs' => 93, 'rhs' => 4 ), + array( 'lhs' => 93, 'rhs' => 6 ), + array( 'lhs' => 133, 'rhs' => 1 ), + array( 'lhs' => 133, 'rhs' => 2 ), + array( 'lhs' => 134, 'rhs' => 3 ), + array( 'lhs' => 134, 'rhs' => 4 ), + array( 'lhs' => 135, 'rhs' => 3 ), + array( 'lhs' => 135, 'rhs' => 5 ), + array( 'lhs' => 89, 'rhs' => 1 ), + array( 'lhs' => 89, 'rhs' => 3 ), + array( 'lhs' => 89, 'rhs' => 3 ), + array( 'lhs' => 89, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 2 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 3 ), + array( 'lhs' => 87, 'rhs' => 5 ), + array( 'lhs' => 87, 'rhs' => 3 ), + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( + 0 => 0, + 23 => 0, + 1 => 1, + 6 => 1, + 7 => 1, + 8 => 1, + 9 => 1, + 10 => 1, + 12 => 1, + 13 => 1, + 14 => 1, + 15 => 1, + 16 => 1, + 17 => 1, + 18 => 1, + 19 => 1, + 20 => 1, + 21 => 1, + 22 => 1, + 28 => 1, + 37 => 1, + 38 => 1, + 39 => 1, + 40 => 1, + 49 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 64 => 1, + 65 => 1, + 68 => 1, + 72 => 1, + 77 => 1, + 121 => 1, + 122 => 1, + 123 => 1, + 140 => 1, + 148 => 1, + 150 => 1, + 166 => 1, + 172 => 1, + 2 => 2, + 5 => 2, + 24 => 2, + 78 => 2, + 3 => 3, + 4 => 4, + 11 => 11, + 25 => 11, + 26 => 11, + 27 => 11, + 29 => 11, + 30 => 11, + 31 => 31, + 32 => 32, + 33 => 33, + 34 => 34, + 61 => 34, + 66 => 34, + 67 => 34, + 69 => 34, + 70 => 34, + 71 => 34, + 151 => 34, + 152 => 34, + 35 => 35, + 36 => 36, + 41 => 41, + 42 => 42, + 43 => 43, + 44 => 44, + 45 => 45, + 46 => 46, + 47 => 47, + 48 => 48, + 50 => 50, + 84 => 50, + 103 => 50, + 51 => 51, + 85 => 51, + 116 => 51, + 153 => 51, + 52 => 52, + 117 => 52, + 53 => 53, + 54 => 54, + 55 => 55, + 60 => 60, + 62 => 62, + 63 => 63, + 73 => 73, + 74 => 74, + 75 => 75, + 76 => 76, + 79 => 79, + 80 => 80, + 81 => 81, + 82 => 82, + 83 => 83, + 86 => 86, + 87 => 87, + 88 => 88, + 120 => 88, + 89 => 89, + 90 => 90, + 91 => 91, + 92 => 92, + 93 => 93, + 94 => 94, + 95 => 95, + 96 => 96, + 97 => 97, + 98 => 97, + 99 => 99, + 100 => 100, + 101 => 101, + 102 => 102, + 104 => 104, + 119 => 104, + 105 => 105, + 106 => 105, + 107 => 107, + 108 => 108, + 109 => 109, + 110 => 110, + 111 => 111, + 112 => 112, + 113 => 113, + 114 => 114, + 115 => 115, + 118 => 118, + 124 => 124, + 154 => 124, + 125 => 125, + 126 => 126, + 127 => 127, + 128 => 128, + 129 => 129, + 130 => 130, + 131 => 131, + 132 => 132, + 133 => 133, + 134 => 134, + 135 => 135, + 136 => 136, + 137 => 137, + 138 => 138, + 139 => 138, + 141 => 141, + 142 => 142, + 143 => 143, + 144 => 143, + 145 => 145, + 146 => 146, + 147 => 147, + 149 => 149, + 155 => 155, + 156 => 156, + 157 => 157, + 158 => 158, + 159 => 159, + 160 => 160, + 161 => 161, + 162 => 162, + 163 => 163, + 164 => 164, + 165 => 165, + 167 => 167, + 168 => 168, + 169 => 169, + 170 => 170, + 171 => 171, + 173 => 173, + 174 => 174, + 175 => 174, + 176 => 176, + 179 => 176, + 180 => 176, + 177 => 177, + 178 => 177, + 181 => 181, + 182 => 181, + 183 => 183, + 184 => 184, + 185 => 184, + 186 => 184, + 187 => 184, + 188 => 184, + 189 => 184, + 190 => 190, + 191 => 191, + 192 => 192, + 193 => 193, + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line <lineno> <grammarfile> + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line <lineno> <thisfile> + */ +#line 28 "/var/www/coffeescript-php/grammar.y" + function yy_r0(){ $this->_retvalue = yy('Block'); } +#line 2653 "/var/www/coffeescript-php/grammar.php" +#line 29 "/var/www/coffeescript-php/grammar.y" + function yy_r1(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 2656 "/var/www/coffeescript-php/grammar.php" +#line 30 "/var/www/coffeescript-php/grammar.y" + function yy_r2(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; } +#line 2659 "/var/www/coffeescript-php/grammar.php" +#line 32 "/var/www/coffeescript-php/grammar.y" + function yy_r3(){ $this->_retvalue = yy_Block::wrap(array($this->yystack[$this->yyidx + 0]->minor)); } +#line 2662 "/var/www/coffeescript-php/grammar.php" +#line 33 "/var/www/coffeescript-php/grammar.y" + function yy_r4(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor->push($this->yystack[$this->yyidx + 0]->minor); } +#line 2665 "/var/www/coffeescript-php/grammar.php" +#line 42 "/var/www/coffeescript-php/grammar.y" + function yy_r11(){ $this->_retvalue = yy('Literal', $this->yystack[$this->yyidx + 0]->minor); } +#line 2668 "/var/www/coffeescript-php/grammar.php" +#line 67 "/var/www/coffeescript-php/grammar.y" + function yy_r31(){ $val = yy('Literal', $this->yystack[$this->yyidx + 0]->minor); + $val->is_undefined($this->yystack[$this->yyidx + 0]->minor === 'undefined'); + $this->_retvalue = $val; } +#line 2673 "/var/www/coffeescript-php/grammar.php" +#line 71 "/var/www/coffeescript-php/grammar.y" + function yy_r32(){ $this->_retvalue = yy('Assign', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2676 "/var/www/coffeescript-php/grammar.php" +#line 72 "/var/www/coffeescript-php/grammar.y" + function yy_r33(){ $this->_retvalue = yy('Assign', $this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2679 "/var/www/coffeescript-php/grammar.php" +#line 74 "/var/www/coffeescript-php/grammar.y" + function yy_r34(){ $this->_retvalue = yy('Value', $this->yystack[$this->yyidx + 0]->minor); } +#line 2682 "/var/www/coffeescript-php/grammar.php" +#line 75 "/var/www/coffeescript-php/grammar.y" + function yy_r35(){ $this->_retvalue = yy('Assign', yy('Value', $this->yystack[$this->yyidx + -2]->minor), $this->yystack[$this->yyidx + 0]->minor, 'object'); } +#line 2685 "/var/www/coffeescript-php/grammar.php" +#line 76 "/var/www/coffeescript-php/grammar.y" + function yy_r36(){ $this->_retvalue = yy('Assign', yy('Value', $this->yystack[$this->yyidx + -4]->minor), $this->yystack[$this->yyidx + -1]->minor, 'object'); } +#line 2688 "/var/www/coffeescript-php/grammar.php" +#line 83 "/var/www/coffeescript-php/grammar.y" + function yy_r41(){ $this->_retvalue = yy('Return', $this->yystack[$this->yyidx + 0]->minor); } +#line 2691 "/var/www/coffeescript-php/grammar.php" +#line 84 "/var/www/coffeescript-php/grammar.y" + function yy_r42(){ $this->_retvalue = yy('Return'); } +#line 2694 "/var/www/coffeescript-php/grammar.php" +#line 86 "/var/www/coffeescript-php/grammar.y" + function yy_r43(){ $this->_retvalue = yy('Comment', $this->yystack[$this->yyidx + 0]->minor); } +#line 2697 "/var/www/coffeescript-php/grammar.php" +#line 88 "/var/www/coffeescript-php/grammar.y" + function yy_r44(){ $this->_retvalue = yy('Code', $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2700 "/var/www/coffeescript-php/grammar.php" +#line 89 "/var/www/coffeescript-php/grammar.y" + function yy_r45(){ $this->_retvalue = yy('Code', array(), $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2703 "/var/www/coffeescript-php/grammar.php" +#line 91 "/var/www/coffeescript-php/grammar.y" + function yy_r46(){ $this->_retvalue = 'func'; } +#line 2706 "/var/www/coffeescript-php/grammar.php" +#line 92 "/var/www/coffeescript-php/grammar.y" + function yy_r47(){ $this->_retvalue = 'boundfunc'; } +#line 2709 "/var/www/coffeescript-php/grammar.php" +#line 94 "/var/www/coffeescript-php/grammar.y" + function yy_r48(){ $this->_retvalue = ''; } +#line 2712 "/var/www/coffeescript-php/grammar.php" +#line 97 "/var/www/coffeescript-php/grammar.y" + function yy_r50(){ $this->_retvalue = array(); } +#line 2715 "/var/www/coffeescript-php/grammar.php" +#line 98 "/var/www/coffeescript-php/grammar.y" + function yy_r51(){ $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); } +#line 2718 "/var/www/coffeescript-php/grammar.php" +#line 99 "/var/www/coffeescript-php/grammar.y" + function yy_r52(){ $this->_retvalue = array_merge($this->yystack[$this->yyidx + -2]->minor, array($this->yystack[$this->yyidx + 0]->minor)); } +#line 2721 "/var/www/coffeescript-php/grammar.php" +#line 101 "/var/www/coffeescript-php/grammar.y" + function yy_r53(){ $this->_retvalue = yy('Param', $this->yystack[$this->yyidx + 0]->minor); } +#line 2724 "/var/www/coffeescript-php/grammar.php" +#line 102 "/var/www/coffeescript-php/grammar.y" + function yy_r54(){ $this->_retvalue = yy('Param', $this->yystack[$this->yyidx + -1]->minor, NULL, TRUE); } +#line 2727 "/var/www/coffeescript-php/grammar.php" +#line 103 "/var/www/coffeescript-php/grammar.y" + function yy_r55(){ $this->_retvalue = yy('Param', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2730 "/var/www/coffeescript-php/grammar.php" +#line 110 "/var/www/coffeescript-php/grammar.y" + function yy_r60(){ $this->_retvalue = yy('Splat', $this->yystack[$this->yyidx + -1]->minor); } +#line 2733 "/var/www/coffeescript-php/grammar.php" +#line 113 "/var/www/coffeescript-php/grammar.y" + function yy_r62(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor->push($this->yystack[$this->yyidx + 0]->minor); } +#line 2736 "/var/www/coffeescript-php/grammar.php" +#line 114 "/var/www/coffeescript-php/grammar.y" + function yy_r63(){ $this->_retvalue = yy('Value', $this->yystack[$this->yyidx + -1]->minor, array($this->yystack[$this->yyidx + 0]->minor)); } +#line 2739 "/var/www/coffeescript-php/grammar.php" +#line 127 "/var/www/coffeescript-php/grammar.y" + function yy_r73(){ $this->_retvalue = yy('Access', $this->yystack[$this->yyidx + 0]->minor); } +#line 2742 "/var/www/coffeescript-php/grammar.php" +#line 128 "/var/www/coffeescript-php/grammar.y" + function yy_r74(){ $this->_retvalue = yy('Access', $this->yystack[$this->yyidx + 0]->minor, 'soak'); } +#line 2745 "/var/www/coffeescript-php/grammar.php" +#line 129 "/var/www/coffeescript-php/grammar.y" + function yy_r75(){ $this->_retvalue = yy('Access', $this->yystack[$this->yyidx + 0]->minor, 'proto'); } +#line 2748 "/var/www/coffeescript-php/grammar.php" +#line 130 "/var/www/coffeescript-php/grammar.y" + function yy_r76(){ $this->_retvalue = yy('Access', yy('Literal', 'prototype')); } +#line 2751 "/var/www/coffeescript-php/grammar.php" +#line 134 "/var/www/coffeescript-php/grammar.y" + function yy_r79(){ $this->_retvalue = extend($this->yystack[$this->yyidx + 0]->minor, array('soak' => TRUE)); } +#line 2754 "/var/www/coffeescript-php/grammar.php" +#line 135 "/var/www/coffeescript-php/grammar.y" + function yy_r80(){ $this->_retvalue = extend($this->yystack[$this->yyidx + 0]->minor, array('proto' => TRUE)); } +#line 2757 "/var/www/coffeescript-php/grammar.php" +#line 137 "/var/www/coffeescript-php/grammar.y" + function yy_r81(){ $this->_retvalue = yy('Index', $this->yystack[$this->yyidx + 0]->minor); } +#line 2760 "/var/www/coffeescript-php/grammar.php" +#line 138 "/var/www/coffeescript-php/grammar.y" + function yy_r82(){ $this->_retvalue = yy('Slice', $this->yystack[$this->yyidx + 0]->minor); } +#line 2763 "/var/www/coffeescript-php/grammar.php" +#line 140 "/var/www/coffeescript-php/grammar.y" + function yy_r83(){ $this->_retvalue = yy('Obj', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx - 3]->generated); } +#line 2766 "/var/www/coffeescript-php/grammar.php" +#line 144 "/var/www/coffeescript-php/grammar.y" + function yy_r86(){ $this->yystack[$this->yyidx + -2]->minor[] = $this->yystack[$this->yyidx + 0]->minor; $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; } +#line 2769 "/var/www/coffeescript-php/grammar.php" +#line 145 "/var/www/coffeescript-php/grammar.y" + function yy_r87(){ $this->yystack[$this->yyidx + -3]->minor[] = $this->yystack[$this->yyidx + 0]->minor; $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor; } +#line 2772 "/var/www/coffeescript-php/grammar.php" +#line 146 "/var/www/coffeescript-php/grammar.y" + function yy_r88(){ $this->_retvalue = array_merge($this->yystack[$this->yyidx + -5]->minor, $this->yystack[$this->yyidx + -2]->minor); } +#line 2775 "/var/www/coffeescript-php/grammar.php" +#line 148 "/var/www/coffeescript-php/grammar.y" + function yy_r89(){ $this->_retvalue = yy('Class'); } +#line 2778 "/var/www/coffeescript-php/grammar.php" +#line 149 "/var/www/coffeescript-php/grammar.y" + function yy_r90(){ $this->_retvalue = yy('Class', NULL, NULL, $this->yystack[$this->yyidx + 0]->minor); } +#line 2781 "/var/www/coffeescript-php/grammar.php" +#line 150 "/var/www/coffeescript-php/grammar.y" + function yy_r91(){ $this->_retvalue = yy('Class', NULL, $this->yystack[$this->yyidx + 0]->minor); } +#line 2784 "/var/www/coffeescript-php/grammar.php" +#line 151 "/var/www/coffeescript-php/grammar.y" + function yy_r92(){ $this->_retvalue = yy('Class', NULL, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2787 "/var/www/coffeescript-php/grammar.php" +#line 152 "/var/www/coffeescript-php/grammar.y" + function yy_r93(){ $this->_retvalue = yy('Class', $this->yystack[$this->yyidx + 0]->minor); } +#line 2790 "/var/www/coffeescript-php/grammar.php" +#line 153 "/var/www/coffeescript-php/grammar.y" + function yy_r94(){ $this->_retvalue = yy('Class', $this->yystack[$this->yyidx + -1]->minor, NULL, $this->yystack[$this->yyidx + 0]->minor); } +#line 2793 "/var/www/coffeescript-php/grammar.php" +#line 154 "/var/www/coffeescript-php/grammar.y" + function yy_r95(){ $this->_retvalue = yy('Class', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2796 "/var/www/coffeescript-php/grammar.php" +#line 155 "/var/www/coffeescript-php/grammar.y" + function yy_r96(){ $this->_retvalue = yy('Class', $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2799 "/var/www/coffeescript-php/grammar.php" +#line 157 "/var/www/coffeescript-php/grammar.y" + function yy_r97(){ $this->_retvalue = yy('Call', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2802 "/var/www/coffeescript-php/grammar.php" +#line 159 "/var/www/coffeescript-php/grammar.y" + function yy_r99(){ $this->_retvalue = yy('Call', 'super', array(yy('Splat', yy('Literal', 'arguments')))); } +#line 2805 "/var/www/coffeescript-php/grammar.php" +#line 160 "/var/www/coffeescript-php/grammar.y" + function yy_r100(){ $this->_retvalue = yy('Call', 'super', $this->yystack[$this->yyidx + 0]->minor); } +#line 2808 "/var/www/coffeescript-php/grammar.php" +#line 162 "/var/www/coffeescript-php/grammar.y" + function yy_r101(){ $this->_retvalue = FALSE; } +#line 2811 "/var/www/coffeescript-php/grammar.php" +#line 163 "/var/www/coffeescript-php/grammar.y" + function yy_r102(){ $this->_retvalue = TRUE; } +#line 2814 "/var/www/coffeescript-php/grammar.php" +#line 166 "/var/www/coffeescript-php/grammar.y" + function yy_r104(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; } +#line 2817 "/var/www/coffeescript-php/grammar.php" +#line 168 "/var/www/coffeescript-php/grammar.y" + function yy_r105(){ $this->_retvalue = yy('Value', yy('Literal', 'this')); } +#line 2820 "/var/www/coffeescript-php/grammar.php" +#line 171 "/var/www/coffeescript-php/grammar.y" + function yy_r107(){ $this->_retvalue = yy('Value', yy('Literal', 'this'), array(yy('Access', $this->yystack[$this->yyidx + 0]->minor)), 'this'); } +#line 2823 "/var/www/coffeescript-php/grammar.php" +#line 173 "/var/www/coffeescript-php/grammar.y" + function yy_r108(){ $this->_retvalue = yy('Arr', array()); } +#line 2826 "/var/www/coffeescript-php/grammar.php" +#line 174 "/var/www/coffeescript-php/grammar.y" + function yy_r109(){ $this->_retvalue = yy('Arr', $this->yystack[$this->yyidx + -2]->minor); } +#line 2829 "/var/www/coffeescript-php/grammar.php" +#line 176 "/var/www/coffeescript-php/grammar.y" + function yy_r110(){ $this->_retvalue = 'inclusive'; } +#line 2832 "/var/www/coffeescript-php/grammar.php" +#line 177 "/var/www/coffeescript-php/grammar.y" + function yy_r111(){ $this->_retvalue = 'exclusive'; } +#line 2835 "/var/www/coffeescript-php/grammar.php" +#line 179 "/var/www/coffeescript-php/grammar.y" + function yy_r112(){ $this->_retvalue = yy('Range', $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -2]->minor); } +#line 2838 "/var/www/coffeescript-php/grammar.php" +#line 181 "/var/www/coffeescript-php/grammar.y" + function yy_r113(){ $this->_retvalue = yy('Range', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2841 "/var/www/coffeescript-php/grammar.php" +#line 182 "/var/www/coffeescript-php/grammar.y" + function yy_r114(){ $this->_retvalue = yy('Range', $this->yystack[$this->yyidx + -1]->minor, NULL, $this->yystack[$this->yyidx + 0]->minor); } +#line 2844 "/var/www/coffeescript-php/grammar.php" +#line 183 "/var/www/coffeescript-php/grammar.y" + function yy_r115(){ $this->_retvalue = yy('Range', NULL, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2847 "/var/www/coffeescript-php/grammar.php" +#line 187 "/var/www/coffeescript-php/grammar.y" + function yy_r118(){ $this->_retvalue = array_merge($this->yystack[$this->yyidx + -3]->minor, array($this->yystack[$this->yyidx + 0]->minor)); } +#line 2850 "/var/www/coffeescript-php/grammar.php" +#line 195 "/var/www/coffeescript-php/grammar.y" + function yy_r124(){ $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2853 "/var/www/coffeescript-php/grammar.php" +#line 197 "/var/www/coffeescript-php/grammar.y" + function yy_r125(){ $this->_retvalue = yy('Try', $this->yystack[$this->yyidx + 0]->minor); } +#line 2856 "/var/www/coffeescript-php/grammar.php" +#line 198 "/var/www/coffeescript-php/grammar.y" + function yy_r126(){ $this->_retvalue = yy('Try', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor[0], $this->yystack[$this->yyidx + 0]->minor[1]); } +#line 2859 "/var/www/coffeescript-php/grammar.php" +#line 199 "/var/www/coffeescript-php/grammar.y" + function yy_r127(){ $this->_retvalue = yy('Try', $this->yystack[$this->yyidx + -2]->minor, NULL, NULL, $this->yystack[$this->yyidx + 0]->minor); } +#line 2862 "/var/www/coffeescript-php/grammar.php" +#line 200 "/var/www/coffeescript-php/grammar.y" + function yy_r128(){ $this->_retvalue = yy('Try', $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -2]->minor[0], $this->yystack[$this->yyidx + -2]->minor[1], $this->yystack[$this->yyidx + 0]->minor); } +#line 2865 "/var/www/coffeescript-php/grammar.php" +#line 202 "/var/www/coffeescript-php/grammar.y" + function yy_r129(){ $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2868 "/var/www/coffeescript-php/grammar.php" +#line 204 "/var/www/coffeescript-php/grammar.y" + function yy_r130(){ $this->_retvalue = yy('Throw', $this->yystack[$this->yyidx + 0]->minor); } +#line 2871 "/var/www/coffeescript-php/grammar.php" +#line 206 "/var/www/coffeescript-php/grammar.y" + function yy_r131(){ $this->_retvalue = yy('Parens', $this->yystack[$this->yyidx + -1]->minor); } +#line 2874 "/var/www/coffeescript-php/grammar.php" +#line 207 "/var/www/coffeescript-php/grammar.y" + function yy_r132(){ $this->_retvalue = yy('Parens', $this->yystack[$this->yyidx + -2]->minor); } +#line 2877 "/var/www/coffeescript-php/grammar.php" +#line 209 "/var/www/coffeescript-php/grammar.y" + function yy_r133(){ $this->_retvalue = yy('While', $this->yystack[$this->yyidx + 0]->minor); } +#line 2880 "/var/www/coffeescript-php/grammar.php" +#line 210 "/var/www/coffeescript-php/grammar.y" + function yy_r134(){ $this->_retvalue = yy('While', $this->yystack[$this->yyidx + -2]->minor, array('guard' => $this->yystack[$this->yyidx + 0]->minor)); } +#line 2883 "/var/www/coffeescript-php/grammar.php" +#line 211 "/var/www/coffeescript-php/grammar.y" + function yy_r135(){ $this->_retvalue = yy('While', $this->yystack[$this->yyidx + 0]->minor, array('invert' => TRUE)); } +#line 2886 "/var/www/coffeescript-php/grammar.php" +#line 212 "/var/www/coffeescript-php/grammar.y" + function yy_r136(){ $this->_retvalue = yy('While', $this->yystack[$this->yyidx + -2]->minor, array('invert' => TRUE, 'guard' => $this->yystack[$this->yyidx + 0]->minor)); } +#line 2889 "/var/www/coffeescript-php/grammar.php" +#line 214 "/var/www/coffeescript-php/grammar.y" + function yy_r137(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor->add_body($this->yystack[$this->yyidx + 0]->minor); } +#line 2892 "/var/www/coffeescript-php/grammar.php" +#line 215 "/var/www/coffeescript-php/grammar.y" + function yy_r138(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor->add_body(yy_Block::wrap(array($this->yystack[$this->yyidx + -1]->minor))); } +#line 2895 "/var/www/coffeescript-php/grammar.php" +#line 219 "/var/www/coffeescript-php/grammar.y" + function yy_r141(){ $this->_retvalue = yy('While', yy('Literal', 'true')); $this->_retvalue->add_body($this->yystack[$this->yyidx + 0]->minor); } +#line 2898 "/var/www/coffeescript-php/grammar.php" +#line 220 "/var/www/coffeescript-php/grammar.y" + function yy_r142(){ $this->_retvalue = yy('While', yy('Literal', 'true')); $this->_retvalue->add_body(yy_Block::wrap($this->yystack[$this->yyidx + 0]->minor)); } +#line 2901 "/var/www/coffeescript-php/grammar.php" +#line 222 "/var/www/coffeescript-php/grammar.y" + function yy_r143(){ $this->_retvalue = yy('For', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2904 "/var/www/coffeescript-php/grammar.php" +#line 224 "/var/www/coffeescript-php/grammar.y" + function yy_r145(){ $this->_retvalue = yy('For', $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2907 "/var/www/coffeescript-php/grammar.php" +#line 226 "/var/www/coffeescript-php/grammar.y" + function yy_r146(){ $this->_retvalue = array('source' => yy('Value', $this->yystack[$this->yyidx + 0]->minor)); } +#line 2910 "/var/www/coffeescript-php/grammar.php" +#line 227 "/var/www/coffeescript-php/grammar.y" + function yy_r147(){ $this->yystack[$this->yyidx + 0]->minor['own'] = isset($this->yystack[$this->yyidx + -1]->minor['own']) ? $this->yystack[$this->yyidx + -1]->minor['own'] : NULL; $this->yystack[$this->yyidx + 0]->minor['name'] = $this->yystack[$this->yyidx + -1]->minor[0]; $this->yystack[$this->yyidx + 0]->minor['index'] = isset($this->yystack[$this->yyidx + -1]->minor[1]) ? $this->yystack[$this->yyidx + -1]->minor[1] : NULL; $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 2913 "/var/www/coffeescript-php/grammar.php" +#line 230 "/var/www/coffeescript-php/grammar.y" + function yy_r149(){ $this->yystack[$this->yyidx + 0]->minor['own'] = TRUE; $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 2916 "/var/www/coffeescript-php/grammar.php" +#line 239 "/var/www/coffeescript-php/grammar.y" + function yy_r155(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + 0]->minor); } +#line 2919 "/var/www/coffeescript-php/grammar.php" +#line 240 "/var/www/coffeescript-php/grammar.y" + function yy_r156(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + 0]->minor, 'object' => TRUE); } +#line 2922 "/var/www/coffeescript-php/grammar.php" +#line 241 "/var/www/coffeescript-php/grammar.y" + function yy_r157(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + -2]->minor, 'guard' => $this->yystack[$this->yyidx + 0]->minor); } +#line 2925 "/var/www/coffeescript-php/grammar.php" +#line 242 "/var/www/coffeescript-php/grammar.y" + function yy_r158(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + -2]->minor, 'guard' => $this->yystack[$this->yyidx + 0]->minor, 'object' => TRUE); } +#line 2928 "/var/www/coffeescript-php/grammar.php" +#line 243 "/var/www/coffeescript-php/grammar.y" + function yy_r159(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + -2]->minor, 'step' => $this->yystack[$this->yyidx + 0]->minor); } +#line 2931 "/var/www/coffeescript-php/grammar.php" +#line 244 "/var/www/coffeescript-php/grammar.y" + function yy_r160(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + -4]->minor, 'guard' => $this->yystack[$this->yyidx + -2]->minor, 'step' => $this->yystack[$this->yyidx + 0]->minor); } +#line 2934 "/var/www/coffeescript-php/grammar.php" +#line 245 "/var/www/coffeescript-php/grammar.y" + function yy_r161(){ $this->_retvalue = array('source' => $this->yystack[$this->yyidx + -4]->minor, 'step' => $this->yystack[$this->yyidx + -2]->minor, 'guard' => $this->yystack[$this->yyidx + 0]->minor); } +#line 2937 "/var/www/coffeescript-php/grammar.php" +#line 247 "/var/www/coffeescript-php/grammar.y" + function yy_r162(){ $this->_retvalue = yy('Switch', $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2940 "/var/www/coffeescript-php/grammar.php" +#line 248 "/var/www/coffeescript-php/grammar.y" + function yy_r163(){ $this->_retvalue = yy('Switch', $this->yystack[$this->yyidx + -5]->minor, $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2943 "/var/www/coffeescript-php/grammar.php" +#line 249 "/var/www/coffeescript-php/grammar.y" + function yy_r164(){ $this->_retvalue = yy('Switch', NULL, $this->yystack[$this->yyidx + -1]->minor); } +#line 2946 "/var/www/coffeescript-php/grammar.php" +#line 250 "/var/www/coffeescript-php/grammar.y" + function yy_r165(){ $this->_retvalue = yy('Switch', NULL, $this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2949 "/var/www/coffeescript-php/grammar.php" +#line 253 "/var/www/coffeescript-php/grammar.y" + function yy_r167(){ $this->_retvalue = array_merge($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2952 "/var/www/coffeescript-php/grammar.php" +#line 255 "/var/www/coffeescript-php/grammar.y" + function yy_r168(){ $this->_retvalue = array(array($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor)); } +#line 2955 "/var/www/coffeescript-php/grammar.php" +#line 256 "/var/www/coffeescript-php/grammar.y" + function yy_r169(){ $this->_retvalue = array(array($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor)); } +#line 2958 "/var/www/coffeescript-php/grammar.php" +#line 258 "/var/www/coffeescript-php/grammar.y" + function yy_r170(){ $this->_retvalue = yy('If', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor, array('type' => $this->yystack[$this->yyidx + -2]->minor)); } +#line 2961 "/var/www/coffeescript-php/grammar.php" +#line 259 "/var/www/coffeescript-php/grammar.y" + function yy_r171(){ $this->_retvalue = $this->yystack[$this->yyidx + -4]->minor->add_else(yy('If', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor, array('type' => $this->yystack[$this->yyidx + -2]->minor))); } +#line 2964 "/var/www/coffeescript-php/grammar.php" +#line 262 "/var/www/coffeescript-php/grammar.y" + function yy_r173(){ $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor->add_else($this->yystack[$this->yyidx + 0]->minor); } +#line 2967 "/var/www/coffeescript-php/grammar.php" +#line 263 "/var/www/coffeescript-php/grammar.y" + function yy_r174(){ $this->_retvalue = yy('If', $this->yystack[$this->yyidx + 0]->minor, yy_Block::wrap(array($this->yystack[$this->yyidx + -2]->minor)), array('type' => $this->yystack[$this->yyidx + -1]->minor, 'statement' => TRUE)); } +#line 2970 "/var/www/coffeescript-php/grammar.php" +#line 266 "/var/www/coffeescript-php/grammar.y" + function yy_r176(){ $this->_retvalue = yy('Op', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2973 "/var/www/coffeescript-php/grammar.php" +#line 267 "/var/www/coffeescript-php/grammar.y" + function yy_r177(){ $this->_retvalue = yy('Op', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); /* prec: 'UNARY'; */ } +#line 2976 "/var/www/coffeescript-php/grammar.php" +#line 271 "/var/www/coffeescript-php/grammar.y" + function yy_r181(){ $this->_retvalue = yy('Op', $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, NULL, TRUE); } +#line 2979 "/var/www/coffeescript-php/grammar.php" +#line 273 "/var/www/coffeescript-php/grammar.y" + function yy_r183(){ $this->_retvalue = yy('Existence', $this->yystack[$this->yyidx + -1]->minor); } +#line 2982 "/var/www/coffeescript-php/grammar.php" +#line 274 "/var/www/coffeescript-php/grammar.y" + function yy_r184(){ $this->_retvalue = yy('Op', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2985 "/var/www/coffeescript-php/grammar.php" +#line 280 "/var/www/coffeescript-php/grammar.y" + function yy_r190(){ if ($this->yystack[$this->yyidx + -1]->minor{0} === '!') { $this->_retvalue = yy('Op', substr($this->yystack[$this->yyidx + -1]->minor, 1), $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); $this->_retvalue->invert(); } else { $this->_retvalue = yy('Op', $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } } +#line 2988 "/var/www/coffeescript-php/grammar.php" +#line 281 "/var/www/coffeescript-php/grammar.y" + function yy_r191(){ $this->_retvalue = yy('Assign', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 2991 "/var/www/coffeescript-php/grammar.php" +#line 282 "/var/www/coffeescript-php/grammar.y" + function yy_r192(){ $this->_retvalue = yy('Assign', $this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -3]->minor); } +#line 2994 "/var/www/coffeescript-php/grammar.php" +#line 283 "/var/www/coffeescript-php/grammar.y" + function yy_r193(){ $this->_retvalue = yy('Extends', $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 2997 "/var/www/coffeescript-php/grammar.php" + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + * <pre> + * rule(A) ::= B. { A = 1; } + * </pre> + * + * The parser will translate to something like: + * + * <code> + * function yy_r0(){$this->_retvalue = 1;} + * </code> + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + * <pre> + * A ::= B blah C. { dosomething(); } + * </pre> + * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //yyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for ($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new yyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +#line 4 "/var/www/coffeescript-php/grammar.y" + + throw new SyntaxError( + 'unexpected '.$this->tokenName($yymajor).' in '.self::$FILE.':' + . (self::$LINE + 1).'.' + ); +#line 3116 "/var/www/coffeescript-php/grammar.php" + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int $yymajor the token number + * @param mixed $yytokenvalue the token value + * @param mixed ... any extra arguments that should be passed to handlers + * + * @return void + */ + function parse($token) + { + list($yymajor, $yytokenvalue, ) = $token ? $token : array(0, 0); + self::$LINE = isset($token[2]) ? $token[2] : -1; + + // See rewriter.php\add_implicit_braces() and grammar.y. + $generated = isset($token['generatedValue']) ? $token['generatedValue'] : FALSE; + +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new yyStackEntry; + $x->stateno = 0; + $x->major = 0; + $x->generated = FALSE; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf( + self::$yyTraceFILE, + "%sInput %s\n", + self::$yyTracePrompt, + self::tokenName($yymajor) + ); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL + && !$this->yy_is_expected_token($yymajor) + ) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue, $generated); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf( + self::$yyTraceFILE, + "%sSyntax Error!\n", + self::$yyTracePrompt + ); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ) { + if (self::$yyTraceFILE) { + fprintf( + self::$yyTraceFILE, + "%sDiscard input token %s\n", + self::$yyTracePrompt, + self::tokenName($yymajor) + ); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 + && $yymx != self::YYERRORSYMBOL + && ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ) { + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2, $generated); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + + if ($token === NULL) + { + return $this->_retvalue; + } + } +} diff --git a/vas/rest/class/vmlib/coffeescript/classes/rewriter.php b/vas/rest/class/vmlib/coffeescript/classes/rewriter.php new file mode 100755 index 0000000000000000000000000000000000000000..bcffa235dca70c012e707e881bb5311d27038cba --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/rewriter.php @@ -0,0 +1,641 @@ +<?php + +namespace CoffeeScript; + +class Rewriter +{ + static $BALANCED_PAIRS = array( + array('(', ')'), + array('[', ']'), + array('{', '}'), + array('INDENT', 'OUTDENT'), + array('CALL_START', 'CALL_END'), + array('PARAM_START', 'PARAM_END'), + array('INDEX_START', 'INDEX_END'), + ); + + static $INVERSES = array(); + + static $EXPRESSION_START = array(); + static $EXPRESSION_END = array(); + + static $EXPRESSION_CLOSE = array('CATCH', 'WHEN', 'ELSE', 'FINALLY'); + + static $IMPLICIT_FUNC = array('IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'); + + static $IMPLICIT_CALL = array( + 'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', + 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER', + '@', '->', '=>', '[', '(', '{', '--', '++' + ); + + static $IMPLICIT_UNSPACED_CALL = array('+', '-'); + + static $IMPLICIT_BLOCK = array('->', '=>', '{', '[', ','); + + static $IMPLICIT_END = array('POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'); + + static $SINGLE_LINERS = array('ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'); + static $SINGLE_CLOSERS = array('TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'); + + static $LINEBREAKS = array('TERMINATOR', 'INDENT', 'OUTDENT'); + + function __construct($tokens) + { + $this->tokens = $tokens; + } + + function add_implicit_braces() + { + $stack = array(); + $start = NULL; + $start_indent = 0; + + $self = $this; + + $condition = function( & $token, $i) use ( & $self) + { + $list = array(); + + for ($j = 0; $j < 3; $j++) + { + $k = ($i + 1) + $j; + $list[$j] = isset($self->tokens[$k]) ? $self->tokens[$k] : array(NULL, NULL); + } + + list($one, $two, $three) = $list; + + if ($one[0] === t('HERECOMMENT')) + { + return FALSE; + } + + $tag = $token[0]; + + return + (in_array($tag, t('TERMINATOR', 'OUTDENT')) && + ! ($two[0] === t(':') || $one[0] === t('@') && $three[0] === t(':')) ) || + ($tag === t(',') && ! is_null($one[0]) && + ! in_array($one[0], t('IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'))); + }; + + $action = function( & $token, $i) use ( & $self) + { + $tok = array(t('}'), '}', $token[2], 'generated' => TRUE); + array_splice($self->tokens, $i, 0, array($tok)); + }; + + $this->scan_tokens(function( & $token, $i, & $tokens) use ( & $self, & $stack, & $start, & $start_indent, & $condition, & $action) + { + if (in_array(($tag = $token[0]), t(Rewriter::$EXPRESSION_START))) + { + $stack[] = array( ($tag === t('INDENT') && $self->tag($i - 1) === t('{')) ? t('{') : $tag, $i ); + return 1; + } + + if (in_array($tag, t(Rewriter::$EXPRESSION_END))) + { + $start = array_pop($stack); + return 1; + } + + $len = count($stack) - 1; + + if ( ! ($tag === t(':') && (($ago = $self->tag($i - 2)) === t(':') || ( ! isset($stack[$len]) || $stack[$len][0] !== t('{'))) )) + { + return 1; + } + + $stack[] = array(t('{')); + $idx = $ago === t('@') ? $i - 2 : $i - 1; + + while ($self->tag($idx - 2) === t('HERECOMMENT')) + { + $idx -= 2; + } + + // This doesn't really work in PHP, so we assign 'generatedValue' to the + // token and handle it in the actual parser (see Lempar.php\Parser\ + // parse()). This is pretty hacky, but it works. (Maybe...) + // + // TODO: In the future change this to use the wrap() function as it seems + // to work without any problems. + + $value = wrap('{'); + $value->generated = TRUE; + + $tok = array(t('{'), $value, $token[2], 'generated' => TRUE, 'generatedValue' => TRUE); + + array_splice($tokens, $idx, 0, array($tok)); + + $self->detect_end($i + 2, $condition, $action); + + return 2; + }); + } + + function add_implicit_indentation() + { + $self = $this; + + $this->scan_tokens(function( & $token, $i, & $tokens) use ( & $self) + { + $tag = $token[0]; + + if ($tag === t('TERMINATOR') && $self->tag($i + 1) === t('THEN')) + { + array_splice($tokens, $i, 1); + return 0; + } + + if ($tag === t('ELSE') && $self->tag($i - 1) !== t('OUTDENT')) + { + array_splice($tokens, $i, 0, $self->indentation($token)); + return 2; + } + + if ($tag === t('CATCH') && in_array($self->tag($i + 2), t('OUTDENT', 'TERMINATOR', 'FINALLY'))) + { + array_splice($tokens, $i + 2, 0, $self->indentation($token)); + return 4; + } + + if (in_array($tag, t(Rewriter::$SINGLE_LINERS)) && $self->tag($i + 1) !== t('INDENT') && + ! ($tag === t('ELSE') && $self->tag($i + 1) === t('IF'))) + { + $starter = $tag; + list($indent, $outdent) = $self->indentation($token); + + if ($starter === t('THEN')) + { + $indent['fromThen'] = TRUE; + } + + $indent['generated'] = $outdent['generated'] = TRUE; + + array_splice($tokens, $i + 1, 0, array($indent)); + + $condition = function($token, $i) use ($starter) + { + return $token[1] !== ';' && in_array($token[0], t(Rewriter::$SINGLE_CLOSERS)) && + ! ($token[0] === t('ELSE') && ! in_array($starter, t('IF', 'THEN'))); + }; + + $action = function( & $token, $i) use ( & $self, $outdent) + { + array_splice($self->tokens, ($self->tag($i - 1) === t(',') ? $i - 1 : $i), 0, array($outdent)); + }; + + $self->detect_end($i + 2, $condition, $action); + + if ($tag === t('THEN')) + { + array_splice($tokens, $i, 1); + } + + return 1; + } + + return 1; + }); + } + + function add_implicit_parentheses() + { + $no_call = FALSE; + $self = $this; + + $action = function( & $token, $i) use ( & $self) + { + $idx = ($token[0] === t('OUTDENT')) ? $i + 1 : $i; + $tok = array(t('CALL_END'), ')'); + + if (isset($token[2])) + { + $tok[2] = $token[2]; + } + + array_splice($self->tokens, $idx, 0, array($tok)); + }; + + $this->scan_tokens(function( & $token, $i, & $tokens) use ( & $action, & $no_call, & $self ) + { + $tag = $token[0]; + + if (in_array($tag, t('CLASS', 'IF'))) + { + $no_call = TRUE; + } + + $prev = NULL; + + if (isset($tokens[$i - 1])) + { + $prev = & $tokens[$i - 1]; + } + + $current = $tokens[$i]; + $next = isset($tokens[$i + 1]) ? $tokens[$i + 1] : NULL; + + $call_object = ! $no_call && $tag === t('INDENT') && + $next && (isset($next['generated']) && $next['generated']) && $next[0] === t('{') && + $prev && in_array($prev[0], t(Rewriter::$IMPLICIT_FUNC)); + + $seen_single = FALSE; + $seen_control = FALSE; + + if (in_array($tag, t(Rewriter::$LINEBREAKS))) + { + $no_call = FALSE; + } + + if ($prev && ! (isset($prev['spaced']) && $prev['spaced']) && $tag === t('?')) + { + $token['call'] = TRUE; + } + + if (isset($token['fromThen']) && $token['fromThen']) + { + return 1; + } + + if ( ! ($call_object || ($prev && (isset($prev['spaced']) && $prev['spaced'])) && + ( (isset($prev['call']) && $prev['call']) || in_array($prev[0], t(Rewriter::$IMPLICIT_FUNC)) ) && + ( in_array($tag, t(Rewriter::$IMPLICIT_CALL)) || ! ( (isset($token['spaced']) && $token['spaced']) || + (isset($token['newLine']) && $token['newLine']) ) && + in_array($tag, t(Rewriter::$IMPLICIT_UNSPACED_CALL)) ) + )) + { + return 1; + } + + array_splice($tokens, $i, 0, array(array(t('CALL_START'), '(', $token[2]))); + + $self->detect_end($i + 1, function($token, $i) use ( & $seen_control, & $seen_single, & $self) + { + $tag = $token[0]; + + if ( ! $seen_single && (isset($token['fromThen']) && $token['fromThen'])) + { + return TRUE; + } + + if (in_array($tag, t('IF', 'ELSE', '->', '=>'))) + { + $seen_single = TRUE; + } + + if (in_array($tag, t('IF', 'ELSE', 'SWITCH', 'TRY'))) + { + $seen_control = TRUE; + } + + if (in_array($tag, t('.', '?.', '::')) && $self->tag($i - 1) === t('OUTDENT')) + { + return TRUE; + } + + return + ! (isset($token['generated']) && $token['generated']) && $self->tag($i - 1) !== t(',') && + (in_array($tag, t(Rewriter::$IMPLICIT_END))) && + ($tag !== t('INDENT') || + ( $self->tag($i - 2) !== t('CLASS') && + ! in_array($self->tag($i - 1), t(Rewriter::$IMPLICIT_BLOCK)) && + ! ( (isset($self->tokens[$i + 1]) && ($post = $self->tokens[$i + 1])) && + (isset($post['generated']) && $post['generated']) && $post[0] === t('{') ) + )); + }, + $action); + + if ($prev[0] === t('?')) + { + $prev[0] = t('FUNC_EXIST'); + } + + return 2; + }); + } + + function close_open_calls() + { + $self = $this; + + $condition = function($token, $i) use ( & $self) + { + return in_array($token[0], t(')', 'CALL_END')) || $token[0] === t('OUTDENT') && + $self->tag($i - 1) === t(')'); + }; + + $action = function($token, $i) use ( & $self) + { + $self->tokens[($token[0] === t('OUTDENT') ? $i - 1 : $i)][0] = t('CALL_END'); + }; + + $this->scan_tokens(function($token, $i) use ( & $self, $condition, $action) + { + if ($token[0] === t('CALL_START')) + { + $self->detect_end($i + 1, $condition, $action); + } + + return 1; + }); + } + + function close_open_indexes() + { + $condition = function($token, $i) + { + return in_array($token[0], t(']', 'INDEX_END')); + }; + + $action = function( & $token, $i) + { + $token[0] = t('INDEX_END'); + }; + + $self = $this; + + $this->scan_tokens(function($token, $i) use ( & $self, $condition, $action) + { + if ($token[0] === t('INDEX_START')) + { + $self->detect_end($i + 1, $condition, $action); + } + + return 1; + }); + } + + function detect_end($i, $condition, $action) + { + $tokens = & $this->tokens; + $levels = 0; + + while (isset($tokens[$i])) + { + $token = & $tokens[$i]; + + if ($levels === 0 && $condition($token, $i)) + { + return $action($token, $i); + } + + if ( ! $token || $levels < 0) + { + return $action($token, $i - 1); + } + + if (in_array($token[0], t(Rewriter::$EXPRESSION_START))) + { + $levels++; + } + else if (in_array($token[0], t(Rewriter::$EXPRESSION_END))) + { + $levels--; + } + + $i++; + } + + return $i - 1; + } + + function ensure_balance($pairs) + { + $levels = array(); + $open_line = array(); + + foreach ($this->tokens as $token) + { + $tag = $token[0]; + + foreach ($pairs as $pair) + { + list($open, $close) = $pair; + + if ( ! isset($levels[$open])) + { + $levels[$open] = 0; + } + + if ($tag === t($open)) + { + if ($levels[$open]++ === 0) + { + $open_line[$open] = $token[2]; + } + } + else if ($tag === t($close) && --$levels[$open] < 0) + { + throw new Error('too many '.$token[1].' on line '.($token[2] + 1)); + } + } + } + + foreach ($levels as $open => $level) + { + if ($level > 0) + { + throw new Error('unclosed '.$open.' on line '.($open_line[$open] + 1)); + } + } + + return $this; + } + + function indentation($token) + { + return array( array(t('INDENT'), 2, $token[2]), array(t('OUTDENT'), 2, $token[2]) ); + } + + static function init() + { + foreach (self::$BALANCED_PAIRS as $pair) + { + list($left, $rite) = $pair; + + self::$EXPRESSION_START[] = self::$INVERSES[$rite] = $left; + self::$EXPRESSION_END[] = self::$INVERSES[$left] = $rite; + } + + self::$EXPRESSION_CLOSE = array_merge(self::$EXPRESSION_CLOSE, self::$EXPRESSION_END); + } + + function remove_leading_newlines() + { + $key = 0; + + foreach ($this->tokens as $k => $token) + { + $key = $k; + $tag = $token[0]; + + if ($tag !== t('TERMINATOR')) + { + break; + } + } + + if ($key) + { + array_splice($this->tokens, 0, $key); + } + } + + function remove_mid_expression_newlines() + { + $self = $this; + + $this->scan_tokens(function( & $token, $i, & $tokens) use ( & $self) + { + if ( ! ($token[0] === t('TERMINATOR') && in_array($self->tag($i + 1), t(Rewriter::$EXPRESSION_CLOSE)))) + { + return 1; + } + + array_splice($tokens, $i, 1); + return 0; + }); + } + + function rewrite() + { + $this->remove_leading_newlines(); + $this->remove_mid_expression_newlines(); + $this->close_open_calls(); + $this->close_open_indexes(); + $this->add_implicit_indentation(); + $this->tag_postfix_conditionals(); + $this->add_implicit_braces(); + $this->add_implicit_parentheses(); + //$this->ensure_balance(self::$BALANCED_PAIRS); + $this->rewrite_closing_parens(); + + return $this->tokens; + } + + function rewrite_closing_parens() + { + $stack = array(); + $debt = array(); + + // Need to change to an associative array of numeric constants, rather + // than the string names. + $inverses = array(); + + foreach (Rewriter::$INVERSES as $k => $v) + { + $inverses[t($k)] = $v; + } + + foreach ($inverses as $k => $v) + { + $debt[$k] = 0; + } + + $self = $this; + + $this->scan_tokens(function( & $token, $i, & $tokens) use ( & $self, & $stack, & $debt, $inverses) + { + if (in_array(($tag = $token[0]), t(Rewriter::$EXPRESSION_START))) + { + $stack[] = $token; + return 1; + } + + if ( ! (in_array($tag, t(Rewriter::$EXPRESSION_END)))) + { + return 1; + } + + if ($debt[ ($inv = t($inverses[$tag])) ] > 0) + { + $debt[$inv]--; + array_splice($tokens, $i, 1); + return 0; + } + + $match = array_pop($stack); + $mtag = $match[0]; + $oppos = $inverses[$mtag]; + + if ($tag === t($oppos)) + { + return 1; + } + + $debt[$mtag]++; + + $val = array(t($oppos), $mtag === t('INDENT') ? $match[1] : $oppos); + + //if ($oppos === 'INDEX_END') + //{ + // $val[1] = ']'; + //} + + if ($self->tag($i + 2) === $mtag) + { + array_splice($tokens, $i + 3, 0, array($val)); + $stack[] = $match; + } + else + { + array_splice($tokens, $i, 0, array($val)); + } + + return 1; + }); + } + + function scan_tokens($block) + { + $i = 0; + + while (isset($this->tokens[$i])) + { + $i += $block($this->tokens[$i], $i, $this->tokens); + } + + return TRUE; + } + + function tag($i) + { + return isset($this->tokens[$i]) ? $this->tokens[$i][0] : NULL; + } + + function tag_postfix_conditionals() + { + $condition = function($token, $i) + { + return in_array($token[0], t('TERMINATOR', 'INDENT')); + }; + + $self = $this; + + $this->scan_tokens(function( & $token, $i) use ( & $condition, & $self) + { + if ( ! ($token[0] === t('IF'))) + { + return 1; + } + + $original = & $token; + + $self->detect_end($i + 1, $condition, function($token, $i) use ( & $original) + { + if ($token[0] !== t('INDENT')) + { + $original[0] = t('POST_IF'); // 'POST_'.$original[0]; + } + }); + + return 1; + }); + } +} + +Rewriter::init(); + +?> diff --git a/vas/rest/class/vmlib/coffeescript/classes/scope.php b/vas/rest/class/vmlib/coffeescript/classes/scope.php new file mode 100755 index 0000000000000000000000000000000000000000..abfbff6f9bce730245dcd28127f2400db04f4440 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/classes/scope.php @@ -0,0 +1,189 @@ +<?php + +namespace CoffeeScript; + +require_once 'helpers.php'; + +/** + * Lexical scope manager. + */ +class Scope +{ + static $root = NULL; + + public $shared = FALSE; + private $has_assignments = FALSE; + + function __construct($parent, $expressions, $method) + { + $this->parent = $parent; + $this->expressions = $expressions; + $this->method = $method; + + $this->variables = array( + array('name' => 'arguments', 'type' => 'arguments') + ); + + $this->positions = array(); + + if ( ! $this->parent) + { + self::$root = $this; + } + } + + function add($name, $type, $immediate = FALSE) + { + if ($this->shared && ! $immediate) + { + return $this->parent->add($name, $type, $immediate); + } + + if (isset($this->positions[$name]) && is_numeric($pos = $this->positions[$name])) + { + $this->variables[$pos]['type'] = $type; + } + else + { + $this->variables[] = array('name' => $name, 'type' => $type); + $this->positions[$name] = count($this->variables) - 1; + } + } + + function assign($name, $value) + { + $this->add($name, array('value' => $value, 'assigned' => TRUE)); + $this->has_assignments = TRUE; + } + + function assigned_variables() + { + $tmp = array(); + + foreach ($this->variables as $v) + { + $type = $v['type']; + + if (is_array($type) && isset($type['assigned']) && $type['assigned']) + { + $tmp[] = "{$v['name']} = {$v['type']['value']}"; + } + } + + return $tmp; + } + + function check($name, $immediate = FALSE) + { + $found = !! $this->type($name); + + if ($found || $immediate) + { + return $found; + } + + return $this->parent ? $this->parent->check($name) : FALSE; + } + + function declared_variables() + { + $real_vars = array(); + $temp_vars = array(); + + foreach ($this->variables as $v) + { + if ($v['type'] === 'var') + { + if ($v['name']{0} === '_') + { + $temp_vars[] = $v['name']; + } + else + { + $real_vars[] = $v['name']; + } + } + } + + asort($real_vars); + asort($temp_vars); + + return array_merge($real_vars, $temp_vars); + } + + function find($name, $options = array()) + { + if ($this->check($name, $options)) + { + return TRUE; + } + + $this->add($name, 'var'); + + return FALSE; + } + + function free_variable($type) + { + $index = 0; + + while ($this->check(($temp = $this->temporary($type, $index)))) + { + $index++; + } + + $this->add($temp, 'var', TRUE); + + return $temp; + } + + function has_assignments() + { + return $this->has_assignments; + } + + function has_declarations() + { + return !! count($this->declared_variables()); + } + + function parameter($name) + { + if ($this->shared && $this->parent->check($name, TRUE)) + { + return; + } + + $this->add($name, 'param'); + } + + function temporary($name, $index) + { + if (strlen($name) > 1) + { + return '_'.$name.($index > 1 ? $index : ''); + } + else + { + $val = strval(base_convert($index + intval($name, 36), 10, 36)); + $val = preg_replace('/\d/', 'a', $val); + + return '_'.$val; + } + } + + function type($name) + { + foreach ($this->variables as $v) + { + if ($v['name'] === $name) + { + return $v['type']; + } + } + + return NULL; + } +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/coffeescript.php b/vas/rest/class/vmlib/coffeescript/coffeescript.php new file mode 100755 index 0000000000000000000000000000000000000000..bbfd970583f5a0312ff284d9436df2a33f4106fb --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/coffeescript.php @@ -0,0 +1,37 @@ +<?php +namespace CoffeeScript; + +require_once 'classes/lexer.php'; +require_once 'classes/parser.php'; + +/** + * Compile some CoffeeScript. + * + * @param $code The source CoffeeScript code. + * @param $options Compiler options. + */ +function compile($code, $options = array(), & $tokens = NULL) +{ + $lexer = new Lexer($code, $options); + + if (isset($options['file'])) + { + Parser::$FILE = $options['file']; + } + + if (isset($options['trace'])) + { + Parser::Trace(fopen($options['trace'], 'w', TRUE), '> '); + } + + $parser = new Parser(); + + foreach (($tokens = $lexer->tokenize()) as $token) + { + $parser->parse($token); + } + + return $parser->parse(NULL)->compile($options); +} + +?> diff --git a/vas/rest/class/vmlib/coffeescript/jsmaker.php b/vas/rest/class/vmlib/coffeescript/jsmaker.php new file mode 100755 index 0000000000000000000000000000000000000000..3b912e88d8f399bf07fa7dc0b6a005b9283a0352 --- /dev/null +++ b/vas/rest/class/vmlib/coffeescript/jsmaker.php @@ -0,0 +1,16 @@ +<?php +ini_set('display_errors', 1); +error_reporting(0); +header('Content-Type: application/javascript', true); +if(isset($_GET['f'])) +{ + include 'class.jstocoffee.php'; + $JsToCoffee = new JsToCoffee; + $JsToCoffee->setCacheDir(__DIR__ . '/cache/'); + $JsToCoffee->setAllowedCoffeeDir(__DIR__ . '/../../coffee/'); + echo $JsToCoffee->makeJavascript($_GET['f']); +} +else +{ + echo ''; +} \ No newline at end of file diff --git a/vas/rest/class/vmlib/context/covage.inc b/vas/rest/class/vmlib/context/covage.inc new file mode 100755 index 0000000000000000000000000000000000000000..54b6488302765982cf7a23a5b194e54df5c75435 --- /dev/null +++ b/vas/rest/class/vmlib/context/covage.inc @@ -0,0 +1,12 @@ +<?php + +// Corps du message +$properties['businessobject.bo_id']['value'] = $this->aObjects["oBusinessObject"]->get('bo_id'); +$properties['businessobject.bo_id']['fr'] = "Corps du message"; +$properties['businessobject.bo_id']['en'] = "Corps du message"; + +// Nom du demandeur +$properties['businessobject.user.name']['value'] = $this->aObjects["oBusinessObject"]->getUser('admin_framework')->aFields['name']; +$properties['businessobject.user.name']['fr'] = "Nom du demandeur"; +$properties['businessobject.user.name']['en'] = "Nom du demandeur"; +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/context/gtf.inc b/vas/rest/class/vmlib/context/gtf.inc new file mode 100755 index 0000000000000000000000000000000000000000..9239727b5b7b8024574f52119230100f8d83b66f --- /dev/null +++ b/vas/rest/class/vmlib/context/gtf.inc @@ -0,0 +1,62 @@ +<?php + +// Adresse email du demandeur +$properties['order.user.email']['value'] = $this->aObjects["oOrder"]->getUser()->aFields['email']; +$properties['order.user.email']['fr'] = "Adresse email du demandeur"; +$properties['order.user.email']['en'] = "Adresse email du demandeur"; + +// Nom du demandeur du traitement +$properties['order.user.name']['value'] = $this->aObjects["oOrder"]->getUser()->aFields['name']; +$properties['order.user.name']['fr'] = "Nom du demandeur du traitement"; +$properties['order.user.name']['en'] = "Nom du demandeur du traitement"; + +// Compte de connexion du demandeur du traitement +$properties['order.user.login']['value'] = $this->aObjects["oOrder"]->getUser()->aFields['login']; +$properties['order.user.login']['fr'] = "Compte du demandeur du traitement"; +$properties['order.user.login']['en'] = "Compte du demandeur du traitement"; + +// Date et heure de la demande +$properties['order.order_date']['value'] = $this->aObjects["oOrder"]->aFields['order_date']; +$properties['order.order_date']['fr'] = "Date et heure de la demande de traitement"; +$properties['order.order_date']['en'] = "Date et heure de la demande de traitement"; + +// Url de téléchargement du résultat +$properties['order.result_url']['value'] = $this->aObjects["oOrder"]->aFields['result_url']; +$properties['order.result_url']['fr'] = "Url de téléchargement du résultat"; +$properties['order.result_url']['en'] = "Url de téléchargement du résultat"; + +// Url de téléchargement du log +$properties['order.log_url']['value'] = $this->aObjects["oOrder"]->aFields['log_url']; +$properties['order.log_url']['fr'] = "Url de téléchargement du fichier de log"; +$properties['order.log_url']['en'] = "Url de téléchargement du fichier de log"; + +// Identifiant de la demande de traitement +$properties['order.order_id']['value'] = $this->aObjects["oOrder"]->aFields['order_id']; +$properties['order.order_id']['fr'] = "Identifiant de la demande de traitement"; +$properties['order.order_id']['en'] = "Identifiant de la demande de traitement"; + +// Nom du traitement +$properties['order.workspace.name']['value'] = $this->aObjects["oOrder"]->getWorkspace()->aFields['name']; +$properties['order.workspace.name']['fr'] = "Nom du traitement"; +$properties['order.workspace.name']['en'] = "Nom du traitement"; + +// Catégorie du traitement +$properties['order.workspace.category.name']['value'] = $this->aObjects["oOrder"]->getWorkspace()->getCategory()->aFields['name']; +$properties['order.workspace.category.name']['fr'] = "Catégorie du traitement"; +$properties['order.workspace.category.name']['en'] = "Catégorie du traitement"; + +// Durée du traitement +$properties['order.length_sec']['value'] = $this->aObjects["oOrder"]->aFields['length_sec']; +$properties['order.length_sec']['fr'] = "Durée du traitement en secondes"; +$properties['order.length_sec']['en'] = "Durée du traitement"; + +// Date et heure de fin de traitement +$properties['order.execution_date']['value'] = $this->aObjects["oOrder"]->aFields['execution_date']; +$properties['order.execution_date']['fr'] = "Date et heure de fin de traitement"; +$properties['order.execution_date']['en'] = "Date et heure de fin de traitement"; + +//Adresse mail du destinataire en copie +$properties['order.email_notifications']['value'] = $this->aObjects["oOrder"]->aFields['email_notifications']; +$properties['order.email_notifications']['fr'] = "Adresse email du destinataire en copie du mail"; +$properties['order.email_notifications']['en'] = "Adresse email du destinataire en copie du mail"; +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/context/message.inc b/vas/rest/class/vmlib/context/message.inc new file mode 100755 index 0000000000000000000000000000000000000000..40b060d307ee4c41905e5894938d455cda9c973d --- /dev/null +++ b/vas/rest/class/vmlib/context/message.inc @@ -0,0 +1,12 @@ +<?php + +// Corps du message +$properties['message.email_body']['value'] = $this->aObjects["oMessage"]->getBody('email_body'); +$properties['message.email_body']['fr'] = "Corps du message"; +$properties['message.email_body']['en'] = "Corps du message"; + +// Id de la demande +$properties['message.order_id']['value'] = $this->aObjects["oMessage"]->getBody('order_id'); +$properties['message.order_id']['fr'] = "Id de la demande"; +$properties['message.order_id']['en'] = "Order Id"; +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/cryptUtil.inc b/vas/rest/class/vmlib/cryptUtil.inc new file mode 100755 index 0000000000000000000000000000000000000000..f0cdd11cd1b12efc48ce0b1216c972c4374dfdc4 --- /dev/null +++ b/vas/rest/class/vmlib/cryptUtil.inc @@ -0,0 +1,302 @@ +<?php + +/* + * + * cryptUtil.inc : fonction de Cryptage et decryptage de texte en fonction d'une clef priv�e + * + */ + +//this takes the key, the message, and whether to encrypt or decrypt +function des($key, $message, $encrypt, $mode, $iv = null, $padding = "") { + //declaring this locally speeds things up a bit + $spfunction1 = array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004); + $spfunction2 = array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, -0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, -0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, -0x7fef7fe0, 0x108000); + $spfunction3 = array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200); + $spfunction4 = array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080); + $spfunction5 = array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, 0x40080000, 0x2080100, 0x40000100); + $spfunction6 = array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010); + $spfunction7 = array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002); + $spfunction8 = array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000); + $masks = array(4294967295, 2147483647, 1073741823, 536870911, 268435455, 134217727, 67108863, 33554431, 16777215, 8388607, 4194303, 2097151, 1048575, 524287, 262143, 131071, 65535, 32767, 16383, 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0); + + //create the 16 or 48 subkeys we will need + $keys = des_createKeys($key); + $m = 0; + $len = strlen($message); + $chunk = 0; + //set up the loops for single and triple des + $iterations = ((count($keys) == 32) ? 3 : 9); //single or triple des + if ($iterations == 3) { + $looping = (($encrypt) ? array(0, 32, 2) : array(30, -2, -2)); + } else { + $looping = (($encrypt) ? array(0, 32, 2, 62, 30, -2, 64, 96, 2) : array(94, 62, -2, 32, 64, 2, 30, -2, -2)); + } + + //pad the message depending on the padding parameter + if ($padding == 2) + $message .= " "; //pad the message with spaces + else if ($padding == 1) { + $temp = 8 - ($len % 8); + $message .= chr($temp) . chr($temp) . chr($temp) . chr($temp) . chr($temp) . chr($temp) . chr($temp) . chr($temp); + if ($temp == 8) + $len+=8; + } //PKCS7 padding + else if ($padding == "") + $message .= (chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0)); //pad the message out with null bytes + + +//store the result here + $result = ""; + $tempresult = ""; + + if ($mode == 1) { //CBC mode + $cbcleft = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $cbcright = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $m = 0; + } + + //loop through each 64 bit chunk of the message + while ($m < $len) { + $left = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + $right = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) { + if ($encrypt) { + $left ^= $cbcleft; + $right ^= $cbcright; + } else { + $cbcleft2 = $cbcleft; + $cbcright2 = $cbcright; + $cbcleft = $left; + $cbcright = $right; + } + } + + //first each 64 but chunk of the message must be permuted according to IP + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; + $right ^= $temp; + $left ^= ($temp << 4); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; + $right ^= $temp; + $left ^= ($temp << 16); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; + $left ^= $temp; + $right ^= ($temp << 2); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; + $left ^= $temp; + $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; + $right ^= $temp; + $left ^= ($temp << 1); + + $left = (($left << 1) | ($left >> 31 & $masks[31])); + $right = (($right << 1) | ($right >> 31 & $masks[31])); + + //do this either 1 or 3 times for each chunk of the message + for ($j = 0; $j < $iterations; $j+=3) { + $endloop = $looping[$j + 1]; + $loopinc = $looping[$j + 2]; + //now go through and perform the encryption or decryption + for ($i = $looping[$j]; $i != $endloop; $i+=$loopinc) { //for efficiency + $right1 = $right ^ $keys[$i]; + $right2 = (($right >> 4 & $masks[4]) | ($right << 28 & 0xffffffff)) ^ $keys[$i + 1]; + //the result is attained by passing these bytes through the S selection functions + $temp = $left; + $left = $right; + $right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f] | $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f] | $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f] | $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]); + } + $temp = $left; + $left = $right; + $right = $temp; //unreverse left and right + } //for either 1 or 3 iterations + //move then each one bit to the right + $left = (($left >> 1 & $masks[1]) | ($left << 31)); + $right = (($right >> 1 & $masks[1]) | ($right << 31)); + + //now perform IP-1, which is IP in the opposite direction + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; + $right ^= $temp; + $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; + $left ^= $temp; + $right ^= ($temp << 8); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; + $left ^= $temp; + $right ^= ($temp << 2); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; + $right ^= $temp; + $left ^= ($temp << 16); + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; + $right ^= $temp; + $left ^= ($temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) { + if ($encrypt) { + $cbcleft = $left; + $cbcright = $right; + } else { + $left ^= $cbcleft2; + $right ^= $cbcright2; + } + } + $tempresult .= (chr($left >> 24 & $masks[24]) . chr(($left >> 16 & $masks[16]) & 0xff) . chr(($left >> 8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right >> 24 & $masks[24]) . chr(($right >> 16 & $masks[16]) & 0xff) . chr(($right >> 8 & $masks[8]) & 0xff) . chr($right & 0xff)); + + $chunk += 8; + if ($chunk == 512) { + $result .= $tempresult; + $tempresult = ""; + $chunk = 0; + } + } //for every 8 characters, or 64 bits in the message + //return the result as an array + return ($result . $tempresult); +} + +//end of des +//des_createKeys +//this takes as input a 64 bit key (even though only 56 bits are used) +//as an array of 2 integers, and returns 16 48 bit keys +function des_createKeys($key) { + //declaring this locally speeds things up a bit + $pc2bytes0 = array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204); + $pc2bytes1 = array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101); + $pc2bytes2 = array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808); + $pc2bytes3 = array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000); + $pc2bytes4 = array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, 0x41000, 0x1010, 0x41010); + $pc2bytes5 = array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, 0x2000000, 0x2000400, 0x2000020, 0x2000420); + $pc2bytes6 = array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002); + $pc2bytes7 = array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800); + $pc2bytes8 = array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, 0x2000002, 0x2040002, 0x2000002, 0x2040002); + $pc2bytes9 = array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408); + $pc2bytes10 = array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, 0x102000, 0x102020, 0x102000, 0x102020); + $pc2bytes11 = array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200); + $pc2bytes12 = array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010); + $pc2bytes13 = array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105); + $masks = array(4294967295, 2147483647, 1073741823, 536870911, 268435455, 134217727, 67108863, 33554431, 16777215, 8388607, 4194303, 2097151, 1048575, 524287, 262143, 131071, 65535, 32767, 16383, 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0); + + //how many iterations (1 for des, 3 for triple des) + $iterations = ((strlen($key) > 8) ? 3 : 1); //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + //stores the return keys + $keys = array(); // size = 32 * iterations but you don't specify this in php + //now define the left shifts which need to be done + $shifts = array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + $m = 0; + $n = 0; + + for ($j = 0; $j < $iterations; $j++) { //either 1 or 3 iterations + //$left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + $v = (isset($key{$m})) ? $key{$m} : ''; + $left = (ord($v) << 24); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $left |= (ord($v) << 16); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $left |= (ord($v) << 8); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $left |= ord($v); + $m++; + + //$right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + $v = (isset($key{$m})) ? $key{$m} : ''; + $right = (ord($v) << 24); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $right |= (ord($v) << 16); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $right |= (ord($v) << 8); + $m++; + $v = (isset($key{$m})) ? $key{$m} : ''; + $right |= ord($v); + $m++; + + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; + $right ^= $temp; + $left ^= ($temp << 4); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; + $left ^= $temp; + $right ^= ($temp << 16); + $temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333; + $right ^= $temp; + $left ^= ($temp << 2); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; + $left ^= $temp; + $right ^= ($temp << 16); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; + $right ^= $temp; + $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; + $left ^= $temp; + $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; + $right ^= $temp; + $left ^= ($temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + $temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0); + //left needs to be put upside down + $left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0); + $right = $temp; + + //now go through and perform these shifts on the left and right keys + for ($i = 0; $i < count($shifts); $i++) { + //shift the keys either one or two bits to the left + if ($shifts[$i] > 0) { + $left = (($left << 2) | ($left >> 26 & $masks[26])); + $right = (($right << 2) | ($right >> 26 & $masks[26])); + } else { + $left = (($left << 1) | ($left >> 27 & $masks[27])); + $right = (($right << 1) | ($right >> 27 & $masks[27])); + } + $left = $left & -0xf; + $right = $right & -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + $lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf] | $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf] | $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf] | $pc2bytes6[($left >> 4 & $masks[4]) & 0xf]; + $righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf] | $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf] | $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf] | $pc2bytes13[($right >> 4 & $masks[4]) & 0xf]; + $temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff; + $keys[$n++] = $lefttemp ^ $temp; + $keys[$n++] = $righttemp ^ ($temp << 16); + } + } //for each iterations + //return the keys we've created + return $keys; +} + +//end of des_createKeys +////////////////////////////// TEST ////////////////////////////// +function stringToHex($s) { + $r = "0x"; + $hexes = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"); + for ($i = 0; $i < strlen($s); $i++) { + $r .= ($hexes [(ord($s{$i}) >> 4)] . $hexes [(ord($s{$i}) & 0xf)]); + } + return $r; +} + +function hexToString($h) { + $r = ""; + for ($i = (substr($h, 0, 2) == "0x") ? 2 : 0; $i < strlen($h); $i+=2) { + $r .= chr(base_convert(substr($h, $i, 2), 16, 10)); + } + return $r; +} + +//Exemple d'utilisation +/* echo "<PRE>"; + $key = "this is a 24 byte key !!"; + $message = "This is a test message"; + $ciphertext = des ($key, $message, 1, 0, null); + echo "DES Test Encrypted: " . stringToHex ($ciphertext); + $recovered_message = des ($key, $ciphertext, 0, 0, null); + echo "\n"; + echo "DES Test Decrypted: " . $recovered_message; */ +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/dateUtil.class.inc b/vas/rest/class/vmlib/dateUtil.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..1eec84c05d99bd54acf607b1c6028d349e8aa19a --- /dev/null +++ b/vas/rest/class/vmlib/dateUtil.class.inc @@ -0,0 +1,260 @@ +<?php + +/** + * \file dateUtil.class.inc + * \brief dateUtil.class.inc \n \n Ce fichier contient la classe php dateOp. + * + * Cette classe � �t� �labor�e par Dorian Constant. + * Fonctions de calcul de dates : addition, soustraction et comparaison. + * + * \author Alf05. + */ + +/** + * \class dateOp + * \brief dateOp Class \n \n Cette classe totalement g�n�rique permet de faire des calcules sur les dates. + * + * Cette classe � �t� �labor�e par Dorian Constant. Tous les param�tres li�s � la cr�ation de formulaires + * Fonctions de calcul de dates : addition, soustraction et comparaison. + * + * Exemples : + * $madate=new dateOp("18/06/2008 12:00","jj/mm/aaaa hh:ii"); + * ou + * $madate=new dateOp("18.6.08 12:00","jj.m.aa h:ii"); + * + * Addition et soustraction + * $madate->AjouteJours(5); + * $madate->AjouteJours(-9); + * $madate->AjouteMois(5); + * $madate->AjouteMois(-9); + * $madate->AjouteAnnees(5); + * $madate->AjouteAnnees(-9); + * $madate->AjouteHeures(5); + * $madate->AjouteHeures(-9); + * $madate->AjouteMinutes(5); + * $madate->AjouteMinutes(-9); + * $madate->AjouteSecondes(5); + * $madate->AjouteSecondes(-9); + * + * Comparaison + * $difference=$madate->DiffenrenceEntreDate('11/04/2000','jj/mm/aaaa'); + * + * Affichage + * echo $madate->GetDate('h:i:s jj/mm/aaaa'); // r�sultat = "12:30:00 18/06/2008" + * + * D�finition du format de date + * 'j' repr�sente les jours ('jj' pour avoir le zero initial) + * 'm' repr�sente les mois ('mm' pour avoir le zero initial) + * 'aa' repr�sente les ann�es ('aaaa' pour avoir l'ann�e sur 4 chiffres) + * 'h' repr�sente les heures ('hh' pour avoir le zero initial) + * 'ii' repr�sente les minutes + * 'ss' repr�sente les secondes + * + * \author Alf05. + */ +class dateOp { + + /** + * Constructeur. + * \param $dat Date. + * \param $format Format de la date. + * \return Vrai. + + */ + /* + * Variable globale stockant le nom de dossier lib. + */ + var $sFolderLib = "vmlib"; + var $lang; + + function __construct($dat, $format = "jj/mm/aaaa hh:ii:ss", $lang = "fr") { + $this->lang = $lang; + loadLang($this->sFolderLib, $this->lang); + $this->errno = array(); + + if (strlen($dat) != strlen($format)) { + $this->_error(ERROR_DATE_FORMAT_INCOMPATIBLE); + return false; + } + + $this->dat['origine'] = $dat; + $this->format = strtolower($format); + return $this->_ExplodeDate($this->dat, $this->format); + } + + /** + * Ajoute un ou plusieurs jours . + * \param $nb nombre de jours + * \return Vrai. + */ + function AjouteJours($nb) { + $this->dat['jj']+=floatval($nb); + return true; + } + + /** + * Ajoute un ou plusieurs mois. + * \param $nb nombre de mois + * \return Vrai. + */ + function AjouteMois($nb) { + $this->dat['mm']+=floatval($nb); + return true; + } + + /** + * Ajoute une ou plusieurs ann�es. + * \param $nb nombre d'ann�e + * \return Vrai. + */ + function AjouteAnnees($nb) { + $this->dat['aaaa']+=floatval($nb); + return true; + } + + /** + * Ajoute un ou plusieurs heures. + * \param $nb nombre d'heures + * \return Vrai. + */ + function AjouteHeures($nb) { + $this->dat['hh']+=floatval($nb); + return true; + } + + /** + * Ajoute un ou plusieurs minutes. + * \param $nb nombre de minutes + * \return Vrai. + */ + function AjouteMinutes($nb) { + $this->dat['ii']+=floatval($nb); + return true; + } + + /** + * Ajoute une ou plusieurs secondes. + * \param $nb nombre de secondes + * \return Vrai. + */ + function AjouteSecondes($nb) { + $this->dat['ss']+=floatval($nb); + return true; + } + + /** + * Calcule la difference avec une date pass� en param�tre. + * \param $dat Date. + * \param $format Format de la date. + * \return Un tableau. + */ + function DiffenrenceEntreDate($dat, $format = "jj/mm/aaaa hh:ii:ss") { + if (strlen($dat) != strlen($format)) { + $this->_error(ERROR_DATE_FORMAT_INCOMPATIBLE); + return false; + } + $this->dat2['origine'] = $dat; + $this->format2 = strtolower($format); + $this->_ExplodeDate($this->dat2, $this->format2); + $d1 = mktime($this->dat['hh'], $this->dat['ii'], $this->dat['ss'], $this->dat['mm'], $this->dat['jj'], $this->dat['aaaa']); + $d2 = mktime($this->dat2['hh'], $this->dat2['ii'], $this->dat2['ss'], $this->dat2['mm'], $this->dat2['jj'], $this->dat2['aaaa']); + + if ($d2 > $d1) + $d = $d2 - $d1; + else + $d = $d1 - $d2; + + return array("ans" => date('Y', $d) - 1970, "mois" => date('m', $d) - 1, "jours" => date('d', $d) - 1, "joursTotal" => $d / 60 / 60 / 24, "heures" => date("G", $d) - 1, "minutes" => date("i", $d), "secondes" => date("s", $d)); + } + + /** + * Retourne la date dans un format pr�cis. + * \param $format Format de la date � renvoyer. + * \return Un tableau. + */ + function GetDate($format = "jj/mm/aaaa") { + $format = str_replace(array('jj', 'j', 'm', 'nn', 'aaaa', 'aa', 'hh', 'h', 'ii', 'ss'), array('d', 'D', 'n', 'm', 'Y', 'y', 'H', 'G', 'i', 's'), $format); + // + if (intval($this->dat['aaaa']) <= 1901 || intval($this->dat['aaaa']) >= 2038) { + $sDay = $this->dat['jj']; + $sMonth = $this->dat['mm']; + $sYear = $this->dat['aaaa']; + if (intval($sDay) <= 9) + $sDay = "0" . $sDay; + if (intval($sMonth) <= 9) + $sMonth = "0" . $sMonth; + if ($format == "d/m/Y") { + return $sDay . "/" . $sMonth . "/" . $sYear; + } + // TODO : Si besoin, g�rer tous les autres formats de dates possibles + } + // + return date($format, mktime($this->dat['hh'], $this->dat['ii'], $this->dat['ss'], $this->dat['mm'], $this->dat['jj'], $this->dat['aaaa'])); + } + + /** + * V�rifie si la date pass� en param�tre correspond au format pass� en param�tre. + * \param $dat Date. + * \param $format Format de la date. + * \return Vrai. + * \private + */ + function _ExplodeDate(&$dat, $format) { + $j[0] = 2; + if (($j[1] = strpos($format, 'jj')) === false) { + $j[0] = 1; + if (($j[1] = strpos($format, 'j')) === false) + $this->_error($format . " : " . ERROR_DAY_NOT_FOUND); + } + $m[0] = 2; + if (($m[1] = strpos($format, 'mm')) === false) + $m[0] = 1; + if (($m[1] = strpos($format, 'm')) === false) + $this->_error($format . " : " . ERROR_MONTH_NOT_FOUND); + $a[0] = 4; + if (($a[1] = strpos($format, 'aaaa')) === false) { + //cherche pour un aa au lieu de aaaa + $a[0] = 2; + if (($a[1] = strpos($format, 'aa')) === false) + $this->_error($format . " : " . ERROR_YEAR_NOT_FOUND); + } + $h[0] = 2; + if (($h[1] = strpos($format, 'hh')) === false) + $h[0] = 1; + if (($h[1] = strpos($format, 'h')) === false) + $this->_error($format . " : " . ERROR_HOUR_NOT_FOUND); + $i[0] = 2; + if (($i[1] = strpos($format, 'ii')) === false) + $i[0] = 1; + if (($i[1] = strpos($format, 'i')) === false) + $this->_error($format . " : " . ERROR_MINUTE_NOT_FOUND); + $s[0] = 2; + if (($s[1] = strpos($format, 'ss')) === false) + $s[0] = 1; + if (($s[1] = strpos($format, 's')) === false) + $this->_error($format . " : " . ERROR_SECOND_NOT_FOUND); + $dat['jj'] = ($j[1] !== false) ? floatval(substr($dat['origine'], $j[1], $j[0])) : 1; + $dat['mm'] = ($m[1] !== false) ? floatval(substr($dat['origine'], $m[1], $m[0])) : 1; + $dat['aaaa'] = ($a[1] !== false) ? floatval(substr($dat['origine'], $a[1], $a[0])) : 1970; + if ($a[0] == 2) + $dat['aaaa'] = floatval(substr(date('Y'), 0, 2) . $dat['aaaa']); + $dat['hh'] = ($h[1] !== false) ? floatval(substr($dat['origine'], $h[1], $h[0])) : 0; + $dat['ii'] = ($i[1] !== false) ? floatval(substr($dat['origine'], $i[1], $i[0])) : 0; + $dat['ss'] = ($s[1] !== false) ? floatval(substr($dat['origine'], $s[1], $s[0])) : 0; + return true; + } + + /** + * Stocke le message d'erreur. + * \param $str. + * \return Vrai. + * \private + */ + function _error($str) { + $this->errno[] = $str; + return true; + } + +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/dbUtil.inc b/vas/rest/class/vmlib/dbUtil.inc new file mode 100755 index 0000000000000000000000000000000000000000..fce8724585322449e66e54301d5f4eaf7558ed76 --- /dev/null +++ b/vas/rest/class/vmlib/dbUtil.inc @@ -0,0 +1,400 @@ +<?php + +/* + * + * dbUtil.inc : fonction de r�cup�ration de connexion BD d'apr�s les param�tres de session + * + */ + +/* + * Variable globale stockant le nom de dossier lib. + */ +require_once __DIR__ . '/error.inc'; +require_once __DIR__ .'/../Ldap.class.inc'; +$sFolderLib = "vmlib"; + +/** + DEPRECATED utiliser la fonction codePass2 + * Cette m�thode code une chaine. + * \param $sPass Chaine � crypt�e. + * \return la chaine cod�e. + */ +/* function codepass($sPass) { + $sCode .= chr(97+strlen($sPass)); + for($i = 0; $i < 20; $i++){ + if ($i < strlen($sPass)){ + $iChar = ord($sPass[$i]); + $sCode .= sprintf("%'04s", $iChar); + }else{ + $sCode .= sprintf("%'04s", rand(0,99)); + } + } + return $sCode; + } */ + +/** + * Cette m�thode code une chaine. + * \param $sKey Cl� de cryptage. + * \param $sCode Chaine � crypt�e. + * \return la chaine cod�e. + */ +function codePass2($sKey, $sCode) { + require_once(__DIR__ . "/cryptUtil.inc"); + $sCode = stringToHex(trim(des(rtrim($sKey), rtrim($sCode), 1, 0, null))); + return $sCode; +} + +/** + DEPRECATED utiliser la fonction decodePass2 + * Cette m�thode d�code une chaine. + * \param $sCode Chaine � traduire. + * \return la chaine d�cod�e. + */ +function decodepass($sCode) { + require_once(__DIR__ . "/cryptUtil.inc"); + $sCode = trim(des(rtrim($_SESSION["ses_Login"]), hexToString(rtrim($sCode)), 0, 0, null)); + return $sCode; +} + +/** + * Cette m�thode d�code une chaine. + * \param $sKey Cl� de cryptage. + * \param $sCode Chaine � traduire. + * \return la chaine d�cod�e. + */ +function decodePass2($sKey, $sCode) { + require_once(__DIR__ . "/cryptUtil.inc"); + $sCode = trim(des(rtrim($sKey), hexToString(rtrim($sCode)), 0, 0, null)); + return $sCode; +} + +/** + * Cette m�thode g�n�re une connexion � la base de donn�es. + * \param $sPageEncoding Encodage de la base de donn�e. + * \return un objet BD. + */ +function connectFromSessionV2($sPageEncoding = "LATIN1") { + global $properties, $sFolderLib; + require_once(__DIR__ . "/cryptUtil.inc"); + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $oBd = new Vm($_SESSION["ses_Login"], utf8_encode(trim(des(rtrim(utf8_decode($_SESSION["ses_Login"])), hexToString(rtrim($_SESSION["ses_Password"])), 0, 0, null))), $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $sPageEncoding); + if ($oBd->erreurRencontree) { + writeToErrorLog(ERROR_CONNECTION_PROBLEM); + writeToErrorLog($oBd->getBDMessage()); + } + return $oBd; +} + +/** + * Cette m�thode g�n�re une connexion � la base de donn�es. + * \param $sPageEncoding Encodage de la base de donn�e. + * \return un objet BD. + */ +function connectFromSession($sPageEncoding = "LATIN1") { + global $properties, $sFolderLib; + require_once(__DIR__ . "/cryptUtil.inc"); + $sPassword = decodePass2($_SESSION["ses_Login"], $_SESSION["ses_Password"]); + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $oBd = new Vm($_SESSION["ses_Login"], $sPassword, $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $sPageEncoding); + if ($oBd->erreurRencontree) { + writeToErrorLog(ERROR_CONNECTION_PROBLEM); + writeToErrorLog($oBd->getBDMessage()); + } + return $oBd; +} + +/** + * Cette m�thode g�n�re une connexion � une base de donn�es pass�e en param�tre. + * \param $sPageEncoding Encodage de la base de donn�e. + * \param $sDatabase Nom de la base de donn�es. + * \return un objet BD. + */ +function connectFromSessionOtherDatabase($sDatabase, $sPageEncoding = "LATIN1") { + global $properties, $sFolderLib; + require_once("vmlib/cryptUtil.inc"); + $sPassword = decodePass2($_SESSION["ses_Login"], $_SESSION["ses_Password"]); + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $oBd = new Vm($_SESSION["ses_Login"], $sPassword, $sDatabase, $properties["server"], $properties["port"], $properties["sgbd"], $sPageEncoding); + if ($oBd->erreurRencontree) { + writeToErrorLog(ERROR_CONNECTION_PROBLEM); + writeToErrorLog($oBd->getBDMessage()); + } + return $oBd; +} + +/** + * Cette m�thode g�n�re une connexion � une base de donn�es pass�e en param�tre. + * \param $sPageEncoding Encodage de la base de donn�e. + * \param $sDatabase Nom de la base de donn�es. + * \return un objet BD. + */ +function connectFromSessionOtherDatabaseV2($sDatabase, $sPageEncoding = "LATIN1") { + global $properties, $sFolderLib; + require_once(__DIR__ . "/cryptUtil.inc"); + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $oBd = new Vm($_SESSION["ses_Login"], utf8_encode(trim(des(rtrim(utf8_decode($_SESSION["ses_Login"])), hexToString(rtrim($_SESSION["ses_Password"])), 0, 0, null))), $sDatabase, $properties["server"], $properties["port"], $properties["sgbd"], $sPageEncoding); + if ($oBd->erreurRencontree) { + writeToErrorLog(ERROR_CONNECTION_PROBLEM); + writeToErrorLog($oBd->getBDMessage()); + } + return $oBd; +} + +/** + * ? + */ +function getUserGroupsEngines($sSessLogin, $oBd, $bRights, $sSessPassword = "") { + global $properties; + $sSql = "SELECT domain_id, user_id FROM " . $properties["schema_framework"] . ".user WHERE lower(login) = '" . utf8_encode(strToLower(utf8_decode($sSessLogin))) . "'"; + $oPDOresult = @$oBd->execute($sSql); + $sListGroupId = ""; + $aFields = $oBd->ligneSuivante($oPDOresult); + $oPDOresult = $oBd->fermeResultat(); + if ($aFields['domain_id'] == "" || $bRights) { + $sSql = "SELECT group_id FROM " . $properties["schema_framework"] . ".user_group WHERE user_id = " . $aFields['user_id']; + $oPDOresult = @$oBd->execute($sSql); + + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupId == "") { + $sListGroupId = $aLigne["group_id"]; + } else { + $sListGroupId .= ", " . $aLigne["group_id"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + } + if ($aFields['domain_id'] != "") { + $sSql = "SELECT * FROM " . $properties["schema_framework"] . ".domain WHERE domain.domain_id='" . $aFields['domain_id'] . "'"; + $resultat = $oBd->execute($sSql); + $aResultLdap = $oBd->objetSuivant($resultat); + $resultat = $oBd->fermeResultat(); + if ($aResultLdap) { + if ($aResultLdap->verify_rights == 1) { + // Informations de l'AD stock� dans un tableau + if ($sSessPassword == "") { + $sSessLogin2 = $aResultLdap->login; + $sSessPassword = $aResultLdap->password; + } else { + $sSessLogin2 = $sSessLogin; + $sSessPassword = $sSessPassword; + } + if ($_REQUEST['object'] == "person") { + $aLdap = array(sIdLdap => $aResultLdap->domain_id, sLdapName => $aResultLdap->domain, sType => $aResultLdap->type, sLoginLdap => utf8_encode(strToLower(utf8_decode($sSessLogin2))), sPwdLdap => $sSessPassword, sServer => $aResultLdap->server, sPort => $aResultLdap->port, sDnResearch => $aResultLdap->dn_search_user); + } else { + $aLdap = array(sIdLdap => $aResultLdap->domain_id, sLdapName => $aResultLdap->domain, sType => $aResultLdap->type, sLoginLdap => utf8_encode(strToLower(utf8_decode($sSessLogin2))), sPwdLdap => $sSessPassword, sServer => $aResultLdap->server, sPort => $aResultLdap->port, sDnResearch => $aResultLdap->dn_search_group); + } + $oLdap = new Ldap(serialize($aLdap)); + $sLdapConn = $oLdap->connectLdap(); + if (ldap_error($sLdapConn) == "Success") { + $aGroups = $oLdap->getGroup($sLdapConn, utf8_encode(strToLower(utf8_decode($sSessLogin)))); + $sListGroupName = ""; + foreach ($aGroups as $iGroupId) { + if ($sListGroupName == "") { + $sListGroupName = "'" . str_replace("'", "''", utf8_encode(strToLower(utf8_decode($iGroupId)))) . "'"; + } else { + $sListGroupName .= ", '" . str_replace("'", "''", utf8_encode(strToLower(utf8_decode($iGroupId)))) . "'"; + } + } + $sSql = "SELECT group_id FROM " . $properties["schema_framework"] . ".group WHERE LOWER(name) IN (" . $sListGroupName . ")"; + $oPDOresult = @$oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupId == "") { + $sListGroupId = $aLigne["group_id"]; + } else { + $sListGroupId .= ", " . $aLigne["group_id"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + } else { + if (ldap_error($sLdapConn) == "Invalid credentials") + $sErrorMessage = ERROR_0033; + else if (ldap_error($sLdapConn) == "Can't contact LDAP server") + $sErrorMessage = TEXT_ERROR_CONTACT_DOMAIN; + else + $sErrorMessage = ldap_error($sLdapConn); + writeToErrorLog($sErrorMessage); + $aFormContent = $_REQUEST; + } + }else { + $sListGroupId = "0"; + } + } + } + if ($sListGroupId == "") { + $sListGroupId = "0"; + } + return $sListGroupId; +} + +/** + * ? + */ +function getUserGroups($sSessLogin, $oBd, $sSessPassword = "", $bRights, $sSchema) { + + $sSql = "SELECT domain_id, user_id FROM " . $sSchema . ".v_user WHERE lower(login) = '" . utf8_encode(strToLower(utf8_decode($sSessLogin))) . "'"; + $oPDOresult = @$oBd->execute($sSql); + + $aFields = $oBd->ligneSuivante($oPDOresult); + $oPDOresult = $oBd->fermeResultat(); + if ($aFields['domain_id'] == "" || $bRights) { + $sSql = "SELECT group_id FROM " . $sSchema . ".v_user_group WHERE user_id = " . $aFields['user_id']; + $oPDOresult = @$oBd->execute($sSql); + $sListGroupId = ""; + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupId == "") { + $sListGroupId = $aLigne["group_id"]; + } else { + $sListGroupId .= ", " . $aLigne["group_id"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + if ($sListGroupId == "") { + $sListGroupId = "0"; + } + } + if ($aFields['domain_id'] != "") { + $sSql = 'SELECT * FROM ' . $sSchema . '.domain WHERE domain.domain_id=\'' . $aFields['domain_id'] . '\''; + $resultat = $oBd->execute($sSql); + $aResultLdap = $oBd->objetSuivant($resultat); + $resultat = $oBd->fermeResultat(); + if ($aResultLdap) { + // Informations de l'AD stock� dans un tableau + if ($sSessPassword == "") { + $sSessLogin2 = $aResultLdap->login; + $sSessPassword = $aResultLdap->password; + } else { + $sSessLogin2 = $sSessLogin; + $sSessPassword = $sSessPassword; + } + if ($_REQUEST['object'] == "person") { + $aLdap = array(sIdLdap => $aResultLdap->domain_id, sLdapName => $aResultLdap->domain, sLoginLdap => utf8_encode(strToLower(utf8_decode($sSessLogin2))), sPwdLdap => $sSessPassword, sServer => $aResultLdap->server, sPort => $aResultLdap->port, sDnResearch => $aResultLdap->dn_search_user, sType => $aResultLdap->type); + } else { + $aLdap = array(sIdLdap => $aResultLdap->domain_id, sLdapName => $aResultLdap->domain, sLoginLdap => utf8_encode(strToLower(utf8_decode($sSessLogin2))), sPwdLdap => $sSessPassword, sServer => $aResultLdap->server, sPort => $aResultLdap->port, sDnResearch => $aResultLdap->dn_search_group, sType => $aResultLdap->type); + } + $oLdap = new Ldap(serialize($aLdap)); + $sLdapConn = $oLdap->connectLdap(); + if (ldap_error($sLdapConn) == "Success") { + $aGroups = $oLdap->getGroup($sLdapConn, $sSessLogin); + $sListGroupName = ""; + foreach ($aGroups as $iGroupId) { + if ($sListGroupName == "") { + $sListGroupName = "'" . str_replace("'", "''", utf8_encode(strToLower(utf8_decode($iGroupId)))) . "'"; + } else { + $sListGroupName .= ", '" . str_replace("'", "''", utf8_encode(strToLower(utf8_decode($iGroupId)))) . "'"; + } + } + $sSql = "SELECT group_id FROM " . $sSchema . ".group WHERE LOWER(name) IN (" . $sListGroupName . ")"; + $oPDOresult = @$oBd->execute($sSql); + + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupId == "") { + $sListGroupId = $aLigne["group_id"]; + } else { + $sListGroupId .= ", " . $aLigne["group_id"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + } else { + if (ldap_error($sLdapConn) == "Invalid credentials") + $sErrorMessage = ERROR_0033; + else if (ldap_error($sLdapConn) == "Can't contact LDAP server") + $sErrorMessage = TEXT_ERROR_CONTACT_DOMAIN; + else + $sErrorMessage = ldap_error($sLdapConn); + writeToErrorLog($sErrorMessage); + $aFormContent = $_REQUEST; + } + } + } + if ($sListGroupId == "") { + $sListGroupId = "0"; + } + return $sListGroupId; +} + +function getUserGroups2($sSessLogin, $oBd, $bRights, $sSchema) { + $sListGroupIdBd = ""; + $sListGroupIdAd = ""; + + $sSql = "SELECT domain_id, user_id FROM " . $sSchema . ".v_user WHERE lower(login) = '" . utf8_encode(strToLower(utf8_decode($sSessLogin))) . "'"; + $oPDOresult = $oBd->execute($sSql); + if ($oBd->erreurRencontree) { + writeToErrorLog($oBd->getBDMessage()); + } else { + $aFields = $oBd->ligneSuivante($oPDOresult); + + $oPDOresult = $oBd->fermeResultat(); + if ($aFields['domain_id'] == "" || $bRights) { + $sSql = "SELECT group_id FROM " . $sSchema . ".v_user_group WHERE user_id = " . $aFields['user_id']; + $oPDOresult = @$oBd->execute($sSql); + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupIdBd == "") { + $sListGroupIdBd = $aLigne["group_id"]; + } else { + $sListGroupIdBd .= ", " . $aLigne["group_id"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + } + if ($aFields['domain_id'] != "") { + $sSql = 'SELECT * FROM ' . $sSchema . '.domain WHERE domain.domain_id=\'' . $aFields['domain_id'] . '\''; + $resultat = $oBd->execute($sSql); + $aResultLdap = $oBd->objetSuivant($resultat); + $resultat = $oBd->fermeResultat(); + if ($aResultLdap) { + // Informations de l'AD stock� dans un tableau + if ($sSessPassword == "") { + $sSessLogin2 = $aResultLdap->login; + //$sSessPassword = stringToHex (des ($sSessLogin2, $aResultLdap->password, 1, 0, null)); + $sSessPassword = $aResultLdap->password; + //writeToErrorLog($aResultLdap->password); + } else { + $sSessLogin2 = $_SESSION['']; + $sSessPassword = utf8_encode(trim(des(rtrim(utf8_decode($_SESSION[''])), hexToString(rtrim($_SESSION[''])), 0, 0, null))); + } + // if ($_REQUEST['object'] == "person"){ + $aLdap = array(sIdLdap => $aResultLdap->domain_id, sLdapName => $aResultLdap->domain, sLoginLdap => utf8_encode(strToLower(utf8_decode($sSessLogin2))), sPwdLdap => $sSessPassword, sServer => $aResultLdap->server, sPort => $aResultLdap->port, sDnResearch => $aResultLdap->dn_search_user, sType => $aResultLdap->type); + // }else{ + // $aLdap = array(sIdLdap=>$aResultLdap->domain_id,sLoginLdap=>strtolower($sSessLogin2),sPwdLdap=> $sSessPassword,sServer=>$aResultLdap->server,sPort=>$aResultLdap->port,sDnResearch=>$aResultLdap->dn_search_group); + // } + $oLdap = new Ldap(serialize($aLdap)); + $sLdapConn = $oLdap->connectLdap(); + if (ldap_error($sLdapConn) == "Success") { + $aGroups = $oLdap->getGroup($sLdapConn, utf8_encode(strToLower(utf8_decode($sSessLogin)))); + $sListGroupName = ""; + foreach ($aGroups as $iGroupId) { + if ($sListGroupName == "") { + $sListGroupName = "'" . utf8_encode(strToLower(utf8_decode($iGroupId))) . "'"; + } else { + $sListGroupName .= ", '" . utf8_encode(strToLower(utf8_decode($iGroupId))) . "'"; + } + } + $sSql = "SELECT name FROM " . $sSchema . ".group WHERE LOWER(name) IN (" . $sListGroupName . ")"; + $oPDOresult = @$oBd->execute($sSql); + $sListGroupIdAd = ""; + while ($aLigne = $oBd->ligneSuivante($oPDOresult)) { + if ($sListGroupIdAd == "") { + $sListGroupIdAd = $aLigne["name"]; + } else { + $sListGroupIdAd .= ", " . $aLigne["name"]; + } + } + $oPDOresult = $oBd->fermeResultat(); + } else { + if (ldap_error($sLdapConn) == "Invalid credentials") + $sErrorMessage = ERROR_0033; + else if (ldap_error($sLdapConn) == "Can't contact LDAP server") + $sErrorMessage = TEXT_ERROR_CONTACT_DOMAIN; + else + $sErrorMessage = ldap_error($sLdapConn); + writeToErrorLog($sErrorMessage); + $aFormContent = $_REQUEST; + } + } + } + } + $aGroupList = array("bd" => $sListGroupIdBd, "ad" => $sListGroupIdAd); + return $aGroupList; +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/error.inc b/vas/rest/class/vmlib/error.inc new file mode 100644 index 0000000000000000000000000000000000000000..13db7b08ff362840fee0ef2bd2d8b84d0c63b52b --- /dev/null +++ b/vas/rest/class/vmlib/error.inc @@ -0,0 +1,70 @@ +<?php + +// gtf.engines/engine.php +define('ERROR_0001', 'Impossible de récupérer les noms des moteurs GTF et FME'); + +// gtf_lib/DbClass.class.inc +define('ERROR_0002', 'The order creation has failed. -- '); +define('ERROR_0003', 'The order update [order_id] has failed. -- '); +define('ERROR_0004', 'The suppression order [order_id] has failed. -- '); + +// gtf_object/Ldap.class.inc +define('ERROR_0005', 'Could not connect to LDAP server.'); + +// gtf_object/Order.class.inc +define('ERROR_0006', "ATTENTION - Le tag du traitement n°[iOrderId] n'est associé à aucun moteur. Le tag default est utilisé pour définir le numéro de moteur."); +define('ERROR_0007', "ATTENTION - Le tag du traitement n'est associé à aucun moteur. Le tag default n'est pas non plus associé à un moteur. Parmi la liste des moteurs disponibles, le moteur n°[aGtfEngineList[0]] a été affecté à la demande de traitement n°[iOrderId]"); +define('ERROR_0008', "ERROR - Aucune méthode n'a permis d'affecté un moteur au traitement. le moteur n°1 a été affecté à la demande de traitement n°[iOrderId]."); +// define('ERROR_0026', 'ERROR - Parmi la liste des moteurs disponibles, le moteur n°[aGtfEngineList[0]] a été affecté à la demande de traitement n°[iOrderId]'); +// define('ERROR_0009', "ERROR - L'algorithme ne permet pas de retourner un numéro de moteur exploitable. Le numéro de moteur retourné n'est pas de type entier. Type de la valeur retournée par la méthode : "); +// define('ERROR_0010', "ERROR - Le numéro du moteur retourné par l'algorithme n'existe pas dans la liste des moteurs disponible dans GTF."); +define('ERROR_0011', "Erreur Le fichier [_FILES[sNomObjet][name]] n'est pas téléchargé sur le serveur"); +define('ERROR_0035', "Erreur de la suppression d'un processus d'une demande stoppée"); +define('ERROR_0036', "Erreur de la commande d'information d'un processus d'une demande stoppée"); +define('ERROR_0037', "Erreur pendant l'arrêt de la demande sur Fme Desktop."); +define('ERROR_0038', "Erreur pendant l'arrêt de la demande sur Fme Server."); + +// veremap/DownloadMaj.class.inc +define('ERROR_0012', "Unable to write file"); +define('ERROR_0013', 'Unable to download file'); +define('ERROR_0014', 'Error downloading binaries'); +define('ERROR_0015', "Une erreur s'est produite lors du telechargment de la mise à jour"); +define('ERROR_0016', 'Unable to unzip the file '); + +// veremap/FopTemplate.class.inc +define('ERROR_0017', 'Error Pdf generation'); +define('ERROR_0018', 'Command : '); +define('ERROR_0019', 'aCommand array '); +define('ERROR_0020', 'Erreur lors de la génération du Fichier Jpeg [sNameJpg] dans [sDirDestination]'); +define('ERROR_0021', 'Command : '); +define('ERROR_0022', 'aCommand array '); + +// vmlib\Email.class.inc +define('ERROR_0023', 'Failed sending email to the following address : '); + +// vmlib\EmailTemplate.class.inc +define('ERROR_0024', 'The e-mail template (id=[iEmailTemplateId]) does not exist...'); + +// gtf.engines\subscription.php +define('ERROR_0025', 'Error creating directory '); + +// configuration\getLicense.phtml +define('ERROR_0027', "Failed to send the mail to the following address : "); + +// configuration\properties.phtml +define('ERROR_0028', "Error writing file properties.inc"); +define('ERROR_0029', 'Le formulaire de properties passé en paramètre est vide!'); + +// forms\widget.phtml +define('ERROR_0030', 'invalid token.'); + +// workspace\importWorkspaces.phtml +define('ERROR_0031', 'Erreur lors de la copie du fichier FMW : '); +define('ERROR_0032', "Le fichier SubForm.class.inc du traitement [sLabelName] n'a pas été généré."); + +// vmlib\dbUtil.inc +define('ERROR_0033', 'Invalid credentials'); // -> TEXT_INVALID_CREDENTIALS + +// vitis/vitis.class.inc +define('ERROR_0034', 'Invalid filter'); +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/lang_vmlib/en-lang.inc b/vas/rest/class/vmlib/lang_vmlib/en-lang.inc new file mode 100755 index 0000000000000000000000000000000000000000..44a182f35c904eb3dc8192f48a955801f712d184 --- /dev/null +++ b/vas/rest/class/vmlib/lang_vmlib/en-lang.inc @@ -0,0 +1,114 @@ +<?php + +define('USER_LABEL', 'User: '); +define('ERROR_LABEL', '<br>Error: '); + +//logUtil +define('ERROR_IMPOSSIBLE_WRITE', 'Impossible to write in the file '); +define('ERROR_RIGHTS_ON_FILE', ': the application does not arrange rights in writing on the file'); +define('ERROR_WRITING_FILE', ': failure of the writing'); +define('ERROR_REQUEST_ERROR', 'SQL Error, more information in the application logs'); + +//BD.class +define('ERROR_INCORRECT_SGBD', 'The dbms is not correct.\n Connection to the database impossible.'); +define('ERROR_ACCESS_SERVER', 'Access to the server impossible for:'); +define('ERROR_CONNECT_SERVER', 'Connection to the server impossible\n'); +define('ERROR_SGBD_UNDEFINED', 'You have not specified the dbms.\n Connection to the database impossible.'); +define('ERROR_REQUEST_IMPOSSIBLE', 'Execution of the request impossible: '); +define('RETURN_BD_LABEL', 'The server return: '); +define('ATTRIBUT_POSITION_BD_LABEL', '"There is not attribute in order $position'); +define('UNKNOWN_BD_LABEL', 'Unknown'); + +//dateUtil +define('ERROR_DATE_FORMAT_INCOMPATIBLE', 'Format of date incompatible with supplied date'); +define('ERROR_DAY_NOT_FOUND', 'Days were not found... Days must be specified by \'jj\' or by \'j\' (ex: jj/mm/aaaa)'); +define('ERROR_MONTH_NOT_FOUND', 'Monthes were not found... Monthes must be specified by \'mm\' or by \'m\' (ex: jj/mm/aaaa)'); +define('ERROR_YEAR_NOT_FOUND', 'Years were not found... Years must be specified by \'aaaa\' or by \'aa\' (ex: jj/mm/aaaa)'); +define('ERROR_HOUR_NOT_FOUND', 'Hours were not found... Hours must be specified by \'hh\' or by \'h\' (ex: jj/mm/aaaa hh:ii:ss)'); +define('ERROR_MINUTE_NOT_FOUND', 'Minutes were not found... Minutes must be specified by \'ii\' or by \'i\' (ex: jj/mm/aaaa hh:ii:ss)'); +define('ERROR_SECOND_NOT_FOUND', 'Seconds were not found... Seconds must be specified by \'ss\' or by \'s\' (ex: jj/mm/aaaa hh:ii:ss)'); + +//dbUtil +define('ERROR_DECODE_EMPTY_STRING', 'Error: The string to be decoded is empty'); +define('ERROR_CONNECTION_PROBLEM', 'Problem of connection:'); + +//Formulaire +define('ENLARGE_INPUT_FORMULAIRE_LABEL', 'Enlarge the input field'); +define('DECREASE_INPUT_FORMULAIRE_LABEL', 'Decrease the input field'); +define('PALLET_FORMULAIRE_LABEL', 'pallet'); +define('SYMBOL_FORMULAIRE_LABEL', 'symbols'); +define('FONT_FORMULAIRE_LABEL', 'fonts'); +define('ASSISTANT_FORMULAIRE_LABEL', 'assistant'); +define('MOVE_RIGHT_FORMULAIRE_LABEL', 'Move to the right'); +define('MOVE_LEFT_FORMULAIRE_LABEL', 'Move to the left'); +define('ERROR_UNKNOWN_TYPE', 'ERROR: $pType is an unknown type\n'); +define('DELETE_FORMULAIRE_LABEL', 'Delete'); +define('ADD_FORMULAIRE_LABEL', 'Add'); +define('SHOW_CALENDAR_FORMULAIRE_LABEL', 'Show calendar'); +define('CALENDAR_FORMULAIRE_LABEL', 'Calendar'); +define('VALIDATE_FORMULAIRE_LABEL', 'Validate'); +define('CANCEL_FORMULAIRE_LABEL', 'Cancel'); +define('NO_DOCUMENT_FORMULAIRE_LABEL', 'No document'); + +//formVerif +define('INPUT_FORMVERIF_LABEL', 'The field'); +define('NOT_NULL_FORMVERIF_LABEL', 'must not be \"NULL\".'); +define('NOT_CORRESPOND_FORMVERIF_LABEL', 'does not correspond at '); +define('NOT_NUMERIC_FORMVERIF_LABEL', 'must be numeric.'); +define('NOT_INTEGER_FORMVERIF_LABEL', 'must be an integer.'); +define('NOT_DECIMAL_FORMVERIF_LABEL', 'must be a decimal.'); +define('NOT_DATE_FORMVERIF_LABEL', 'must ba a date '); +define('NOT_SPACE_FORMVERIF_LABEL', 'does not have to contain of spaces or special characters (accepted \'point\').'); +define('NOT_EXTENSION_FORMVERIF_LABEL', 'forbids the upload of files of extension '); +define('NOT_CONTAINS_FORMVERIF_LABEL', 'does not have to contain: '); + +//ldap +define('ERROR_USER_NOT_FOUND_LDAP', 'Refused connection. The user [LOGIN] was not found in Active Directory.'); +define('ERROR_CONNECT_LDAP', 'Impossible connection. Impossible to connect to the server of Active Directory.'); +define('ERROR_LDAP_FAILED', 'Failed connection LDAP'); + +//vm +define('NOT_RECORD_FOUND_VM', 'No recording of this type was found'); +define('WARNING_DELETE_VM_01', '\'Warning! The recording N '); +define('WARNING_DELETE_VM_02', ' is going to be deleted.'); + +//phpUtil +define('ERROR_DOWNLOAD_FILE', 'Erreur downloading file '); +define('ERROR_UPLOAD_MAX_FILE_SIZE', 'it exceeds the size of upload_max_filesize, configured in the php.ini'); +define('ERROR_MAX_FILE_SIZE', 'it exceeds the size of MAX_FILE_SIZE, which was specified in the HTML form.'); +define('ERROR_NO_FILE_DOWNLOADED', 'No file was downloaded.'); +define('ERROR_PARTIAL_DOWNLOAD', 'It had only partially downloaded.'); +define('ERROR_MISSING_TEMP_FOLDER', 'a temporary folder is missing.'); +define('ERROR_WRITING_DISK', 'Failure of the writing of the file on the disk.'); +define('ERROR_PHP_EXT_SEND', 'a PHP extension stopped the sending of file.'); +define('ERROR_FILE', 'Error the file '); +define('ERROr_NOT_FILE', ' is not a file '); +define('FILE_LABEL_PHPUTIL', 'The file '); +define('ERROR_VALID_FILE', ' valid.<br> The authorized formats are:'); +define('OF_LABEL_PHPUTIL', ' of '); +define('ERROR_EXCEED_MAX_SIZE', ' bytes exceeds the authorized maximal size'); +define('LABEL_BYTES_PHPUTIL', ' bytes'); +define('ERROR_EXCEED_MAX_SIZE_PHP', ' exceeds the authorized maximal size by the PHP configuration'); +define('ERROR_COPYING_FILE', 'Error during the file copy '); +define('ON_SERVER_PHPUTIL', ' on the server'); +define('ERROR_DOWNLOAD_SERVER', ' is not downloaded on the server'); +define('ERROR_CODE_PHPUTIL', 'Error code: '); +define('ERROR_DAY_CODE', 'The day code "'); +define('ERROR_CODE_NOT_VALID', 'is not valid'); +define('ERROR_NOT_INF', 'He was have to be lower in '); +define('ERROR_NOT_SUP', ' and supérior in '); +define('ERROR_DAY_WEEK', 'You cannot define one month and a day or a day of the week.'); +define('ERROR_MONTH_CODE', 'The month code "'); +define('ERROR_NUMBER_PHPUTIL', 'It can\'t be a number.'); +define('ERROR_WEEK_CODE', 'The day code of the week "'); +define('ERROR_CODE_3_VALUES', 'The code does not contain three values separated by a space.'); + +define('YES', 'Yes'); +define('NO', 'No'); + +define('SUCCESS_REQUEST', htmlentities("Request processed successfully")); +define('FAILED_REQUEST', htmlentities("Error during request processing. HTTP error:")); + +// genericTreeviewField() +define('HTMLFORM_GENERIC_TREEVIEW_FIELD_TITLE', htmlentities("Aperçu de votre sélection", ENT_COMPAT | ENT_HTML401, $encodage)); +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/lang_vmlib/fr-lang.inc b/vas/rest/class/vmlib/lang_vmlib/fr-lang.inc new file mode 100755 index 0000000000000000000000000000000000000000..36e37795d6b49feaaed20971b26f88216ddf4eb2 --- /dev/null +++ b/vas/rest/class/vmlib/lang_vmlib/fr-lang.inc @@ -0,0 +1,114 @@ +<?php + +define('USER_LABEL', 'Utilisateur : '); +define('ERROR_LABEL', '<br>Erreur : '); + +//logUtil +define('ERROR_IMPOSSIBLE_WRITE', 'Impossible d\'écrire dans le fichier '); +define('ERROR_RIGHTS_ON_FILE', ' : l\'application ne dispose pas de droits en écriture sur le fichier'); +define('ERROR_WRITING_FILE', ' : échec de l\'écriture'); +define('ERROR_REQUEST_ERROR', 'Une erreur SQl est survenue, plus d\'information dans les fichiers de log de l\'application, veuillez contacter votre administrateur'); + +//BD.class +define('ERROR_INCORRECT_SGBD', 'Le sgbd spécifié n\'est pas correct.\n Connexion à la base impossible.'); +define('ERROR_ACCESS_SERVER', 'Accès au serveur impossible pour :'); +define('ERROR_CONNECT_SERVER', 'Connexion au serveur impossible\n'); +define('ERROR_SGBD_UNDEFINED', 'Vous n\'avez pas spécifié votre sgbd.\n Connexion à la base impossible.'); +define('ERROR_REQUEST_IMPOSSIBLE', 'Impossible d\'exécuter la requête : '); +define('RETURN_BD_LABEL', 'Le serveur renvoit : '); +define('ATTRIBUT_POSITION_BD_LABEL', '"Il n\'y a pas d\'attribut en position $position'); +define('UNKNOWN_BD_LABEL', 'Inconnu'); + +//dateUtil +define('ERROR_DATE_FORMAT_INCOMPATIBLE', 'Format de date incompatible avec la date fournie'); +define('ERROR_DAY_NOT_FOUND', 'Les jours n\'ont pas été trouvés... Les jours doivent être précisés par \'jj\' ou par \'j\' (ex: jj/mm/aaaa)'); +define('ERROR_MONTH_NOT_FOUND', 'Les mois n\'ont pas été trouvés... Les mois doivent être précisés par \'mm\' ou par \'m\' (ex: jj/mm/aaaa)'); +define('ERROR_YEAR_NOT_FOUND', 'Les années n\'ont pas été trouvés... Les années doivent être précisés par \'aaaa\' ou par \'aa\' (ex: jj/mm/aaaa)'); +define('ERROR_HOUR_NOT_FOUND', 'Les heures n\'ont pas été trouvées... Les heures doivent être précisées par \'hh\' ou \'h\' (ex: jj/mm/aaaa hh:ii:ss)'); +define('ERROR_MINUTE_NOT_FOUND', 'Les minutes n\'ont pas été trouvées... Les minutes doivent être précisées par \'ii\' ou \'i\' (ex: jj/mm/aaaa hh:ii:ss)'); +define('ERROR_SECOND_NOT_FOUND', 'Les secondes n\'ont pas été trouvées... Les secondes doivent être précisés par \'ss\' ou \'s\' (ex: jj/mm/aaaa hh:ii:ss)'); + +//dbUtil +define('ERROR_DECODE_EMPTY_STRING', 'Erreur : La chaine à décoder est vide'); +define('ERROR_CONNECTION_PROBLEM', 'Problème de connexion :'); + +//Formulaire +define('ENLARGE_INPUT_FORMULAIRE_LABEL', 'Agrandir la zone de saisie'); +define('DECREASE_INPUT_FORMULAIRE_LABEL', 'Diminuer la zone de saisie'); +define('PALLET_FORMULAIRE_LABEL', 'palette'); +define('SYMBOL_FORMULAIRE_LABEL', 'symboles'); +define('FONT_FORMULAIRE_LABEL', 'polices'); +define('ASSISTANT_FORMULAIRE_LABEL', 'assistant'); +define('MOVE_RIGHT_FORMULAIRE_LABEL', 'Déplacer à droite'); +define('MOVE_LEFT_FORMULAIRE_LABEL', 'Déplacer à gauche'); +define('ERROR_UNKNOWN_TYPE', 'ERREUR: $pType est un type inconnu\n'); +define('DELETE_FORMULAIRE_LABEL', 'Supprimer'); +define('ADD_FORMULAIRE_LABEL', 'Ajouter'); +define('SHOW_CALENDAR_FORMULAIRE_LABEL', 'Afficher le calendrier'); +define('CALENDAR_FORMULAIRE_LABEL', 'Calendrier'); +define('VALIDATE_FORMULAIRE_LABEL', 'Valider'); +define('CANCEL_FORMULAIRE_LABEL', 'Annuler'); +define('NO_DOCUMENT_FORMULAIRE_LABEL', 'Aucun document'); + +//formVerif +define('INPUT_FORMVERIF_LABEL', 'Le champ'); +define('NOT_NULL_FORMVERIF_LABEL', 'ne doit pas être \"NULL\".'); +define('NOT_CORRESPOND_FORMVERIF_LABEL', 'ne correspond pas a '); +define('NOT_NUMERIC_FORMVERIF_LABEL', 'doit être de type numérique.'); +define('NOT_INTEGER_FORMVERIF_LABEL', 'doit être de type entier.'); +define('NOT_DECIMAL_FORMVERIF_LABEL', 'doit être de type entier décimal.'); +define('NOT_DATE_FORMVERIF_LABEL', 'doit être de type date '); +define('NOT_SPACE_FORMVERIF_LABEL', 'ne doit pas contenir d\'espaces ou de caractères spéciaux (\'point\' accepté).'); +define('NOT_EXTENSION_FORMVERIF_LABEL', 'interdit l\'upload de fichiers d\'extension '); +define('NOT_CONTAINS_FORMVERIF_LABEL', 'ne doit pas contenir : '); + +//ldap +define('ERROR_USER_NOT_FOUND_LDAP', 'Connexion refusée. L\'utilisateur [LOGIN] n\'a pas été trouvé dans l\'Active Directory.'); +define('ERROR_CONNECT_LDAP', 'Connexion impossible. Impossible de se connecter au serveur de l\'Active Directory.'); +define('ERROR_LDAP_FAILED', 'Connexion LDAP échouée'); + +//vm +define('NOT_RECORD_FOUND_VM', 'Aucun enregistrement de ce type n\'a été trouvé'); +define('WARNING_DELETE_VM_01', '\'Attention ! l\\\'enregistrement n° '); +define('WARNING_DELETE_VM_02', ' va être supprimé.'); + +//phpUtil +define('ERROR_DOWNLOAD_FILE', 'Erreur lors du téléchargement du fichier '); +define('ERROR_UPLOAD_MAX_FILE_SIZE', 'il excède la taille de upload_max_filesize, configurée dans le php.ini'); +define('ERROR_MAX_FILE_SIZE', 'il excède la taille de MAX_FILE_SIZE, qui a été spécifiée dans le formulaire HTML.'); +define('ERROR_NO_FILE_DOWNLOADED', 'Aucun fichier n\'a été téléchargé.'); +define('ERROR_PARTIAL_DOWNLOAD', 'il n\'a été que partiellement téléchargé.'); +define('ERROR_MISSING_TEMP_FOLDER', 'un dossier temporaire est manquant.'); +define('ERROR_WRITING_DISK', 'échec de l\'écriture du fichier sur le disque.'); +define('ERROR_PHP_EXT_SEND', 'une extension PHP a arrété l\'envoi de fichier.'); +define('ERROR_FILE', 'Erreur Le fichier '); +define('ERROR_NOT_FILE', ' n\'est pas un fichier '); +define('FILE_LABEL_PHPUTIL', 'Le fichier '); +define('ERROR_VALID_FILE', ' valide.<br> Les formats autorisés sont :'); +define('OF_LABEL_PHPUTIL', ' de '); +define('ERROR_EXCEED_MAX_SIZE', ' octets dépasse la taille maximale autorisée'); +define('LABEL_BYTES_PHPUTIL', ' octets'); +define('ERROR_EXCEED_MAX_SIZE_PHP', ' dépasse la taille maximale autorisée par la configuration PHP'); +define('ERROR_COPYING_FILE', 'Erreur lors de la copie du fichier '); +define('ON_SERVER_PHPUTIL', ' sur le serveur'); +define('ERROR_DOWNLOAD_SERVER', ' n\'est pas téléchargé sur le serveur'); +define('ERROR_CODE_PHPUTIL', 'Code erreur : '); +define('ERROR_DAY_CODE', 'Le code du jour "'); +define('ERROR_CODE_NOT_VALID', '" n\'est pas valide'); +define('ERROR_NOT_INF', 'Il ne doit pas être inférieure à '); +define('ERROR_NOT_SUP', ' et supérieure à '); +define('ERROR_DAY_WEEK', 'Vous ne pouvez pas définir un mois et un jour ou un jour de la semaine.'); +define('ERROR_MONTH_CODE', 'Le code du mois "'); +define('ERROR_NUMBER_PHPUTIL', 'Il ne peut pas être un nombre.'); +define('ERROR_WEEK_CODE', 'Le code du jour de la semaine "'); +define('ERROR_CODE_3_VALUES', 'Le code ne contient pas trois valeurs séparées par un espace.'); + +define('YES', 'Oui'); +define('NO', 'Non'); + +define('SUCCESS_REQUEST', htmlentities("Requête exécutée avec succés.")); +define('FAILED_REQUEST', htmlentities("Erreur lors de l'exécution de la requête. Erreur HTTP : ")); + +// genericTreeviewField() +define('HTMLFORM_GENERIC_TREEVIEW_FIELD_TITLE', htmlentities("Aperçu de votre sélection", ENT_COMPAT | ENT_HTML401, $encodage)); +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/logUtil.inc b/vas/rest/class/vmlib/logUtil.inc new file mode 100644 index 0000000000000000000000000000000000000000..d7474ff379d5a0cf1850ac78f8ab2f5712560450 --- /dev/null +++ b/vas/rest/class/vmlib/logUtil.inc @@ -0,0 +1,198 @@ +<?php + +/** + * \file logUtil.inc + * \brief + * + * Fonctions de mise en place de logs + * + * \author Olivier Gayte <olivier.gayte@veremes.com> + * \author Frédéric Mauro + */ +/* + * Variable globale stockant une erreur. + */ +$sMessageLogError = ""; + +/* + * Variable globale stockant le nom de dossier lib. + */ +$sFolderLib = "vmlib"; +/** + * Converti une chaine ISO-8859-1 en UTF-8 + * \param $sString Chaîne de caractères à convertir. + * \return une chaine encodée en UTF-8 + */ +/* function Latin1ToUtf8($sString){ + if( mb_detect_encoding($sString,"UTF-8, ISO-8859-1")!="UTF-8" ){ + return iconv("ISO-8859-1","UTF-8",$sString); + } + else{ + return $sString; + } + } + bfd + + + function baseEncoding_pageEncoding($sDatabaseEncoding,$sPageEncoding,$sString){ + return iconv($sDatabaseEncoding,$sPageEncoding,$sString); + } + */ + +require_once("phpUtil.inc"); + +/** + * Ajoute la cha�ne de caract�re au fichier de log $sFileName. + * \param $sString Cha�ne de caract�res. + * \param $sFileName Fichier dans lequel �crire la cha�ne. + * \return un bool�en, true si l'�criture a fonctionn� sinon false. + */ +function writeToLog($sString, $sFileName) { + if (empty($sFileName)) + return false; + global $properties, $sMessageLogError, $sFolderLib; + + // Si le répertoire de log n'existe pas : création + if (!is_dir(dirname($sFileName))) + mkdir(dirname($sFileName), 0777, true); + if (empty(pathinfo($sFileName, PATHINFO_EXTENSION))) + return false; + + // Add Date and User informations before writing message in log file + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $sString = str_replace(chr(13), '[\n]', $sString); + $sString = str_replace(chr(10), '[\n]', $sString); + if(isset($_SESSION['ses_Login']) && isset($_SERVER['REMOTE_ADDR']) && isset($_SERVER['REMOTE_PORT'])){ + $sPrelog = date("d/n/Y H:i:s").' '.$_SESSION['ses_Login'].' '.$_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['REMOTE_PORT']; + } else { + $sPrelog = date("d/n/Y H:i:s"); + } + + $sMessageLogtoWrite = $sPrelog . $properties["log_delim"] . $sString . CR . LF; + + // Rename old file if greater than porperties log_size (maximum log size to open it through app in Kb) + // Get size of Log file in bytes + $iLogFileSize = filesize($sFileName); + + if($iLogFileSize !== false){ + // get size of log message + $iMessageLength = strlen($sMessageLogtoWrite); + $iTotalSizeKb = ($iLogFileSize + $iMessageLength) / 1024; + // compare with porperties log_size (maximum log size to open it through app in Kb) + if($iTotalSizeKb >= $properties['log_size'] - 1){ + // Rename of the original file to split log and keep the possibility to read it through application + $sFileSplitName = str_replace(".log", "." . date("Y_m_d_U") . ".log", $sFileName); + if(!rename($sFileName, $sFileSplitName)){ + $sMessageLogError = ERROR_IMPOSSIBLE_WRITE . $sFileName . ERROR_RIGHTS_ON_FILE . " (" . $sString . ")."; + } + } + } + + // create if needed and open log file to write log message inside. + $handle = fopen($sFileName, 'a'); + if (fwrite($handle, $sMessageLogtoWrite) === false) { + fclose($handle); + if (is_writable($sFileName)) { + $sMessageLogError = ERROR_IMPOSSIBLE_WRITE . $sFileName . ERROR_RIGHTS_ON_FILE . " (" . $sString . ")."; + } else { + $sMessageLogError = ERROR_IMPOSSIBLE_WRITE . $sFileName . ERROR_WRITING_FILE . " (" . $sString . ")."; + } + return false; + } else { + fclose($handle); + $sMessageLogError = ""; + return true; + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier des log SQL. + * \param $sString Cha�ne de caract�res. + */ +function writeToSqlLog($sString) { + global $properties; + if (isSet($properties["log_mode"])) { + if ($properties["log_mode"] == true) { + writeToLog($sString, $properties["sql_log_file"]); + } + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier des log SQL. + * \param $sString Cha�ne de caract�res. + */ +function writeToSqlErrorLog($sString) { + global $properties; + if (isSet($properties["log_mode"])) { + if ($properties["log_mode"] == true) { + writeToLog($sString, $properties["sql_error_log_file"]); + } + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier des log ERROR. + * \param $sString Cha�ne de caract�res. + */ +function writeToErrorLog($sString) { + global $properties; + if (isSet($properties["log_mode"])) { + if ($properties["log_mode"] == true) { + writeToLog($sString, $properties["error_log_file"]); + } + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier des log Proxy. + * \param $sString Cha�ne de caract�res. + */ +function writeToProxyLog($sString) { + global $properties; + if (isSet($properties["log_mode"])) { + if ($properties["log_mode"] == true) { + writeToLog($sString, $properties["proxy_log_file"]); + } + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier des log DEBUG. + * \param $sString Cha�ne de caract�res. + */ +function writeToDebugLog($sString) { + global $properties; + if (isSet($properties["debug_mode"])) { + if ($properties["debug_mode"] == true) { + writeToLog($sString, $properties["debug_log_file"]); + } + } +} + +/** + * Ajoute la cha�ne de caract�re au fichier $sFileName. + * \param $sString Cha�ne de caract�res. + * \param $sFileName Fichier dans lequel �crire la cha�ne. + * \return un bool�en, true si l'�criture a fonctionn� sinon false. + */ +function writeToFile($sString, $sFileName) { + global $properties, $sFolderLib; + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $handle = fopen($sFileName, 'a'); + if (fwrite($handle, $sString . CR . LF)) { + fclose($handle); + if (is_writable($sFileName)) { + $sMessageLogError = ERROR_IMPOSSIBLE_WRITE . $sFileName . ERROR_RIGHTS_ON_FILE . " (" . $sString . ")."; + } else { + $sMessageLogError = ERROR_IMPOSSIBLE_WRITE . $sFileName . ERROR_WRITING_FILE . " (" . $sString . ")."; + } + return false; + } else { + fclose($handle); + $sMessageLogError = ""; + return true; + } +} + +?> \ No newline at end of file diff --git a/vas/rest/class/vmlib/phpUtil.inc b/vas/rest/class/vmlib/phpUtil.inc new file mode 100755 index 0000000000000000000000000000000000000000..dee4b832527ccda3d2af6ca01b50acc49085d063 --- /dev/null +++ b/vas/rest/class/vmlib/phpUtil.inc @@ -0,0 +1,744 @@ +<?php + +/* + * @brief Fonctions php diverses + * + * @author Fabien Marty <fabien.marty@veremes.com> + */ +/* + * Variable globale stockant le nom de dossier lib. + */ +$sFolderLib = "vmlib"; + +/** + *This method remove all the backslashes of the element in an array. + *@file vmlib/phpUtil.inc + *@return $aString An array without the backlashes. + */ +function stripslashes_deep($aString) { + $aString = is_array($aString) ? + array_map('stripslashes_deep', $aString) : + stripslashes($aString); + + return $aString; +} + +/** + *This method allow to upload a file on a server. + *@file vmlib/phpUtil.inc + *@param $sNomObjet Name of the object. + *@param $sFileType Type of file needed. + *@param $sServerPath New path of the file. + *@param $sMaxSize Maximal size of the file. + *@return $sErrorMsg The error message. + */ +function uploadFile($sNomObjet, $sFileType, $sServerPath, $sMaxSize) { + global $properties, $sFolderLib; + loadLang($sFolderLib, $properties["language"], $sFolderLib . "/"); + $aExtensionPicture = array('gif', 'jpg', 'jpeg', 'png'); + $aExtensionPictureAndPdf = array('gif', 'jpg', 'jpeg', 'png', 'pdf'); + $aExtensionFile = array('pdf', 'gif', 'jpg', 'jpeg', 'png', 'txt'); + $aExtensionZip = array('zip', 'gex'); + $aExtensionFmw = array('fmw'); + $aForbiddenExtension = explode('|', str_replace("*.", "", $properties['forbidden_extension'])); + $sTmpFile = $_FILES[$sNomObjet]['tmp_name']; + // Si l'utilisateur n'a indiqué aucun fichier à uploader, il ne se passe rien + $sErrorMsg = ""; + + if ($sTmpFile == '') { + if ($_FILES[$sNomObjet]['name'] != "") { + switch ($_FILES[$sNomObjet]['error']) { + case "1" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_UPLOAD_MAX_FILE_SIZE; + break; + case "2" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_MAX_FILE_SIZE; + break; + case "3" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_PARTIAL_DOWNLOAD; + break; + case "4" : + $sErrorMsg = ERROR_NO_FILE_DOWNLOADED; + break; + case "6" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_MISSING_TEMP_FOLDER; + break; + case "7" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_WRITING_DISK; + break; + case "8" : + $sErrorMsg = ERROR_DOWNLOAD_FILE . $_FILES[$sNomObjet]['name'] . " : " . ERROR_PHP_EXT_SEND; + break; + } + writeToErrorLog($sErrorMsg); + } + return $sErrorMsg; + } + $aTemp = explode("\\", $sServerPath); + if (is_uploaded_file($sTmpFile)) { + if (!in_array(extension($aTemp[count($aTemp) - 1]), $aForbiddenExtension)) { + //Teste si le fichier correspont au format voulu. + $bAllowUpload = false; + $sFormat = ""; + switch ($sFileType) { + case "image" : + if (in_array(extension($aTemp[count($aTemp) - 1]), $aExtensionPicture)) { + $bAllowUpload = true; + } else { + foreach ($aExtensionPicture as $sValue) { + $sFormat .= " " . $sValue; + } + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + break; + case "image-pdf" : + if (in_array(extension($aTemp[count($aTemp) - 1]), $aExtensionPictureAndPdf)) { + $bAllowUpload = true; + } else { + foreach ($aExtensionPictureAndPdf as $sValue) { + $sFormat .= " " . $sValue; + } + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + break; + case "document" : + if (in_array(extension($aTemp[count($aTemp) - 1]), $aExtensionFile)) { + $bAllowUpload = true; + } else { + foreach ($aExtensionFile as $sValue) { + $sFormat .= " " . $sValue; + } + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + break; + case "zip" : + if (in_array(extension($aTemp[count($aTemp) - 1]), $aExtensionZip)) { + $bAllowUpload = true; + } else { + foreach ($aExtensionZip as $sValue) { + $sFormat .= " " . $sValue; + } + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + break; + case "fmw" : + if (in_array(extension($aTemp[count($aTemp) - 1]), $aExtensionFmw)) { + $bAllowUpload = true; + } else { + foreach ($aExtensionFmw as $sValue) { + $sFormat .= " " . $sValue; + } + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + break; + default : + + $bAllowUpload = true; + + break; + } + + //Teste si le fichier n'est pas de trop grande taille. + if ($_FILES[$sNomObjet]['size'] > $sMaxSize || $_FILES[$sNomObjet]['error'] == 1) { + $bAllowUpload = false; + if ($_FILES[$sNomObjet]['size'] > $sMaxSize) + $sErrorMsg .= FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . OF_LABEL_PHPUTIL . $_FILES[$sNomObjet]['size'] . ERROR_EXCEED_MAX_SIZE . ' (' . $sMaxSize . LABEL_BYTES_PHPUTIL . ').'; + if ($_FILES[$sNomObjet]['error'] > $sMaxSize) + $sErrorMsg .= FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_EXCEED_MAX_SIZE_PHP . ' (' . $sMaxSize . LABEL_BYTES_PHPUTIL . ').'; + } + //Lance l'upload. + if ($bAllowUpload) { + if (!copy($sTmpFile, $sServerPath)) { + writeToErrorLog(ERROR_COPYING_FILE . $_FILES[$sNomObjet]['name'] . ON_SERVER_PHPUTIL . ', ' . $sTmpFile . ', ' . $sServerPath); + $sErrorMsg = ERROR_COPYING_FILE . $_FILES[$sNomObjet]['name'] . ON_SERVER_PHPUTIL . '.'; + } + unlink($sTmpFile); + //chmod($sServerPath,755); + } + } else { + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_NOT_FILE . $sFileType . ERROR_VALID_FILE . $sFormat . '.'; + } + } else { + writeToErrorLog(ERROR_FILE . $_FILES[$sNomObjet]['name'] . ERROR_DOWNLOAD_SERVER); + $sErrorMsg = FILE_LABEL_PHPUTIL . $_FILES[$sNomObjet]['name'] . ERROR_DOWNLOAD_SERVER . ' (' . ERROR_CODE_PHPUTIL . $_FILES[$sNomObjet]['error'] . ').'; + } + + return $sErrorMsg; +} + +/** + *This method return the extension of a file. + *@file vmlib/phpUtil.inc + *@param $sString Full name of a file. + *@return Retourne une chaine. + */ +function extension($sString) { + $aTemp = explode(".", $sString); + $sString = strtolower($aTemp[count($aTemp) - 1]); + + return $sString; +} + +/** + *This method return the name of a file from its full path. + *@file vmlib/phpUtil.inc + *@param $sFullFileName Full path of a file. + *@return $aTemp2 The file name. + */ +function getFileName($sFullFileName) { + $aTemp = explode("/", $sFullFileName); + $aTemp2 = explode("\\", $aTemp[(count($aTemp) - 1)]); + + return $aTemp2[(count($aTemp2) - 1)]; +} + +/** + *Creates a compressed zip file + *@file vmlib/phpUtil.inc + *@param string $sFolder + *@param string $sDestination + *@param string $sPassword + *@return boolean + */ +function createZip($sFolder, $sDestination, $sExtensionToExclude = '', $sPassword = '', $bDeleteFiles = false) { + if (!empty($sExtensionToExclude)) { + $aExtensionToExclude = explode('|', $sExtensionToExclude); + } else { + $aExtensionToExclude = array(); + } + $sFolder = rtrim($sFolder, "/"); + + $zip = new ZipArchive(); + + if ($zip->open($sDestination, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) { + die("An error occurred creating your ZIP file."); + } + + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($sFolder), RecursiveIteratorIterator::LEAVES_ONLY + ); + $aCompressedFiles = array(); + foreach ($files as $name => $file) { + if (!$file->isDir()) { + $filePath = $file->getRealPath(); + + // Récupération de l'extension + $oFileInfo = new SplFileInfo($filePath); + $sExtension = $oFileInfo->getExtension(); + + $relativePath = substr($filePath, strlen($sFolder) + 1); + if (in_array($sExtension, $aExtensionToExclude)) { + continue; + } + if ($zip->addFile($filePath, $relativePath)) + $aCompressedFiles[] = $filePath; + // Mot de passe. + if (!empty($sPassword)) + $zip->setEncryptionName($oFileInfo->getFilename(), ZipArchive::EM_AES_256, $sPassword); + } + } + + if ($zip->close()) { + // Suppression des fichiers compressés. + if ($bDeleteFiles) { + foreach ($aCompressedFiles as $sFilePath) { + if (file_exists($sFilePath)) + unlink($sFilePath); + } + } + } + return file_exists($sDestination); +} + +/** + *Unzip a compressed zip file + *@file vmlib/phpUtil.inc + *@param string $sZipFile + *@param string $sDestination + */ +function unZip($sZipFile, $sDestination) { + $zip = new ZipArchive; + $res = $zip->open($sZipFile); + if ($res === TRUE) { + // extract it to the path we determined above + $zip->extractTo($sDestination); + $zip->close(); + return file_exists($sDestination); + } else { + return false; + } +} + +/** + *@file vmlib/phpUtil.inc + *@brief Teste un code pour savoir si il correspond à une fréquence. + * Ce code est d'un jour (de 1 à 31), d'un mois (de 1 à 12) et d'un type de jour de la semaine (de 1 à 7). + * Ces éléments doivent être définis ainsi : * défini tout le temps et / défini une répétition. + *@param $sCode Code of the frequency. + *@return $sReturn Return nothing if the code is good else return an error message. + */ +function TesteCode($sCode) { + $bIsCorrecte = true; + $sErrorMessage = ""; + $aCode = explode(" ", $sCode); + if (count($aCode) == 3) { + $aCode = Array('jour' => $aCode[0], 'mois' => $aCode[1], 'jour_semaine' => $aCode[2]); + + //Teste sur le jour + if ($aCode['jour'] != "*") { + if (($aCode['mois'] == "*" || is_numeric($aCode['mois'])) && $aCode['jour_semaine'] == "*") { + if (is_numeric($aCode['jour'])) { + if ($aCode['jour'] >= 32 && $aCode['jour'] <= 0) { + $sErrorMessage = ERROR_DAY_CODE . $aCode['jour'] . ERROR_CODE_NOT_VALID . ERROR_NOT_INF . "1" . ERROR_NOT_SUP . '31.'; + $bIsCorrecte = false; + } + } else { + if (substr($aCode['jour'], 0, 2) != '*/' || !is_numeric(substr($aCode['jour'], 2, 2))) { + $sErrorMessage = ERROR_DAY_CODE . $aCode['jour'] . ERROR_CODE_NOT_VALID; + $bIsCorrecte = false; + } else { + if (substr($aCode['jour'], 2, 1) >= 31 && substr($aCode['jour'], 2, 2) <= 0) { + $sErrorMessage = ERROR_DAY_CODE . $aCode['jour'] . ERROR_CODE_NOT_VALID . ERROR_NOT_INF . '1' . ERROR_NOT_SUP . '30.'; + $bIsCorrecte = false; + } + } + } + } else { + $sErrorMessage = ERROR_DAY_WEEK; + $bIsCorrecte = false; + } + } + + //Teste sur le mois + if ($aCode['mois'] != "*" && $bIsCorrecte == true) { + if (($aCode['jour'] == "*" || is_numeric($aCode['jour']) ) && $aCode['jour_semaine'] == "*") { + if (is_numeric($aCode['mois'])) { + if ($aCode['mois'] >= 13 && $aCode['mois'] <= 0) { + $sErrorMessage = ERROR_MONTH_CODE . $aCode['mois'] . ERROR_CODE_NOT_VALID . ERROR_NOT_INF . '1' . ERROR_NOT_SUP . '12.'; + $bIsCorrecte = false; + } + } else { + if (substr($aCode['mois'], 0, 2) != '*/' || !is_numeric(substr($aCode['mois'], 2, 2))) { + $sErrorMessage = ERROR_MONTH_CODE . $aCode['mois'] . ERROR_CODE_NOT_VALID; + $bIsCorrecte = false; + } else { + if (substr($aCode['mois'], 2, 1) >= 13 && substr($aCode['mois'], 2, 2) <= 0) { + $sErrorMessage = ERROR_MONTH_CODE . $aCode['mois'] . ERROR_CODE_NOT_VALID . ERROR_CODE_NOT_VALID . ERROR_NOT_INF . '1' . ERROR_NOT_SUP . '12.'; + $bIsCorrecte = false; + } + } + } + } else { + $sErrorMessage = ERROR_DAY_WEEK; + $bIsCorrecte = false; + } + } + + //Teste sur le jour de la semaine + if ($aCode['jour_semaine'] != "*" && $bIsCorrecte == true) { + if ($aCode['jour'] == "*" && $aCode['mois'] == "*") { + if (is_numeric($aCode['jour_semaine'])) { + $sErrorMessage = ERROR_WEEK_CODE . $aCode['jour_semaine'] . ERROR_CODE_NOT_VALID . ERROR_NUMBER_PHPUTIL; + $bIsCorrecte = false; + } else { + if (substr($aCode['jour_semaine'], 0, 2) != '*/' || !is_numeric(substr($aCode['jour_semaine'], 2, 2))) { + $sErrorMessage = ERROR_WEEK_CODE . $aCode['jour_semaine'] . ERROR_CODE_NOT_VALID; + $bIsCorrecte = false; + } else { + if (substr($aCode['jour_semaine'], 2, 2) >= 13 && substr($aCode['jour_semaine'], 2, 2) <= 0) { + $sErrorMessage = ERROR_WEEK_CODE . $aCode['jour_semaine'] . ERROR_CODE_NOT_VALID . ERROR_CODE_NOT_VALID . ERROR_NOT_INF . '1' . ERROR_NOT_SUP . '12.'; + $bIsCorrecte = false; + } + } + } + } else { + $sErrorMessage = ERROR_DAY_WEEK; + $bIsCorrecte = false; + } + } + } else { + $sErrorMessage = ERROR_CODE_3_VALUES; + $bIsCorrecte = false; + } + + $sReturn = $sErrorMessage; + + return $sReturn; +} + +/** + * Cette méthode permet de générer un nom de fichier unique. + * \return une chaîne de caractères. + */ +function UniqFileName() { + $sUniqFileName = date('YmdHis') . rand(1, 100000); + return $sUniqFileName; +} + +/* + * function html2rgb + * \brief Ce code convertit les couleurs HTML (codées en hexa), en RGB . + * \param $color chaine correspondant à la couleur + * \return un tableau correspondant à la couleur en rgb + */ + +function html2rgb($color) { + // gestion du #... + if (substr($color, 0, 1) == "#") + $color = substr($color, 1, 6); + $aTableau[0] = hexdec(substr($color, 0, 2)); + $aTableau[1] = hexdec(substr($color, 2, 2)); + $aTableau[2] = hexdec(substr($color, 4, 2)); + return $aTableau; +} + +/* + * function rgb2html + * \brief La réciproque exacte de la fonction html2rgb. + * \param $aTableau tableau correspondant à la couleur en rgb + * \return un chaine correspondant à la couleur + */ + +function rgb2html($aTableau) { + for ($i = 0; $i <= 2; $i++) { + $aTableau[$i] = bornes($aTableau[$i], 0, 255); + } + // Le str_pad permet de remplir avec des 0 + // parce que sinon rgb2html(Array(0,255,255)) retournerai #0ffff<=manque un 0 ! + return "#" . str_pad(dechex(($aTableau[0] << 16) | ($aTableau[1] << 8) | $aTableau[2]), 6, "0", STR_PAD_LEFT); +} + +/* + * function rgb2html + * \brief Une petite fonction utile pour borner les nombres entre 0 et 255. + */ + +function bornes($nb, $min, $max) { + if ($nb < $min) + $nb = $min; // $nb est borné bas + if ($nb > $max) + $nb = $max; // $nb est Borné haut + return $nb; +} + +/* + * function verifyFolder + * \brief vérifie l'existance d'un répertoire + * \param $sFolder : chemin du répertoire + * \return $bFolderExist : booleen , true si le répertoire existe sinon false + */ + +function verifyFolder($sFolder) { + @$bFolderExist = dir($sFolder); + return (@$bFolderExist); +} + +/** + * Cette fonction permet de supprimer un dossier sur le serveur. + * \param $sDossier Dossier à supprimer. + * return un booleen. + */ +function clearDir($sDossier) { + $ouverture = @opendir($sDossier); + if (!$ouverture) + return; + while ($sFichier = readdir($ouverture)) { + + if ($sFichier == '.' || $sFichier == '..') + continue; + if (is_dir($sDossier . "/" . $sFichier)) { + $bCleared = clearDir($sDossier . "/" . $sFichier); + if (!$bCleared) + return false; + } + else { + $bCleared = @unlink($sDossier . "/" . $sFichier); + if (!$bCleared) + return false; + } + } + closedir($ouverture); + $bCleared = @rmdir($sDossier); + if (!$bCleared) + return false; + return true; +} + +/* + * function loadLang + * charge le fichier de lang + */ + +function loadLang($folderExt, $lang = "fr", $folderRoot = "", $encodage = "UTF-8") { + if ($lang == "") { + $lang = "fr"; + } + if ($folderExt != "") { + include_once($folderRoot . 'lang_' . $folderExt . '/' . $lang . '-lang.inc'); + } else { + include_once($folderRoot . 'lang/' . $lang . '-lang.inc'); + } +} + +/** + * Cette fonction retourne le contenu d'un fichier dans une variable. + * \param $sFilePath chaine Nom complet du fichier. + * \return une chaine contenant le contenu du fichier, rien si le fichier n'existe pas. + */ +function getFileContent($sFilePath) { + $sFileContent = ""; + if (file_exists($sFilePath)) { + ob_start(); + include($sFilePath); + $sFileContent = ob_get_contents(); + ob_end_clean(); + } + return $sFileContent; +} + +/** + * ? + */ +function convert($value_in = false, $source_base = 10, $target_base = 32) { + // We use these values for our conversions + $values = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '_'); + $characters = array_flip($values); + $string_out = ''; + // Easy answers + if ($source_base == $target_base) { + return $value_in; + } + $len = strlen($value_in); + $sum = array(); + if ($source_base > $target_base) { + for ($i = 0; $i < $len; $i++) { + $char = substr($value_in, $len - $i - 1, 1); + $sum[$i] = $characters[$char] * pow($source_base, $i); + } + } else { + if ($source_base != 10) { + $value = convert($value_in, $source_base, 10); + } else { + $value = $value_in; + } + $cnt = 0; + while ($value > 0) { + $times = $value / $target_base; + $sum[] = mod($value, $target_base); + $value = floor2($times); // get rid of our remainder + } + for ($i = count($sum); $i > 0; $i--) { + $string_out .= $values[$sum[$i - 1]]; + } + return $string_out; + } + if ($target_base == 10) { + return array_sum($sum); + } + return implode($sum); +} + +function mod($val, $mod) { + return $val - floor2($val / $mod) * $mod; +} + +function floor2($val) { + $bits = explode('.', $val); + return $bits[0]; +} + +/** + * Send a websocket message + * @param string $webSocketServer + * @param string $webSocketPort + * @param string $webSocketAlias + * @param array $aPlayload array to convent JSON and send + */ +function sendWebsocketMessage($webSocketServer, $webSocketPort, $webSocketAlias, $aPlayload) { + require_once 'vmlib/class.websocket_client.php'; + + $client = new WebsocketClient; + $client->connect($webSocketServer, $webSocketPort, '/' . $webSocketAlias); + + $sPayload = json_encode($aPlayload); + + // Check each 10ms if the server is yet connected and send the data via the websocket + for ($index = 0; $index < 100; $index++) { + if ($client->isConnected() === true) { + $client->sendData($sPayload); + break; + } else { + usleep(10000); + } + } + + usleep(5000); +} + +/** + * \class array2xml + * \brief array2xml Class \n \n Cette classe totalement générique permet de générer du XML à partir d'un tableau PHP + */ +class array2xml extends DomDocument { + + private $xpath; + private $sRoot; + private $sNodeName; + + /** + * Constructeur + * \param $sRoot Nom du premier noeud (string) + * \param $sNodeName The name numeric keys are called (string) + */ + public function __construct($sRoot = 'root', $sNodeName = 'node') { + parent::__construct(); + //$this->encoding = "ISO-8859-1"; + $this->encoding = "utf-8"; + $this->formatOutput = true; + $this->sNodeName = $sNodeName; + $this->sRoot = $this->appendChild($this->createElement($sRoot)); + $this->xpath = new DomXPath($this); + } + + /* + * Crée le XML à partir du tableau + * \param $aValueXml Le tableau à convertir + * \param $sNode Nom du noeud dans lequelle inlure les valeurs (string) + */ + + public function createNode($aValueXml, $sNode = null) { + if (is_null($sNode)) { + $sNode = $this->sRoot; + } + foreach ($aValueXml as $element => $value) { + $element = is_numeric($element) ? $this->sNodeName : $element; + $child = $this->createElement($element, (is_array($value) ? null : utf8_encode($value))); + $sNode->appendChild($child); + if (is_array($value)) { + self::createNode($value, $child); + } + } + } + + /* + * Retourne le XML généré sous forme de chaine + * return le XML (string) + */ + + public function __toString() { + return $this->saveXML(); + } + + /* + * Perform an XPath query on the XML representation of the array + * \param str $query - query to perform + * return mixed + */ + + public function query($query) { + return $this->xpath->evaluate($query); + } + +} + +/** + * Generate an unique id + */ +function vitisUniqId() { + return uniqid(rand(10000, 99999)); +} + +/** + * Generate an unique id + * @param {integer} $iLength length og the random string before hash it + * @return string random string generated by hashing a random string concatenated with current timestamp + */ +function getUniqRandomId($iLength = 64){ + $sCharacters = 'abcdefghijklmnopqrstuvwxyz0123456789'; + $sString = ''; + $iMax = strlen($sCharacters) - 1; + + for ($i = 0; $i < $iLength; $i++) { + $sString .= $sCharacters[(mt_rand(0, $iMax*10) % $iMax)]; + } + + $sString .= time(); + + return sha1($sString, false); + } + +/** + * Copie un dossier ainsi que son contenu + * @param {string} $src Source + * @param {string} $dst Destination + */ +function copyDirectory($src,$dst) { + $dir = opendir($src); + @mkdir($dst); + while(false !== ( $file = readdir($dir)) ) { + if (( $file != '.' ) && ( $file != '..' )) { + if ( is_dir($src . '/' . $file) ) { + copyDirectory($src . '/' . $file,$dst . '/' . $file); + } + else { + copy($src . '/' . $file,$dst . '/' . $file); + } + } + } + closedir($dir); +} + +// end of class + +/** + * Get a date format + * @param string $sUserDateFormat + * @param string $sDateType + * \return date pattern + */ +function getDatePattern($sUserDateFormat, $sDateType) { + $Pattern= ""; + switch ($sDateType) { + case "year" : + $Pattern= "YYYY"; + break; + case "month" : + $Pattern= "MM"; + break; + case "day" : + $Pattern= "DD"; + break; + case "yeartomonth" : + $Pattern= "YYYY-DD"; + break; + case "yeartoday" : + $Pattern= substr($sUserDateFormat, 10); + break; + case "yeartominute" : + $Pattern= str_replace("[FORMATDATE]", $sUserDateFormat, "[FORMATDATE] HH24:MI:SS"); + break; + case "hourtosecond" : + $Pattern= 'HH24:MI:SS'; + break; + case "yeartosecond" : + $Pattern= str_replace("[FORMATDATE]", $sUserDateFormat, "[FORMATDATE] HH24:MI:SS"); + break; + case "yeartosecondtz" : + $Pattern= str_replace("[FORMATDATE]", $sUserDateFormat, "[FORMATDATE] HH24:MI:SStz"); + break; + case "yeartomillisecond" : + $Pattern= str_replace("[FORMATDATE]", $sUserDateFormat, "[FORMATDATE] HH24:MI:SS.ms"); + break; + case "yeartomillisecondtz" : + $Pattern= str_replace("[FORMATDATE]", $sUserDateFormat, "[FORMATDATE] HH24:MI:SS.mstz"); + break; + } + return $Pattern; +} +?> diff --git a/vas/rest/class/vmlib/stringUtil.inc b/vas/rest/class/vmlib/stringUtil.inc new file mode 100755 index 0000000000000000000000000000000000000000..f1ebb95912ae82ee7b94ff11f7a118315dabfd9c --- /dev/null +++ b/vas/rest/class/vmlib/stringUtil.inc @@ -0,0 +1,149 @@ +<?php + +/* + * stringUtil.inc : fonctions sur les cha�nes de caract�res + */ + +function addDelimitedAttribute($sMain, $sAdded, $sDelim, $sProtectField) { + // renvoie la concat�nation des cha�nes $main et $added en ajoutant le d�limiteur $sDelim + if ($sMain == "") + $sMain = $sProtectField . $sAdded . $sProtectField; + else + $sMain .= $sDelim . $sProtectField . $sAdded . $sProtectField; + return $sMain; +} + +function addDelimitedString($sMain, $sAdded, $sDelim) { + // renvoie la concat�nation des cha�nes $main et $added en ajoutant le d�limiteur $sDelim + if ($sMain == "") + $sMain = $sAdded; + else + $sMain .= $sDelim . $sAdded; + return $sMain; +} + +// Convertit une chaine geometrique type veremes (x@y x@y) en wkt +function vm2wkt($sGeom, $sType) { + + switch ($sType) { + + case 'point' : + $aPointCoord = array(); + $aPointCoord = split("@", $sGeom); + $sWkt = "POINT ("; + + $aPointCoordxy[0]["x"] = $aPointCoord[0]; + $aPointCoordxy[0]["y"] = $aPointCoord[1]; + + $sWkt = $sWkt . $aPointCoordxy[0]["x"] . " " . $aPointCoordxy[0]["y"] . ")"; + + break; + + case 'line' : + $aLineCoord = array(); + $aPoint = array(); + $aLineCoord = split(" ", $sGeom); + + $sWkt = "LINESTRING ("; + $i = 0; + + while ($aLineCoord[$i]) { + $aPoint = split("@", $aLineCoord[$i]); + $aLineCoordxy[$i]["x"] = $aPoint[0]; + $aLineCoordxy[$i]["y"] = $aPoint[1]; + $i++; + } + + $i = 0; + while ($aLineCoordxy[$i]) { + $sWkt = $sWkt . $aLineCoordxy[$i]["x"] . " " . $aLineCoordxy[$i]["y"] . ","; + $i++; + } + $sWkt = rtrim($sWkt, ','); + $sWkt = $sWkt . ")"; + break; + + case 'polygon': + + $sWkt = "POLYGON (("; + $aShapeCoord = array(); + $aShapeCoord = split(" ", $aRequest["mf_selectShape"]); + + $i = 0; + while ($aShapeCoord[$i]) { + $aPoint = split("@", $aShapeCoord[$i]); + $aShapeCoordxy[$i]["x"] = $aPoint[0]; + $aShapeCoordxy[$i]["y"] = $aPoint[1]; + $i++; + } + + $i = 0; + while ($aShapeCoord[$i]) { + $sWkt = $sWkt . $aShapeCoordxy[$i]["x"] . " " . $aShapeCoordxy[$i]["y"] . ","; + $i++; + } + $sWkt = rtrim($sWkt, ','); + $sWkt = $sWkt . "))"; + + break; + } + return $sWkt; +} + +function wkt2vm($sWkt) { + + $sWkt = ltrim($sWkt, 'POLYGON('); + $sWkt = rtrim($sWkt, ')'); + $sWkt = str_replace(" ", "@", $sWkt); + $sWkt = str_replace(",", " ", $sWkt); + + return $sWkt; +} + +/* + * Fonction qui permet de prendre une chaine de caractere + * De la d�couper selon un d�limiter choisi en permettant de mettre des caract�res de protections + */ + +function stringExplode($sValue, $cDelimiter, $cProtectDeb, $cProtectFin) { + $iArray = 0; + $iChar = 0; + $iLength = strlen($sValue); + $aPart = array(); + while ($iChar < $iLength) { + if ($sValue[$iChar] == $cDelimiter) { + $iArray++; + $iChar++; + } else { // Caract�re diff�rent de $cDelimiter + if ($sValue[$iChar] == $cProtectDeb) { // Le caract�re est �gal � $cProtectDeb + $aPart[$iArray].=$sValue[$iChar]; + $iChar++; + while ($sValue[$iChar] != $cProtectFin) { // On boucle jusqu'� la trouver $cProtectFin + $aPart[$iArray].=$sValue[$iChar]; + $iChar++; + } + } + $aPart[$iArray].=$sValue[$iChar]; + $iChar++; + } + } //while + return $aPart; +} + +/* + * Fonction qui normalise une chaine de caract�re + * En remplacant tout les caract�res sp�ciaux par des _ + */ + +function normalizeString($sString) { + + $sString = str_replace(" ", "_", $sString); + $sString = str_replace(":", "_", $sString); + $sString = str_replace("/", "_", $sString); + $sString = str_replace("\\", "_", $sString); + $sString = str_replace("*", "_", $sString); + + return $sString; +} + +?> \ No newline at end of file diff --git a/vas/rest/class/wab_lib/BusinessObject.class.inc b/vas/rest/class/wab_lib/BusinessObject.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..36ae854ee3dd0789c11f938c6eba90dda09a36bf --- /dev/null +++ b/vas/rest/class/wab_lib/BusinessObject.class.inc @@ -0,0 +1,390 @@ +<?php + +//Par défaut il faudra inclure la lib de log pour pouvoir logger +//D’autres lib pourront être chargées ici en fonction des besoins + +require_once("vmlib/logUtil.inc"); +require_once("vmlib/Email.class.inc"); +require_once("vmlib/phpUtil.inc"); +require_once("gtf_lib/gtf_object/User.class.inc"); + +class WabBusinessObject { + + protected $bo_id; + protected $className; + private $status; + protected $history; + protected $oBd; + public $aValues = array(); + protected $aTableInfo = array(); + protected $aProperties = array(); + protected $aSql = array(); + protected $bNoError = true; + protected $sErrorMessage; + + /* * **************************************************** + Class constructor + \oBd : Connection object. + \aProperties : Array of properties. + + * **************************************************** */ + + public function __construct($oBd, $aTableInfo, $aValues, $aProperties, $className, $iId = null) { + require 'BusinessObject.class.sql.inc'; + //$this->aTableInfo = $aTableInfo; + $this->oBd = $oBd; + $this->aValues = $aValues; + $this->aProperties = $aProperties; + $this->className = $className; + $this->bo_id = $iId; + $this->history = ""; + } + + /* * **************************************************** + Sauve l'action réalisé par l'utilisateur + \sEvent : action réalisé (changement de statut...) + * **************************************************** */ + + private function addHistoryEvent($sEvent) { + $this->history .= date('d/m/Y H:i') . ' | ' . $_SESSION['ses_Login'] . ' | ' . $sEvent . PHP_EOL; + } + + /* * **************************************************** + Change le statut + \sStatus : statut + * **************************************************** */ +/* + protected function setStatus($sStatus) { + // Mode insertion ? + if (!empty($this->iId)) + $this->bo_id = $this->iId; + // + $this->status = $sStatus; + $this->addHistoryEvent($this->status); + $this->save(); + } +*/ + public function wabSetStatus($sSchema, $sTable, $sBoNameField, $mBoIdValue, $sStatusName, $sView = '') { + require 'BusinessObject.class.sql.inc'; + + if($sView === ''){ + $sView = $sTable; + } + + // get status Id avec le StatusName + $aParams = array( + "SCHEMA"=> array("value"=> $sSchema, "type"=>'column_name'), + "TABLE"=> array("value"=> $sTable, "type"=>'column_name'), + "STATUS_NAME"=> array("value"=> $sStatusName, "type"=>'string') + ); + $oResultat = $this->oBd->executeWithParams($aSQL["getStatusId"], $aParams); + + $this->status = $this->oBd->objetSuivant($oResultat)->status_id; + // ajout historique + $this->addHistoryEvent($this->status); + // UPDATE dans la table avec le boName + $sSql = $aSQL["updateStatus"]; + $aParams = array( + "SCHEMA" => array("value"=> $sSchema, "type"=> 'column_name'), + "TABLE" => array("value"=> $sView, "type"=> 'column_name'), + "STATUS_ID" => array("value"=> $this->status, "type"=> 'number'), + "BOIDFIELD" => array("value"=> $sBoNameField, "type"=> 'column_name'), + "BOID" => array("value"=> $mBoIdValue, "type"=> 'number') + ); + + $this->oBd->executeWithParams($sSql, $aParams); + } + + public function wabGetStatus($sSchema, $sTable, $sBoNameField, $mBoIdValue) { + require 'BusinessObject.class.sql.inc'; + // GET Status name + $sSql = $aSQL["getStatusName"]; + $aParams = array( + "SCHEMA" => array("value"=> $sSchema, "type"=> 'column_name'), + "TABLE" => array("value"=> $sTable, "type"=> 'column_name'), + "BOIDFIELD" => array("value"=> $sBoNameField, "type"=> 'column_name'), + "BOID" => array("value"=> $mBoIdValue, "type"=> 'number') + ); + + $oResultat = $this->oBd->executeWithParams($sSql, $aParams); + return $this->oBd->objetSuivant($oResultat)->name; + } + /* * ******************************************************************** + Ajoute une note + \sLineAttribute : Champ de form. contenant la note à ajouter + \sNoteAttribute : Champ de form. contenant l'historique des notes + * ******************************************************************** */ + + protected function addNote($sLineAttribute, $sNoteAttribute) { + if (!empty($this->aValues[$sLineAttribute])) { + // Mode insertion ? + if (!empty($this->iId)) + $this->bo_id = $this->iId; + // + $note = preg_replace('/^<br>/', '', $this->aValues[$sNoteAttribute]); + $note .= date('d/m/Y H:i') . ' | ' . $_SESSION['ses_Login'] . ' | ' . $this->aValues[$sLineAttribute] . PHP_EOL; + $this->aValues[$sNoteAttribute] = $note; + $this->save(); + } + } + + /* * ********************************************* + Retourne toutes les infos d'une méthode pour + la transition + \sMethodName : Nom de la méthode + * ********************************************* */ + /* function getMethodParameters($sMethodName) { + $sSql = $this->aSql[$this->oBd->sgbd]['getMethodParameters']; + $sSql = str_replace('[methodName]', $sMethodName , $sSql); + $sSql = str_replace('[schema_gpm]', $this->aProperties['schema_gpm'] , $sSql); + $sSql = str_replace('[className]', $this->className , $sSql); + $result = $this->oBd->execute($sSql); + if(!$oBd->erreurRencontree) { + $oMethodParameters = $this->oBd->objetSuivant($result); + } + return $oMethodParameters; + } */ + + /* * ********************************************** + Exécute le processus de transition par défaut. + \sMethodName : Nom de la méthode + * ********************************************** */ + /* function setTransition($sMethodName) { + $oMethodParameters = $this->getMethodParameters($sMethodName . '()'); + // Before script + if (!empty($oMethodParameters->before_transition_code)) + eval($oMethodParameters->before_transition_code); + // Mise à jour du status + if ($this->bNoError) { + $this->setStatus($oMethodParameters->transition_to_status); + // After script + if (!empty($oMethodParameters->after_transition_code)) + eval($oMethodParameters->after_transition_code); + } + + } */ + + /* * ************************************************************ + Vérifie si la méthode appelée inexistante est une méthode de + transition. + \$sMethodName : Nom de la méthode inexistante + \$aMethodArguments : Arguments de la méthode + /Retour : Tableau avec un message si erreur. + * ************************************************************ */ + /* public function __call($sMethodName, $aMethodArguments) { + $sSql = $this->aSql[$this->oBd->sgbd]['isTransitionMethod']; + $sSql = str_replace('[methodName]', $sMethodName . '()' , $sSql); + $sSql = str_replace('[schema_gpm]', $this->aProperties['schema_gpm'] , $sSql); + $sSql = str_replace('[className]', $this->className , $sSql); + $oResult = $this->oBd->execute($sSql); + if(!$oBd->erreurRencontree) { + if ($this->oBd->nombreLigne ($oResult) > 0) { + $this->setTransition($sMethodName); + } + } + if ($this->bNoError) { + $aReturn = array('sStatus' => 0); + $bFinishCreateWorkspace = true; + } else { + $aReturn = array('sStatus' => 1, 'sMessage' => $this->sErrorMessage); + $bFinishCreateWorkspace = false; + } + return array('bFinishCreateWorkspace' => $bFinishCreateWorkspace, 'aReturn' => $aReturn); + } */ + + /* * ******************************************************************** + Modifie un paramètre de la classe + \sParameterName : nom du paramètre à modifier + \sValue : Nouvelle valeur + * ******************************************************************** */ + + function set($sParameterName, $sValue) { + if (property_exists($this, $sParameterName)) + $this->$sParameterName = $sValue; + else + $this->aValues[$sParameterName] = $sValue; + } + + /* * ******************************************************************** + Retourne un paramètre de la classe + \sParameterName : nom du paramètre à retourner + /Retour : Valeur du paramètre (si il existe) + * ******************************************************************** */ + + function get($sParameterName) { + if (property_exists($this, $sParameterName)) + return $this->$sParameterName; + } + + /* * ******************************************************************** + Sauve tous les paramètres de la classe + * ******************************************************************** */ + + function save() { + $aValues = $this->getClassParameters(); + $this->oBd->update($this->aTableInfo['schema_name'], str_replace($this->aTableInfo["module"] . "_", "", $this->aTableInfo['name']), $aValues, $this->aTableInfo['id_field'], $this->bo_id, $this->aTableInfo['id_field_type']); + } + + /* * ******************************************************************** + Fusionne les propriétés de l'objet et le tableau aValues + /Return : tableau + * ******************************************************************** */ + + function getClassParameters() { + foreach (get_object_vars($this) as $sIndex => $value) { + if (!is_array($value) && !is_object($value)) + $aClassParameters[$sIndex] = $value; + } + return array_merge($this->aValues, $aClassParameters); + } + + /* * ******************************************************************** + Insère une demande pour un projet FME + \$sWorkspaceKey : Clé du projet FME + \$sWkParams : Paramètres de la demande + \$iPriorityId : Priority level + \$iEmailOptionId : Identifier for email option + \$sEmailNotifications : Notificiation email address + \$sXslStyleSheet : Stylesheet path + /Retour : booléen (T:ok, F:erreur) + * ******************************************************************** */ + + function insertOrder($sWorkspaceKey, $sWkParams, $iPriorityId = 1, $iEmailOptionId = 3, $sEmailNotifications = null, $sXslStyleSheet = '') { + + $bNoError = true; + + if($properties['web_server_name'] === "[HTTP_HOST]"){ + $properties['web_server_name'] = "https://localhost"; + } + + // Get token + $sToken = $this->getToken(); + + if ($sToken !== false) { + + //get workspace id + $sSQL = "SELECT workspace_id FROM [SCHEMA_GTF].workspace WHERE key = [WK_KEY];"; + $aParams = array( + "SCHEMA_GTF" => array('value'=> $this->aProperties["schema_gtf"], 'type' => 'column_name'), + "WK_KEY" => array('value'=> $sWorkspaceKey, 'type' => 'string'), + ); + $oWK = $this->oBd->executeWithParams($sSQL, $aParams); + // oBd en erreur + $iWKid = $this->oBd->objetSuivant ($oWK)->workspace_id; + // Insertion de la demande + $sUrl = $this->aProperties['web_server_name'] . '/' . $this->aProperties['services_alias'] . '/gtf/userorders'; + $postfields = array( + 'token'=>$sToken, + 'order_date' => date('Y-m-d'), + 'workspace_id'=>$iWKid, + 'priority_id'=>$iPriorityId, + 'email_option_id'=>$iEmailOptionId, + 'wk_params'=>$sWkParams, + 'xslstylesheet'=>$sXslStyleSheet + ); + + if ( $sEmailNotifications != null){ + $postfields['email_notifications'] = $sEmailNotifications; + } + + $oReturn = $this->postCurlRequest ($sUrl, $postfields); + + } else + $sErrorMsg = 'Error while performing a cURL session (' . __METHOD__ . ' (get token))'; + + if ($sErrorMsg != '') { + writeToErrorLog($sErrorMsg); + $bNoError = false; + $this->sErrorMessage = $sErrorMsg; + } + $this->bNoError = $bNoError; + return $bNoError; + } + + /* * ******************************************************************** + Envoi un email + \$iEmailTemplateId : Id du modèle d'email. + /Retour : Message + * ******************************************************************** */ + + function sendMail($iEmailTemplateId = null) { + $sMessage = ''; + $aObjects = array('oBusinessObject' => $this); + if (empty($iEmailTemplateId)) + $iEmailTemplateId = $this->aProperties['default_mail_model']; + $oEmail = new Email($this->oBd, $iEmailTemplateId, $this->aProperties, $aObjects); + //if(!empty($sValuesKey)){ + //$oEmail->aValues = $this->aValues; + //} + if (!empty($oEmail->oEmailTemplate->name)) + $sMessage = $oEmail->send(); + return $sMessage; + } + + /* * ******************************************************************** + Retourne un objet de la classe "User". + \$sUserLogin : Login d'un utilisateur + /Retour : Objet de la classe User + * ******************************************************************** */ + + function getUser($sUserLogin) { + $sSql = $this->aSql[$this->oBd->sgbd]['getUserId']; + //$sSql = str_replace('[login]', $this->aValues[$sUserLogin], $sSql); + //$sSql = str_replace('[schema_framework]', $this->aProperties['schema_framework'], $sSql); + $aParams = array( + "login"=>array("value"=>$this->aValues[$sUserLogin], "type"=>"string"), + "schema_framework"=>array("value"=>$this->aProperties['schema_framework'], "type"=>"column_name"), + ); + $oResult = $this->oBd->executeWithParams($sSql, $aParams); + if (!$this->oBd->erreurRencontree) { + if ($this->oBd->nombreLigne($oResult) > 0) { + $oUser = new User($this->oBd, $this->oBd->objetSuivant($oResult)->user_id, $this->aProperties); + return $oUser; + } + } + } + + /* * ******************************************************************** + Récupére un token de session utilisateur. + /Retour : string token + * ******************************************************************** */ + + function getToken () { + + if($this->aProperties['web_server_name'] === "[HTTP_HOST]"){ + $this->aProperties['web_server_name'] = "https://localhost"; + } + $sUrl = $this->aProperties['web_server_name'] . '/' . $this->aProperties['services_alias'] . '/vitis/privatetoken'; + + if(!empty($_SESSION["ses_Login"])){ + $sUserPassword = trim(des(rtrim(utf8_decode($_SESSION['ses_Login'])), hexToString(rtrim($_SESSION['ses_Password'])), 0, 0, null)); + $postfields = array('user'=>$_SESSION["ses_Login"], 'password'=>$sUserPassword); + } else { + $postfields = array('user'=>$this->aProperties["login_bot"], 'password'=>$this->aProperties["pass_bot"]); + } + + $oToken = json_decode($this->postCurlRequest ($sUrl, $postfields)); + return $oToken->token; + } + + /* * ******************************************************************** + envoi une requete curl en POST + \$sUrl : Url pour envoyer la requete + \$postfields : array contenant les paramètres à envoyer + /Retour : string token + * ******************************************************************** */ + function postCurlRequest ($sUrl, $postfields) { + $ch = curl_init($sUrl); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json")); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + return curl_exec($ch); + } + +} + +?> diff --git a/vas/rest/class/wab_lib/BusinessObject.class.sql.inc b/vas/rest/class/wab_lib/BusinessObject.class.sql.inc new file mode 100755 index 0000000000000000000000000000000000000000..bf02e36db648547116d594e3689cc070a8d36fc8 --- /dev/null +++ b/vas/rest/class/wab_lib/BusinessObject.class.sql.inc @@ -0,0 +1,5 @@ +<?php + $aSQL["getStatusId"] = 'SELECT * FROM [SCHEMA].rt_[TABLE]_status WHERE name = [STATUS_NAME]'; + $aSQL["updateStatus"] = 'UPDATE [SCHEMA].v_[TABLE] SET status_id=[STATUS_ID] WHERE v_[TABLE].[BOIDFIELD]=[BOID]'; + $aSQL["getStatusName"] = 'SELECT name FROM [SCHEMA].rt_[TABLE]_status WHERE status_id = (SELECT status_id FROM [SCHEMA].[TABLE] WHERE [TABLE].[BOIDFIELD]=[BOID])'; +?> \ No newline at end of file diff --git a/vas/sql/sqlQueries.xml b/vas/sql/sqlQueries.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e745ccc2419751dc9590cbf5e359dc3ed5fb6a2 --- /dev/null +++ b/vas/sql/sqlQueries.xml @@ -0,0 +1,948 @@ +<?xml version="1.0" encoding="utf-8"?> +<sqlQueries> + <title>Scripts d'installation et de mises à jour de la base du VAS</title> + <queriesCollection> + <query> + <type>init</type> + <version>2016.01.00</version> + <code> + <![CDATA[ + CREATE SCHEMA s_vitis; + CREATE OR REPLACE FUNCTION s_vitis.create_role_if_not_exists(rolename NAME, rights text) RETURNS TEXT AS $$ BEGIN IF NOT EXISTS (SELECT * FROM pg_roles WHERE rolname = rolename) THEN EXECUTE 'CREATE ROLE ' || rolename|| ' ' || rights; RETURN 'CREATE ROLE'; ELSE RETURN format('ROLE ''%I'' ALREADY EXISTS', rolename); END IF; END; $$ LANGUAGE plpgsql; + select s_vitis.create_role_if_not_exists('vitis_user', 'NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION'); + GRANT vitis_user TO u_vitis; + select s_vitis.create_role_if_not_exists('vitis_admin', 'NOSUPERUSER INHERIT NOCREATEDB CREATEROLE NOREPLICATION'); + GRANT vitis_user TO vitis_admin; + ALTER SCHEMA s_vitis OWNER TO u_vitis; + SET search_path = s_vitis, pg_catalog; + CREATE FUNCTION f_add_col(_tbl regclass, _col text, _type regtype, OUT success boolean) RETURNS boolean LANGUAGE plpgsql AS $$ BEGIN IF EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = _tbl AND attname = _col AND NOT attisdropped) THEN success := FALSE; ELSE EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type; success := TRUE; END IF; END $$; + ALTER FUNCTION s_vitis.f_add_col(_tbl regclass, _col text, _type regtype, OUT success boolean) OWNER TO u_vitis; + CREATE FUNCTION f_add_unique_index(_schema text, _table text, _col text, _name text, OUT success boolean) RETURNS boolean LANGUAGE plpgsql AS $$ BEGIN IF EXISTS (SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = _name AND n.nspname = _schema ) THEN success := FALSE; ELSE EXECUTE ' CREATE UNIQUE INDEX ' || _name || ' ON ' || _schema || '.' || _table || ' (lower(' || _col || '));' ; success := TRUE; END IF; END $$; + ALTER FUNCTION s_vitis.f_add_unique_index(_schema text, _table text, _col text, _name text, OUT success boolean) OWNER TO u_vitis; + CREATE FUNCTION s2hms(integer) RETURNS character varying LANGUAGE plpgsql AS $_$ declare nDureeSeconde ALIAS for $1; sDureeChaine varchar(10) ; nHeures int ; nMinutes int ; nSecondes int ; nHeures2 varchar(2) ; nMinutes2 varchar(2) ; nSecondes2 varchar(2) ; BEGIN nHeures := nDureeSeconde / 3600 ; nMinutes := (nDureeSeconde %% 3600) / 60 ; nSecondes := nDureeSeconde %% 60 ; if nHeures < 10 then nHeures2:= 0 || cast(nHeures as text) ; else nHeures2:= cast(nHeures as text) ; end if; if nMinutes < 10 then nMinutes2:= 0 || cast(nMinutes as text) ; else nMinutes2:= cast(nMinutes as text) ; end if; if nSecondes < 10 then nSecondes2:= 0 || cast(nSecondes as text) ; else nSecondes2:= cast(nSecondes as text) ; end if; sDureeChaine := nHeures2 || ':' || nMinutes2 || ':' || nSecondes2; RETURN sDureeChaine; END; $_$; + ALTER FUNCTION s_vitis.s2hms(integer) OWNER TO u_vitis; + CREATE TABLE "user" (user_id integer NOT NULL,login character varying(50),name character varying(80),ip_constraint character varying(255), email character varying(100), company character varying(80),department character varying(80),last_connection timestamp without time zone, domain_id integer,restriction text); + ALTER TABLE "user" OWNER TO u_vitis; + CREATE TABLE vm_translation (translation_id character varying(60) NOT NULL, lang character varying(2) NOT NULL, translation text); + ALTER TABLE vm_translation OWNER TO u_vitis; + CREATE TABLE "group" (group_id integer NOT NULL, name character varying(50)); + ALTER TABLE "group" OWNER TO u_vitis; + COMMENT ON TABLE "group" IS 'User group having the same access rights to workspaces and inboxes'; + CREATE TABLE user_group (user_id integer, group_id integer); + ALTER TABLE user_group OWNER TO u_vitis; + CREATE SEQUENCE seq_common START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; + ALTER TABLE seq_common OWNER TO u_vitis; + CREATE TABLE domain (domain_id integer NOT NULL, domain character varying(50), alias character varying(50), server character varying(100), port integer, dn_search_user character varying(255), filter_user character varying(100), dn_search_group character varying(255), filter_group character varying(100), login character varying(50), password character varying(50), type character varying(10), verify_rights boolean DEFAULT true); + ALTER TABLE domain OWNER TO u_vitis; + COMMENT ON TABLE domain IS 'Ms Active Directory domain'; + COMMENT ON COLUMN domain.dn_search_user IS 'Distinguished Name for users root node '; + COMMENT ON COLUMN domain.dn_search_group IS 'Distinguished Name for groups root node '; + CREATE TABLE privileges ( rolname character varying(100) NOT NULL, description text); + ALTER TABLE privileges OWNER TO u_vitis; + CREATE SEQUENCE seq_translation START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; + ALTER TABLE seq_translation OWNER TO u_vitis; + CREATE SEQUENCE seq_vm START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; + ALTER TABLE seq_vm OWNER TO u_vitis; + CREATE VIEW v_group AS SELECT CASE WHEN (user_group.nb_members IS NULL) THEN (0)::bigint ELSE user_group.nb_members END AS nb_members, "group".group_id, "group".name FROM ("group" LEFT JOIN ( SELECT count(*) AS nb_members, user_group_1.group_id FROM user_group user_group_1 GROUP BY user_group_1.group_id) user_group ON (("group".group_id = user_group.group_id))); + ALTER TABLE v_group OWNER TO u_vitis; + CREATE TABLE vm_application_module ( application_name character varying(100) NOT NULL, module_name character varying(50) NOT NULL); + ALTER TABLE vm_application_module OWNER TO u_vitis; + CREATE TABLE vm_mode ( mode_id character varying(100) NOT NULL, module_id character varying(50)); + ALTER TABLE vm_mode OWNER TO u_vitis; + CREATE TABLE vm_mode_rolname ( index integer, mode_id character varying(100) NOT NULL, rolname character varying(100) NOT NULL); + ALTER TABLE vm_mode_rolname OWNER TO u_vitis; + CREATE VIEW v_mode AS SELECT DISTINCT vm_mode.mode_id, vm_application_module.application_name, vm_mode_rolname.index, vm_application_module.module_name FROM ((((vm_mode LEFT JOIN vm_application_module ON (((vm_mode.module_id)::text = (vm_application_module.module_name)::text))) LEFT JOIN vm_mode_rolname ON (((vm_mode.mode_id)::text = (vm_mode_rolname.mode_id)::text))) JOIN pg_group ON ((pg_group.groname = (vm_mode_rolname.rolname)::name))) JOIN pg_user ON (((pg_user.usesysid = ANY (pg_group.grolist)) AND ((pg_user.usename)::text = ("current_user"())::text)))); + ALTER TABLE v_mode OWNER TO u_vitis; + CREATE VIEW v_ra_members_group AS SELECT count(*) AS nb_members, user_group.group_id FROM user_group GROUP BY user_group.group_id; + ALTER TABLE v_ra_members_group OWNER TO u_vitis; + CREATE TABLE vm_section ( section_id integer DEFAULT nextval('seq_vm'::regclass) NOT NULL, label_id character varying(60), name character varying(50), index integer, event text, tab_id integer, template character varying(100), ressource_id character varying(100), module character varying(100)); + ALTER TABLE vm_section OWNER TO u_vitis; + CREATE TABLE vm_tab ( tab_id integer DEFAULT nextval('seq_vm'::regclass) NOT NULL, event character varying(255) NOT NULL, index integer DEFAULT 0 NOT NULL, mode_id character varying(100) NOT NULL, label_id character varying(60) NOT NULL, ressource_id character varying(100), edit_column character varying(255), show_column character varying(255), sorted_by character varying(100), sorted_dir character varying(4) DEFAULT 'ASC'::character varying, name character varying(100)); + ALTER TABLE vm_tab OWNER TO u_vitis; + CREATE VIEW v_section AS SELECT vm_section.tab_id, vm_section.section_id, vm_section.event, vm_section.index, vm_translation.translation AS label, vm_translation.lang, vm_section.name, vm_section.template, vm_section.ressource_id, vm_section.module AS module_name FROM s_vitis.vm_section LEFT JOIN s_vitis.vm_translation ON vm_section.label_id::text = vm_translation.translation_id::text LEFT JOIN s_vitis.vm_tab ON vm_section.tab_id::text = vm_tab.tab_id::text; + ALTER TABLE v_section OWNER TO u_vitis; + CREATE VIEW v_tab AS SELECT vm_tab.tab_id, vm_tab.event, vm_tab.index, vm_tab.mode_id, vm_translation.translation AS label, vm_translation.lang, vm_tab.ressource_id, vm_tab.edit_column, vm_tab.show_column, vm_tab.sorted_by, vm_tab.sorted_dir, vm_tab.name FROM (vm_tab LEFT JOIN vm_translation ON (((vm_tab.label_id)::text = (vm_translation.translation_id)::text))); + ALTER TABLE v_tab OWNER TO u_vitis; + CREATE VIEW v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN ((array_to_string(ARRAY( SELECT pg_group.groname FROM (pg_group JOIN pg_roles ON ((pg_roles.oid = ANY (pg_group.grolist)))) WHERE ((("user".login)::name = pg_roles.rolname) AND ((pg_group.groname = 'vitis_admin'::name) OR (pg_group.groname = 'vitis_user'::name)))), '|'::text) = 'vitis_user|vitis_admin'::text) OR (array_to_string(ARRAY( SELECT pg_group.groname FROM (pg_group JOIN pg_roles ON ((pg_roles.oid = ANY (pg_group.grolist)))) WHERE ((("user".login)::name = pg_roles.rolname) AND ((pg_group.groname = 'vitis_admin'::name) OR (pg_group.groname = 'vitis_user'::name)))), '|'::text) = 'vitis_admin|vitis_user'::text)) THEN 'admin'::text WHEN (array_to_string(ARRAY( SELECT pg_group.groname FROM (pg_group JOIN pg_roles ON ((pg_roles.oid = ANY (pg_group.grolist)))) WHERE ((("user".login)::name = pg_roles.rolname) AND ((pg_group.groname = 'vitis_admin'::name) OR (pg_group.groname = 'vitis_user'::name)))), '|'::text) = 'vitis_user'::text) THEN 'user'::text ELSE ''::text END AS role FROM ("user" LEFT JOIN domain ON (("user".domain_id = domain.domain_id))); + ALTER TABLE v_user OWNER TO u_vitis; + CREATE VIEW v_user_group AS SELECT user_group.group_id, user_group.user_id FROM ((user_group LEFT JOIN "user" ON ((user_group.user_id = "user".user_id))) LEFT JOIN "group" ON (("group".group_id = user_group.group_id))) WHERE ((("user".login)::name)::text = ("current_user"())::text); + ALTER TABLE v_user_group OWNER TO u_vitis; + CREATE TABLE version ( version character varying(10) NOT NULL, build integer NOT NULL, date timestamp with time zone NOT NULL, active boolean); + ALTER TABLE version OWNER TO u_vitis; + CREATE TABLE vm_application ( name character varying(100) NOT NULL); + ALTER TABLE vm_application OWNER TO u_vitis; + CREATE TABLE vm_module ( module_id character varying(50) NOT NULL, description text, version character varying(50) NOT NULL, label character varying(50), type character varying(3)); + ALTER TABLE vm_module OWNER TO u_vitis; + CREATE TABLE vm_string ( string text, string_id character varying(60) NOT NULL); + ALTER TABLE vm_string OWNER TO u_vitis; + CREATE TABLE vm_table_button ( button_class character varying(50), table_button_id integer DEFAULT nextval('seq_vm'::regclass) NOT NULL, event character varying(100) NOT NULL, label_id character varying(60), ressource_id character varying(100), tab_id integer); + ALTER TABLE vm_table_button OWNER TO u_vitis; + CREATE TABLE vm_table_field ( table_field_id integer DEFAULT nextval('seq_vm'::regclass) NOT NULL, name character varying(200) NOT NULL, sortable boolean DEFAULT true, resizeable boolean DEFAULT false, index integer, width integer, align character varying(6) DEFAULT 'left'::character varying NOT NULL, label_id character varying(60), module character varying(50), ressource_id character varying(100), template character varying(255), tab_id integer); + ALTER TABLE vm_table_field OWNER TO u_vitis; + INSERT INTO privileges (rolname, description) VALUES ('vitis_admin', E'rôle administrateur de vitis\nPermet d''accéder aux modes :\n - Utilisateur\n - Utilisateurs\n - Configuration\n - Logs'); + INSERT INTO privileges (rolname, description) VALUES ('vitis_user', E'rôle utilisateur de vitis\n\nPermet de se connecter à l''application'); + INSERT INTO vm_mode (mode_id, module_id) VALUES ('user', 'vitis'); + INSERT INTO vm_mode (mode_id, module_id) VALUES ('users', 'vitis'); + INSERT INTO vm_mode (mode_id, module_id) VALUES ('configuration', 'vitis'); + INSERT INTO vm_mode (mode_id, module_id) VALUES ('logs', 'vitis'); + INSERT INTO vm_mode (mode_id, module_id) VALUES ('help', 'vitis'); + INSERT INTO vm_mode_rolname (index, mode_id, rolname) VALUES (20, 'users', 'vitis_admin'); + INSERT INTO vm_mode_rolname (index, mode_id, rolname) VALUES (70, 'configuration', 'vitis_admin'); + INSERT INTO vm_mode_rolname (index, mode_id, rolname) VALUES (80, 'logs', 'vitis_admin'); + INSERT INTO vm_mode_rolname (index, mode_id, rolname) VALUES (10, 'user', 'vitis_user'); + INSERT INTO vm_mode_rolname (index, mode_id, rolname) VALUES (90, 'help', 'vitis_admin'); + INSERT INTO vm_module (module_id, description, version, label, type) VALUES ('vitis', 'module vitis veremes', '0.1', 'vitis', NULL); + INSERT INTO vm_string (string, string_id) VALUES ('Chaine de caractère nulle', 'vitis_1'); + INSERT INTO vm_string (string, string_id) VALUES ('onglet 2 du mode (Utilisateurs) utilisé dans la table vm_tab', 'vitis_2'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre de la list correspondant à le vm_table 3 (v_user)', 'vitis_3'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre Formulaire vm_table id 3 (v_user)', 'vitis_4'); + INSERT INTO vm_string (string, string_id) VALUES ('Button d''ajout de la table v_user table_button_id = 38', 'vitis_5'); + INSERT INTO vm_string (string, string_id) VALUES ('Button de suppression de la table v_user table_button_id =39', 'vitis_6'); + INSERT INTO vm_string (string, string_id) VALUES ('Button import AD de la table v_user table_button_id =40', 'vitis_7'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ user_id correspondant au table field_id 1', 'vitis_8'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ login correspondant au table field_id 11', 'vitis_9'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ name correspondant au table field_id 12', 'vitis_10'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ email correspondant au table field_id 13', 'vitis_11'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ ip correspondant au table field_id 14', 'vitis_12'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ company correspondant au table field_id 15', 'vitis_13'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ domain_id de la table domain correspondant au table field_id 146', 'vitis_14'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ Role de la table v_user pour connaitre si un utilisateur est administrateur ou pas', 'vitis_15'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ department correspondant au table field_id 18', 'vitis_16'); + INSERT INTO vm_string (string, string_id) VALUES ('onglet 1 du mode administration (Annuaires) utilisé dans la table vm_tab', 'vitis_17'); + INSERT INTO vm_string (string, string_id) VALUES ('onglet 3 du mode administration (Groupes) utilisé dans la table vm_tab', 'vitis_18'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre Formulaire vm_table id (group)', 'vitis_19'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre de la list correspondant à le vm_table 1 (group)', 'vitis_20'); + INSERT INTO vm_string (string, string_id) VALUES ('Button d''ajout de la table group table_button_id = 9', 'vitis_21'); + INSERT INTO vm_string (string, string_id) VALUES ('Button de suppression de la table group table_button_id =10', 'vitis_22'); + INSERT INTO vm_string (string, string_id) VALUES ('Button import AD de la table group table_button_id =50', 'vitis_23'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ id de la vue group correspondant au table field_id 154', 'vitis_24'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ nom de la vue group correspondant au table field_id 135', 'vitis_25'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ nb_members de la vue v_ra_members_group correspondant au champ Membres', 'vitis_26'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre de la list correspondant à le vm_table 19 (domain)', 'vitis_27'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre Formulaire vm_table domain', 'vitis_28'); + INSERT INTO vm_string (string, string_id) VALUES ('Button d''ajout de la table domain table_button_id = 7', 'vitis_29'); + INSERT INTO vm_string (string, string_id) VALUES ('Button de suppression de la table domain table_button_id =8', 'vitis_30'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ domain_id de la table domain correspondant au table field_id 145', 'vitis_31'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ domain de la table domain correspondant au table field_id 145', 'vitis_32'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ server de la table domain correspondant au table field_id 147', 'vitis_33'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ port de la table domain correspondant au table field_id 148', 'vitis_34'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ alias correspondant au table field_id 139', 'vitis_35'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ name de la vue update correspondant au table_field_id 41"', 'vitis_37'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ from de la vue update correspondant au table_field_id 42"', 'vitis_38'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ to de la vue update correspondant au table_field_id 43"', 'vitis_39'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ publishing_date de la vue update correspondant au table_field_id 44"', 'vitis_40'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ status de la vue update correspondant au table_field_id 45"', 'vitis_41'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ telechargement de la vue update correspondant au table_field_id 46"', 'vitis_42'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ installation de la vue update correspondant au table_field_id 47"', 'vitis_43'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ log de la vue update correspondant au table_field_id 48"', 'vitis_44'); + INSERT INTO vm_string (string, string_id) VALUES ('"Champ error_log de la vue update correspondant au table_field_id 49"', 'vitis_45'); + INSERT INTO vm_string (string, string_id) VALUES ('status disponible de la table rt_update_status', 'vitis_46'); + INSERT INTO vm_string (string, string_id) VALUES ('status téléchargé de la table rt_update_status', 'vitis_47'); + INSERT INTO vm_string (string, string_id) VALUES ('status installé de la table rt_update_status', 'vitis_48'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ update_id correspondant au table field_id 41', 'vitis_49'); + INSERT INTO vm_string (string, string_id) VALUES ('status erreur de la table rt_update_status', 'vitis_50'); + INSERT INTO vm_string (string, string_id) VALUES ('onglet 4 du mode administration (Privilèges) utilisé dans la table vm_tab', 'vitis_51'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre Formulaire vm_table id (privileges)', 'vitis_52'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre de la liste correspondant à le vm_table 1 (privileges)', 'vitis_53'); + INSERT INTO vm_string (string, string_id) VALUES ('Groupe d''utilisateurs', 'vitis_54'); + INSERT INTO vm_string (string, string_id) VALUES ('Description du groupe d''utilisateurs', 'vitis_55'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section general pour v_user', 'vitis_57'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section general pour group', 'vitis_58'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section general pour domain', 'vitis_59'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section general pour privileges', 'vitis_60'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ last_connection correspondant à la table v_user', 'vitis_61'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ alias correspondant à la table domain', 'vitis_62'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ type correspondant à la table domain', 'vitis_63'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ from de la vue update', 'vitis_64'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ to de la vue update', 'vitis_65'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ publishing_date de la vue update', 'vitis_66'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ status de la vue update', 'vitis_67'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ telechargement de la vue update', 'vitis_68'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ installation de la vue update', 'vitis_69'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ log de la vue update', 'vitis_70'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ error_log de la vue update', 'vitis_71'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ update_id de la vue update', 'vitis_72'); + INSERT INTO vm_string (string, string_id) VALUES ('Button de suppression de la table update', 'vitis_73'); + INSERT INTO vm_string (string, string_id) VALUES ('Champ name de la vue update', 'vitis_74'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section configuration pour configuration', 'vitis_75'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section version pour configuration', 'vitis_76'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section php info pour configuration', 'vitis_77'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section mises à jour pour configuration', 'vitis_78'); + INSERT INTO vm_string (string, string_id) VALUES ('Titre section installation pour configuration', 'vitis_79'); + INSERT INTO vm_string (string, string_id) VALUES ('Onglet Administration de l''objet vitis_help', 'vitis_291'); + INSERT INTO vm_string (string, string_id) VALUES ('Onglet Web service de l''objet vitis_help', 'vitis_80'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadConfiguration()', 0, 'configuration', 'vitis_1', NULL, NULL, NULL, NULL, 'ASC', 'vitis_configuration'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadHelp()', 0, 'help', 'vitis_1', NULL, NULL, NULL, NULL, 'ASC', 'vitis_help'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadLogsJob()', 0, 'logs', 'vitis_1', NULL, NULL, NULL, NULL, 'ASC', 'vitis_log'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadUser();', 0, 'user', 'vitis_1', 'vitis/users', NULL, NULL, NULL, 'ASC', 'vitis_user'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadList()', 1, 'users', 'vitis_17', 'vitis/domains', 'editSectionForm', 'showSectionForm', 'domain_id', 'DESC', 'vitis_domain'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadList()', 2, 'users', 'vitis_18', 'vitis/groups', 'editSectionForm', 'showSectionForm', 'group_id', 'DESC', 'vitis_group'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadList()', 3, 'users', 'vitis_51', 'vitis/privileges', 'editSectionForm', 'showSectionForm', 'rolname', 'ASC', 'vitis_privilege'); + INSERT INTO vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadList()', 0, 'users', 'vitis_2', 'vitis/users', 'editSectionForm', 'showSectionForm', 'user_id', 'DESC', 'vitis_users'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_57', 'general', 1, 'javascript:loadSection', (select tab_id from s_vitis.vm_tab where name = 'vitis_users'), 'workspaceListTpl.html', NULL, 'vitis'); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'nb_members', true, true, 3, 130, 'right', 'vitis_26', NULL, 'vitis/groups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'domain_id', true, true, 1, 30, 'right', 'vitis_31', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'type', true, true, 2, 100, 'left', 'vitis_63', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'alias', true, true, 3, 300, 'left', 'vitis_62', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'domain', true, true, 4, 300, 'left', 'vitis_32', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'server', true, true, 5, 150, 'left', 'vitis_33', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'port', true, true, 6, 50, 'right', 'vitis_34', NULL, 'vitis/domains', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'group_id', true, true, 1, 40, 'right', 'vitis_24', NULL, 'vitis/groups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'rolname', true, true, 1, 200, 'left', 'vitis_54', NULL, 'vitis/privileges', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_privilege')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'description', true, true, 2, 800, 'left', 'vitis_55', NULL, 'vitis/privileges', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_privilege')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'name', true, true, 2, 200, 'left', 'vitis_25', NULL, 'vitis/groups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'name', true, true, 3, 150, 'left', 'vitis_10', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'email', true, true, 6, 250, 'left', 'vitis_11', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'user_id', true, true, 1, 30, 'right', 'vitis_8', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'login', true, true, 2, 200, 'left', 'vitis_9', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'ip_constraint', true, true, 9, 150, 'left', 'vitis_12', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'company', true, true, 5, 130, 'left', 'vitis_13', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'domain', true, true, 8, 200, 'left', 'vitis_14', NULL, 'vitis/users', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'last_connection', true, true, 9, 170, 'left', 'vitis_61', NULL, 'vitis/users', '<div data-app-format-date-column="{{row.entity[col.field]}}"></div>', (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'role', true, true, 4, 40, 'center', 'vitis_15', NULL, 'vitis/users', '<div data-app-user-role-column="{{row.entity[col.field]}}"></div>', (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_59', 'general', 1, 'javascript:loadSection', (select tab_id from s_vitis.vm_tab where name = 'vitis_domain'), 'workspaceListTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_60', 'general', 1, 'javascript:loadSection', (select tab_id from s_vitis.vm_tab where name = 'vitis_privilege'), 'workspaceListTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_1', 'general', 1, 'Javascript:reloadSectionForm', (select tab_id from s_vitis.vm_tab where name = 'vitis_user'), 'simpleFormTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_58', 'general', 1, 'javascript:loadSection', (select tab_id from s_vitis.vm_tab where name = 'vitis_group'), 'workspaceListTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_1', 'general', 1, 'Javascript:reloadSectionForm', (select tab_id from s_vitis.vm_tab where name = 'vitis_log'), 'doubleFormTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_76', 'version', 2, 'Javascript:reloadSectionForm', (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'), 'modules/vitis/templates/versionConfigurationTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_77', 'phpinfo', 3, 'Javascript:reloadSectionForm', (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'), 'modules/vitis/templates/phpInfoConfigurationTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_75', 'general', 1, 'setPropertiesFormValues', (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'), 'simpleFormTpl.html', NULL, 'vitis'); + INSERT INTO vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_80', 'webService', 2, 'Javascript:reloadSectionForm', (select tab_id from s_vitis.vm_tab where name = 'vitis_help'), 'modules/vitis/templates/webServiceHelpTpl.html', NULL, 'vitis'); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('add_smallFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'AddSectionForm', 'vitis_5', 'vitis/users', (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('deleteFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'deleteUsers()', 'vitis_6', 'vitis/users', (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('add_smallFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'AddSectionForm', 'vitis_29', 'vitis/domains', (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('deleteFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'DeleteSelection', 'vitis_30', 'vitis/domains', (select tab_id from s_vitis.vm_tab where name = 'vitis_domain')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('add_smallFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'AddSectionForm', 'vitis_21', 'vitis/groups', (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('deleteFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'DeleteSelection', 'vitis_22', 'vitis/groups', (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('adImport', (select nextval('s_vitis.seq_vm'::regclass)), 'ImportFromAd("group")', 'vitis_23', 'vitis/groups', (select tab_id from s_vitis.vm_tab where name = 'vitis_group')); + INSERT INTO vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('adImport', (select nextval('s_vitis.seq_vm'::regclass)), 'ImportFromAd("person")', 'vitis_7', 'vitis/users', (select tab_id from s_vitis.vm_tab where name = 'vitis_users')); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_1', 'fr', NULL); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_1', 'en', NULL); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_2', 'fr', 'Utilisateurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_2', 'en', 'Users'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_3', 'fr', 'Utilisateurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_3', 'en', 'Users'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_4', 'fr', 'utilisateur'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_4', 'en', 'user'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_5', 'en', 'Add user'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_6', 'en', 'Delete users'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_6', 'fr', 'Supprimer les utilisateurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_7', 'fr', 'Importer de l''A.D.'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_7', 'en', 'Import from A.D.'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_8', 'fr', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_8', 'en', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_9', 'fr', 'Compte'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_9', 'en', 'Login'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_10', 'fr', 'Nom'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_10', 'en', 'Name'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_11', 'fr', 'Email'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_11', 'en', 'Email'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_12', 'en', 'Workstation IP'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_13', 'fr', 'Société'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_13', 'en', 'Company'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_14', 'fr', 'Domaine'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_14', 'en', 'Domain'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_15', 'fr', 'Rôle'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_15', 'en', 'Role'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_16', 'en', 'Department'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_16', 'fr', 'Service'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_17', 'fr', 'Domaines'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_17', 'en', 'Domains'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_18', 'fr', 'Groupes'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_18', 'en', 'Groups'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_19', 'fr', 'groupe'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_19', 'en', 'group'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_20', 'fr', 'Groupes'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_20', 'en', 'Groups'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_21', 'en', 'Add group'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_22', 'fr', 'Supprimer les groupes'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_22', 'en', 'Delete groups'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_23', 'fr', 'Importer de l''A.D.'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_23', 'en', 'Import from AD'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_24', 'fr', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_24', 'en', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_25', 'fr', 'Groupe'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_25', 'en', 'Group'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_28', 'en', 'domain'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_28', 'fr', 'domaine'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_27', 'en', 'Domains'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_27', 'fr', 'Domaines'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_29', 'en', 'Add domain'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_30', 'en', 'Delete domaines'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_30', 'fr', 'Supprimer les domaines'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_31', 'fr', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_31', 'en', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_32', 'fr', 'Domaine'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_32', 'en', 'Domain'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_33', 'fr', 'Serveur'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_33', 'en', 'Server'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_34', 'fr', 'Port'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_34', 'en', 'Port'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_35', 'fr', 'Supprimer mise à jour'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_35', 'en', 'Delete update'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_37', 'fr', 'Nom'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_37', 'en', 'Name'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_38', 'fr', 'De'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_38', 'en', 'From'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_39', 'fr', 'A'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_39', 'en', 'To'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_40', 'fr', 'Date de publication'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_40', 'en', 'Publishing date'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_41', 'fr', 'Statut'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_41', 'en', 'Status'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_42', 'fr', 'Téléchargement'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_42', 'en', 'Download'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_43', 'fr', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_43', 'en', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_44', 'fr', 'Log'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_44', 'en', 'Log'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_45', 'fr', 'Erreurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_45', 'en', 'Errors'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_46', 'fr', 'Disponible'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_46', 'en', 'Available'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_47', 'fr', 'Téléchargé'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_47', 'en', 'Downloaded'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_48', 'fr', 'Installé'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_48', 'en', 'Installed'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_49', 'fr', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_49', 'en', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_50', 'fr', 'Erreur'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_50', 'en', 'Error'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_51', 'fr', 'Privilèges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_51', 'en', 'Privileges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_52', 'fr', 'Privilèges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_52', 'en', 'Privileges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_53', 'fr', 'Privilèges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_53', 'en', 'Privileges'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_54', 'fr', 'Groupes d''utilisateurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_54', 'en', 'User groups'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_55', 'fr', 'Description'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_55', 'en', 'Description'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_57', 'fr', 'Général'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_57', 'en', 'General'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_58', 'fr', 'Général'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_58', 'en', 'General'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_59', 'fr', 'Général'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_59', 'en', 'General'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_60', 'fr', 'Général'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_60', 'en', 'General'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_61', 'fr', 'Dernière connexion'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_61', 'en', 'Last connection'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_62', 'fr', 'Alias'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_62', 'en', 'Alias'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_63', 'fr', 'Type'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_63', 'en', 'Type'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_64', 'fr', 'De'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_64', 'en', 'From'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_65', 'fr', 'A'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_65', 'en', 'To'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_66', 'fr', 'Date de publication'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_26', 'fr', 'Nombre de membres'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_26', 'en', 'Number of members'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_66', 'en', 'Publishing date'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_67', 'fr', 'Statut'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_67', 'en', 'Status'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_68', 'fr', 'Téléchargement'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_68', 'en', 'Download'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_69', 'fr', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_69', 'en', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_70', 'fr', 'Log'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_70', 'en', 'Log'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_71', 'fr', 'Erreurs'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_71', 'en', 'Errors'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_72', 'fr', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_72', 'en', 'ID'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_73', 'fr', 'Supprimer mise à jour'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_73', 'en', 'Delete update'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_74', 'fr', 'Nom'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_74', 'en', 'Name'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_75', 'fr', 'Configuration'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_75', 'en', 'Configuration'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_76', 'fr', 'Version'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_76', 'en', 'Version'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_77', 'fr', 'Php info'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_77', 'en', 'Php info'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_78', 'fr', 'Mises à jour'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_78', 'en', 'Mises à jour'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_79', 'fr', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_79', 'en', 'Installation'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_80', 'fr', 'Service Web'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_80', 'en', 'Web Service'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_21', 'fr', 'Ajouter un groupe'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_29', 'fr', 'Ajouter un domaine'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_5', 'fr', 'Ajouter un utilisateur'); + INSERT INTO vm_translation (translation_id, lang, translation) VALUES ('vitis_12', 'fr', 'IP du poste'); + ALTER TABLE ONLY vm_application_module ADD CONSTRAINT fk_application_module_name PRIMARY KEY (application_name, module_name); + ALTER TABLE ONLY domain ADD CONSTRAINT pk_domain_id PRIMARY KEY (domain_id); + ALTER TABLE ONLY "group" ADD CONSTRAINT pk_group_id PRIMARY KEY (group_id); + ALTER TABLE ONLY vm_application ADD CONSTRAINT pk_name PRIMARY KEY (name); + ALTER TABLE ONLY privileges ADD CONSTRAINT pk_privileges PRIMARY KEY (rolname); + ALTER TABLE ONLY vm_string ADD CONSTRAINT pk_string_id PRIMARY KEY (string_id); + ALTER TABLE ONLY vm_tab ADD CONSTRAINT pk_tab_id PRIMARY KEY (tab_id); + ALTER TABLE ONLY vm_table_button ADD CONSTRAINT pk_table_button_id PRIMARY KEY (table_button_id); + ALTER TABLE ONLY vm_table_field ADD CONSTRAINT pk_table_field_id PRIMARY KEY (table_field_id); + ALTER TABLE ONLY user_group ADD CONSTRAINT pk_user_group UNIQUE (group_id, user_id); + ALTER TABLE ONLY "user" ADD CONSTRAINT pk_user_id PRIMARY KEY (user_id); + ALTER TABLE ONLY vm_mode ADD CONSTRAINT pk_vm_mode PRIMARY KEY (mode_id); + ALTER TABLE ONLY vm_mode_rolname ADD CONSTRAINT pk_vm_mode_rolname PRIMARY KEY (rolname, mode_id); + ALTER TABLE ONLY vm_module ADD CONSTRAINT pk_vm_module PRIMARY KEY (module_id); + ALTER TABLE ONLY vm_section ADD CONSTRAINT pk_vm_section PRIMARY KEY (section_id); + ALTER TABLE ONLY vm_translation ADD CONSTRAINT pk_vm_translation PRIMARY KEY (translation_id, lang); + ALTER TABLE ONLY version ADD CONSTRAINT pk_version PRIMARY KEY (version); + ALTER TABLE ONLY vm_module ADD CONSTRAINT uk_label UNIQUE (label); + ALTER TABLE ONLY "user" ADD CONSTRAINT uk_user_login UNIQUE (login); + CREATE INDEX fki_login ON "user" USING btree (login); + CREATE INDEX fki_user_restriction ON "user" USING btree (restriction); + CREATE UNIQUE INDEX uk_domain ON domain USING btree (lower((domain)::text)); + CREATE UNIQUE INDEX uk_login ON "user" USING btree (lower((login)::text)); + CREATE UNIQUE INDEX uk_mode_id ON vm_mode_rolname USING btree (rolname, lower((mode_id)::text)); + CREATE UNIQUE INDEX uk_name_group ON "group" USING btree (lower((name)::text)); + ALTER TABLE s_vitis.vm_tab ADD CONSTRAINT uk_vm_tab_name UNIQUE (name); + CREATE RULE delete_v_group AS ON DELETE TO v_group DO INSTEAD DELETE FROM "group" WHERE ("group".group_id = old.group_id); + CREATE RULE delete_v_user AS ON DELETE TO v_user DO INSTEAD DELETE FROM "user" WHERE ("user".user_id = old.user_id); + CREATE RULE delete_v_user_group AS ON DELETE TO v_user_group DO INSTEAD DELETE FROM user_group WHERE (user_group.group_id = old.group_id); + CREATE RULE insert_v_group AS ON INSERT TO v_group DO INSTEAD INSERT INTO "group" (group_id, name) VALUES (new.group_id, new.name); + CREATE RULE insert_v_user AS ON INSERT TO v_user DO INSTEAD INSERT INTO "user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction); + CREATE RULE update_v_group AS ON UPDATE TO v_group DO INSTEAD UPDATE "group" SET name = new.name WHERE ("group".group_id = new.group_id); + CREATE RULE update_v_user AS ON UPDATE TO v_user DO INSTEAD UPDATE "user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, restriction = new.restriction WHERE ("user".user_id = new.user_id); + ALTER TABLE ONLY vm_application_module ADD CONSTRAINT fk_application_name FOREIGN KEY (application_name) REFERENCES vm_application(name) ON UPDATE CASCADE ON DELETE CASCADE; + ALTER TABLE ONLY "user" ADD CONSTRAINT fk_domain_id FOREIGN KEY (domain_id) REFERENCES domain(domain_id) ON UPDATE CASCADE ON DELETE CASCADE; + ALTER TABLE ONLY user_group ADD CONSTRAINT fk_group_id_user FOREIGN KEY (group_id) REFERENCES "group"(group_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_table_field ADD CONSTRAINT fk_label_id FOREIGN KEY (label_id) REFERENCES vm_string(string_id); + ALTER TABLE ONLY vm_table_button ADD CONSTRAINT fk_label_id_button FOREIGN KEY (label_id) REFERENCES vm_string(string_id); + ALTER TABLE ONLY vm_mode_rolname ADD CONSTRAINT fk_mode_id FOREIGN KEY (mode_id) REFERENCES vm_mode(mode_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_tab ADD CONSTRAINT fk_mode_id_tab FOREIGN KEY (mode_id) REFERENCES vm_mode(mode_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_mode ADD CONSTRAINT fk_module_id FOREIGN KEY (module_id) REFERENCES vm_module(module_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_application_module ADD CONSTRAINT fk_module_name FOREIGN KEY (module_name) REFERENCES vm_module(module_id) ON UPDATE CASCADE ON DELETE CASCADE; + ALTER TABLE ONLY vm_mode_rolname ADD CONSTRAINT fk_rolname FOREIGN KEY (rolname) REFERENCES privileges(rolname) ON DELETE CASCADE; + ALTER TABLE ONLY vm_tab ADD CONSTRAINT fk_string_id_tab FOREIGN KEY (label_id) REFERENCES vm_string(string_id); + ALTER TABLE ONLY vm_translation ADD CONSTRAINT fk_string_id_translation FOREIGN KEY (translation_id) REFERENCES vm_string(string_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_section ADD CONSTRAINT fk_string_section FOREIGN KEY (label_id) REFERENCES vm_string(string_id); + ALTER TABLE ONLY user_group ADD CONSTRAINT fk_user_id_group FOREIGN KEY (user_id) REFERENCES "user"(user_id) ON DELETE CASCADE; + ALTER TABLE ONLY vm_table_button ADD CONSTRAINT fk_vm_tab_button FOREIGN KEY (tab_id) REFERENCES vm_tab(tab_id); + ALTER TABLE ONLY vm_table_field ADD CONSTRAINT fk_vm_tab_button FOREIGN KEY (tab_id) REFERENCES vm_tab(tab_id); + ALTER TABLE ONLY vm_section ADD CONSTRAINT fk_vm_tab_section FOREIGN KEY (tab_id) REFERENCES vm_tab(tab_id); + ALTER TABLE ONLY vm_section ADD CONSTRAINT fk_module_vm_section FOREIGN KEY (module) REFERENCES vm_module (module_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION; + REVOKE ALL ON SCHEMA s_vitis FROM PUBLIC; + REVOKE ALL ON SCHEMA s_vitis FROM u_vitis; + GRANT ALL ON SCHEMA s_vitis TO u_vitis; + GRANT USAGE ON SCHEMA s_vitis TO vitis_admin; + GRANT USAGE ON SCHEMA s_vitis TO vitis_user; + REVOKE ALL ON TABLE "user" FROM PUBLIC; + REVOKE ALL ON TABLE "user" FROM u_vitis; + GRANT ALL ON TABLE "user" TO u_vitis; + GRANT ALL ON TABLE "user" TO vitis_admin; + GRANT SELECT,UPDATE ON TABLE "user" TO vitis_user; + REVOKE ALL ON TABLE vm_translation FROM PUBLIC; + REVOKE ALL ON TABLE vm_translation FROM u_vitis; + GRANT ALL ON TABLE vm_translation TO u_vitis; + GRANT SELECT ON TABLE vm_translation TO vitis_user; + GRANT ALL ON TABLE vm_translation TO vitis_admin; + REVOKE ALL ON TABLE "group" FROM PUBLIC; + REVOKE ALL ON TABLE "group" FROM u_vitis; + GRANT ALL ON TABLE "group" TO u_vitis; + GRANT ALL ON TABLE "group" TO vitis_admin; + GRANT SELECT ON TABLE "group" TO vitis_user; + REVOKE ALL ON TABLE user_group FROM PUBLIC; + REVOKE ALL ON TABLE user_group FROM u_vitis; + GRANT ALL ON TABLE user_group TO u_vitis; + GRANT ALL ON TABLE user_group TO vitis_admin; + GRANT SELECT ON TABLE user_group TO vitis_user; + REVOKE ALL ON SEQUENCE seq_common FROM PUBLIC; + REVOKE ALL ON SEQUENCE seq_common FROM u_vitis; + GRANT ALL ON SEQUENCE seq_common TO u_vitis; + GRANT ALL ON SEQUENCE seq_common TO vitis_admin; + GRANT SELECT,UPDATE ON SEQUENCE seq_common TO vitis_user; + REVOKE ALL ON TABLE domain FROM PUBLIC; + REVOKE ALL ON TABLE domain FROM u_vitis; + GRANT ALL ON TABLE domain TO u_vitis; + GRANT ALL ON TABLE domain TO vitis_admin; + GRANT SELECT ON TABLE domain TO vitis_user; + REVOKE ALL ON TABLE privileges FROM PUBLIC; + REVOKE ALL ON TABLE privileges FROM u_vitis; + GRANT ALL ON TABLE privileges TO u_vitis; + GRANT ALL ON TABLE privileges TO vitis_admin; + GRANT SELECT ON TABLE privileges TO vitis_user; + REVOKE ALL ON SEQUENCE seq_translation FROM PUBLIC; + REVOKE ALL ON SEQUENCE seq_translation FROM u_vitis; + GRANT ALL ON SEQUENCE seq_translation TO u_vitis; + GRANT ALL ON SEQUENCE seq_translation TO vitis_admin; + GRANT SELECT,UPDATE ON SEQUENCE seq_translation TO vitis_user; + REVOKE ALL ON SEQUENCE seq_vm FROM PUBLIC; + REVOKE ALL ON SEQUENCE seq_vm FROM u_vitis; + GRANT ALL ON SEQUENCE seq_vm TO u_vitis; + GRANT ALL ON SEQUENCE seq_vm TO vitis_admin; + GRANT SELECT,UPDATE ON SEQUENCE seq_vm TO vitis_user; + REVOKE ALL ON TABLE v_group FROM PUBLIC; + REVOKE ALL ON TABLE v_group FROM u_vitis; + GRANT ALL ON TABLE v_group TO u_vitis; + GRANT ALL ON TABLE v_group TO vitis_admin; + GRANT SELECT ON TABLE v_group TO vitis_user; + REVOKE ALL ON TABLE vm_application_module FROM PUBLIC; + REVOKE ALL ON TABLE vm_application_module FROM u_vitis; + GRANT ALL ON TABLE vm_application_module TO u_vitis; + GRANT ALL ON TABLE vm_application_module TO vitis_admin; + GRANT SELECT ON TABLE vm_application_module TO vitis_user; + REVOKE ALL ON TABLE vm_mode FROM PUBLIC; + REVOKE ALL ON TABLE vm_mode FROM u_vitis; + GRANT ALL ON TABLE vm_mode TO u_vitis; + GRANT ALL ON TABLE vm_mode TO vitis_admin; + GRANT SELECT ON TABLE vm_mode TO vitis_user; + REVOKE ALL ON TABLE vm_mode_rolname FROM PUBLIC; + REVOKE ALL ON TABLE vm_mode_rolname FROM u_vitis; + GRANT ALL ON TABLE vm_mode_rolname TO u_vitis; + GRANT SELECT ON TABLE vm_mode_rolname TO vitis_user; + GRANT ALL ON TABLE vm_mode_rolname TO vitis_admin; + REVOKE ALL ON TABLE v_mode FROM PUBLIC; + REVOKE ALL ON TABLE v_mode FROM u_vitis; + GRANT ALL ON TABLE v_mode TO u_vitis; + GRANT ALL ON TABLE v_mode TO vitis_admin; + GRANT SELECT ON TABLE v_mode TO vitis_user; + REVOKE ALL ON TABLE v_ra_members_group FROM PUBLIC; + REVOKE ALL ON TABLE v_ra_members_group FROM u_vitis; + GRANT ALL ON TABLE v_ra_members_group TO u_vitis; + GRANT ALL ON TABLE v_ra_members_group TO vitis_admin; + GRANT SELECT ON TABLE v_ra_members_group TO vitis_user; + REVOKE ALL ON TABLE vm_section FROM PUBLIC; + REVOKE ALL ON TABLE vm_section FROM u_vitis; + GRANT ALL ON TABLE vm_section TO u_vitis; + GRANT ALL ON TABLE vm_section TO vitis_admin; + GRANT SELECT ON TABLE vm_section TO vitis_user; + REVOKE ALL ON TABLE vm_tab FROM PUBLIC; + REVOKE ALL ON TABLE vm_tab FROM u_vitis; + GRANT ALL ON TABLE vm_tab TO u_vitis; + GRANT SELECT ON TABLE vm_tab TO vitis_user; + GRANT ALL ON TABLE vm_tab TO vitis_admin; + REVOKE ALL ON TABLE v_section FROM PUBLIC; + REVOKE ALL ON TABLE v_section FROM u_vitis; + GRANT ALL ON TABLE v_section TO u_vitis; + GRANT ALL ON TABLE v_section TO vitis_admin; + GRANT SELECT ON TABLE v_section TO vitis_user; + REVOKE ALL ON TABLE v_tab FROM PUBLIC; + REVOKE ALL ON TABLE v_tab FROM u_vitis; + GRANT ALL ON TABLE v_tab TO u_vitis; + GRANT ALL ON TABLE v_tab TO vitis_admin; + GRANT SELECT ON TABLE v_tab TO vitis_user; + REVOKE ALL ON TABLE v_user FROM PUBLIC; + REVOKE ALL ON TABLE v_user FROM u_vitis; + GRANT ALL ON TABLE v_user TO u_vitis; + GRANT ALL ON TABLE v_user TO vitis_admin; + GRANT SELECT,UPDATE ON TABLE v_user TO vitis_user; + REVOKE ALL ON TABLE v_user_group FROM PUBLIC; + REVOKE ALL ON TABLE v_user_group FROM u_vitis; + GRANT ALL ON TABLE v_user_group TO u_vitis; + GRANT ALL ON TABLE v_user_group TO vitis_admin; + GRANT SELECT ON TABLE v_user_group TO vitis_user; + REVOKE ALL ON TABLE vm_application FROM PUBLIC; + REVOKE ALL ON TABLE vm_application FROM u_vitis; + GRANT ALL ON TABLE vm_application TO u_vitis; + GRANT ALL ON TABLE vm_application TO vitis_admin; + GRANT SELECT ON TABLE vm_application TO vitis_user; + REVOKE ALL ON TABLE vm_module FROM PUBLIC; + REVOKE ALL ON TABLE vm_module FROM u_vitis; + GRANT ALL ON TABLE vm_module TO u_vitis; + GRANT ALL ON TABLE vm_module TO vitis_admin; + GRANT SELECT ON TABLE vm_module TO vitis_user; + REVOKE ALL ON TABLE vm_string FROM PUBLIC; + REVOKE ALL ON TABLE vm_string FROM u_vitis; + GRANT ALL ON TABLE vm_string TO u_vitis; + GRANT SELECT ON TABLE vm_string TO vitis_user; + GRANT ALL ON TABLE vm_string TO vitis_admin; + REVOKE ALL ON TABLE vm_table_button FROM PUBLIC; + REVOKE ALL ON TABLE vm_table_button FROM u_vitis; + GRANT ALL ON TABLE vm_table_button TO u_vitis; + GRANT SELECT ON TABLE vm_table_button TO vitis_user; + GRANT ALL ON TABLE vm_table_button TO vitis_admin; + REVOKE ALL ON TABLE vm_table_field FROM PUBLIC; + REVOKE ALL ON TABLE vm_table_field FROM u_vitis; + GRANT ALL ON TABLE vm_table_field TO u_vitis; + GRANT ALL ON TABLE vm_table_field TO vitis_user; + GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE vm_table_field TO vitis_admin; + ]]> + </code> + + </query> + <query> + <type>update</type> + <version>2016.02.00</version> + <code> + <![CDATA[ + -- Frédéric le 15/07/2016 15:21 + UPDATE s_vitis.vm_table_button SET event = 'deleteUsers()' WHERE tab_id = (select tab_id from s_vitis.vm_tab where name = 'vitis_users') AND label_id = 'vitis_6'; + ]]> + </code> + + </query> + <query> + <type>update</type> + <version>2016.03.00</version> + <code> + <![CDATA[ + ]]> + </code> + + </query> + <query> + <type>update</type> + <version>2016.04.00</version> + <code> + <![CDATA[ + ]]> + </code> + + </query> + <query> + <type>update</type> + <version>2016.05.00</version> + <code> + <![CDATA[ + ]]> + </code> + + </query> + <query> + <type>update</type> + <version>2017.01.00</version> + <code> + <![CDATA[ + -- Anthony le 24/01/2017 à 10:20 + CREATE OR REPLACE FUNCTION s_vitis.insertJointure(arrayJointure text, value1 varchar(100), tableSchema varchar(255),jointureTable varchar(255), key1 varchar(255), key2 varchar(255)) RETURNS VOID AS $BODY$ DECLARE item varchar(255); request text; BEGIN FOREACH item IN ARRAY string_to_array(arrayJointure, '|') LOOP request = 'INSERT INTO '|| tableSchema ||'.'|| jointureTable ||' ('|| key1 ||', '|| key2 ||')VALUES('; IF pg_typeof(value1)::text = 'integer' THEN request = request || value1 || ', '; ELSE request = request || '''' || value1 || ''', '; END IF; IF pg_typeof(item)::text = 'integer' THEN request = request || item || ');'; ELSE request = request || '''' || item || ''');'; END IF; EXECUTE request; END LOOP; RETURN; END $BODY$ LANGUAGE 'plpgsql'; + ALTER FUNCTION s_vitis.insertjointure(text, character varying, character varying, character varying, character varying, character varying) OWNER TO u_vitis; + CREATE OR REPLACE FUNCTION s_vitis.wabinsertstate( schemametier character varying, tablestatus character varying, statusname character varying, progress integer) RETURNS void AS $BODY$ DECLARE request text; rowData integer; Id integer; BEGIN EXECUTE 'SELECT status_id FROM ' || schemaMetier || '.' || tableStatus || ' WHERE name = '''||statusName||''';' INTO rowData; IF rowData IS NOT NULL THEN RAISE NOTICE '%', rowData;request = 'UPDATE ' || schemaMetier || '.' || tableStatus || ' SET progress = '|| progress ||' WHERE name = '''||statusName||''';'; ELSE EXECUTE 'SELECT MAX(status_id) FROM '||schemaMetier||'.'||tableStatus|| ';' INTO Id; IF Id IS NOT NULL THEN RAISE NOTICE '%', Id; Id:= Id + 1; else Id:=1; RAISE NOTICE '%', Id;end if;request = 'INSERT INTO ' || schemaMetier || '.' || tableStatus || ' (status_id, name, progress) VALUES (' || Id || ',''' || statusName|| ''', ' || progress || ');'; END IF; RAISE NOTICE '%', request;EXECUTE request; RETURN; END $BODY$ LANGUAGE plpgsql VOLATILE COST 100; + ALTER FUNCTION s_vitis.wabinsertstate(character varying, character varying, character varying, integer) OWNER TO u_vitis; + -- Armand le 30/01/2017 à 10:00 + CREATE OR REPLACE VIEW s_vitis.v_section AS SELECT vm_section.tab_id, vm_section.section_id, vm_section.event, vm_section.index, vm_translation.translation AS label, vm_translation.lang, vm_section.name, vm_section.template, vm_section.ressource_id, vm_section.module AS module_name, vm_tab.name AS tab_name, vm_tab.mode_id FROM s_vitis.vm_section LEFT JOIN s_vitis.vm_translation ON vm_section.label_id::text = vm_translation.translation_id::text LEFT JOIN s_vitis.vm_tab ON vm_section.tab_id::text = vm_tab.tab_id::text; + ALTER TABLE s_vitis.v_section OWNER TO u_vitis; + REVOKE ALL ON TABLE s_vitis.v_section FROM PUBLIC; + REVOKE ALL ON TABLE s_vitis.v_section FROM u_vitis; + GRANT ALL ON TABLE s_vitis.v_section TO u_vitis; + GRANT ALL ON TABLE s_vitis.v_section TO vitis_admin; + GRANT SELECT ON TABLE s_vitis.v_section TO vitis_user; + -- Sébastien le 01/02/2017 à 12:33 + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Section Mode du mode Configuration', 'vitis_81'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_81', 'fr', 'Modes'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_81', 'en', 'Modes'); + INSERT INTO s_vitis.vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_81', 'modes', 2, 'loadModes', (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'), 'workspaceListTpl.html', 'vitis/modes', 'vitis'); + UPDATE s_vitis.vm_section SET index = 3 WHERE name = 'version' and label_id = 'vitis_76' and tab_id = (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'); + UPDATE s_vitis.vm_section SET index = 4 WHERE name = 'phpinfo' and label_id = 'vitis_77' and tab_id = (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'); + -- Armand le 15/02/2017 à 11:40 + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Titre section websocket pour configuration', 'vitis_82'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_82', 'fr', 'Websocket'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_82', 'en', 'Websocket'); + INSERT INTO s_vitis.vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_82', 'websocket', 4, 'Javascript:reloadWebsocketStatus', (select tab_id from s_vitis.vm_tab where name = 'vitis_configuration'), 'modules/vitis/templates/websocketConfigurationTpl.html', NULL, 'vitis'); + -- Armand le 31/03/2017 à 11:40 + REVOKE ALL ON TABLE s_vitis.vm_table_field FROM vitis_user; + REVOKE ALL ON TABLE s_vitis.vm_table_field FROM vitis_admin; + GRANT SELECT ON TABLE s_vitis.vm_table_field TO vitis_user; + GRANT ALL ON TABLE s_vitis.vm_table_field TO vitis_admin; + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.01.01</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.01.02</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.01.03</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.01.04</version> + <code> + <![CDATA[ + -- Armand le 20/06/2017 à 18h ajout de la table feature_style + CREATE TABLE IF NOT EXISTS s_vitis.feature_style(feature_style_id SERIAL NOT NULL,draw_color VARCHAR(50),draw_outline_color VARCHAR(50),draw_size VARCHAR(50),draw_dash VARCHAR(50),draw_symbol VARCHAR(50),text_font VARCHAR(50),text_color VARCHAR(50),text_outline_color VARCHAR(50),text_size VARCHAR(50),text_outline_size VARCHAR(50),text_offset_x VARCHAR(50),text_offset_y VARCHAR(50),text_rotation VARCHAR(50),text_text VARCHAR(255),feature_type VARCHAR(255),PRIMARY KEY (feature_style_id)); + ALTER TABLE s_vitis.feature_style owner TO u_vitis; + GRANT ALL ON table s_vitis.feature_style TO u_vitis; + GRANT SELECT ON TABLE s_vitis.feature_style TO vitis_user; + GRANT ALL ON table s_vitis.feature_style TO vitis_admin; + -- Armand le 27/07/2017 à 18h restriction des droits de vitis_user pour des raisons de sécurité + REVOKE ALL ON TABLE s_vitis."user" FROM vitis_user; + REVOKE ALL ON TABLE s_vitis."user_group" FROM vitis_user; + CREATE OR REPLACE FUNCTION s_vitis.is_vitis_admin() RETURNS boolean AS $total$ declare total boolean; BEGIN SELECT(SELECT count(*) FROM information_schema.applicable_roles WHERE role_name='vitis_admin') > 0 INTO total; RETURN total; END; $total$ LANGUAGE plpgsql; + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id WHERE "user".login = "current_user"() OR s_vitis.is_vitis_admin(); + CREATE OR REPLACE RULE delete_v_user AS ON DELETE TO s_vitis.v_user DO INSTEAD DELETE FROM s_vitis."user" WHERE "user".user_id = old.user_id; + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction); + DROP RULE update_v_user ON s_vitis.v_user; + CREATE OR REPLACE RULE update_v_user_u AS ON UPDATE TO s_vitis.v_user DO INSTEAD UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department WHERE (new.name = "current_user"() or s_vitis.is_vitis_admin()) AND "user".user_id = new.user_id; + CREATE OR REPLACE RULE update_v_user_a AS ON UPDATE TO s_vitis.v_user WHERE s_vitis.is_vitis_admin() DO INSTEAD UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, restriction = new.restriction WHERE (new.name = "current_user"() or s_vitis.is_vitis_admin()) AND "user".user_id = new.user_id; + CREATE OR REPLACE VIEW s_vitis.v_user_group_by_rights AS SELECT user_group.user_id, user_group.group_id FROM s_vitis.user_group LEFT JOIN s_vitis."user" ON user_group.user_id = "user".user_id LEFT JOIN s_vitis."group" ON "group".group_id = user_group.group_id WHERE "user".login::name::text = "current_user"()::text OR s_vitis.is_vitis_admin(); + ALTER TABLE s_vitis.v_user_group_by_rights OWNER TO u_vitis; + GRANT ALL ON TABLE s_vitis.v_user_group_by_rights TO u_vitis; + GRANT ALL ON TABLE s_vitis.v_user_group_by_rights TO vitis_admin; + GRANT SELECT ON TABLE s_vitis.v_user_group_by_rights TO vitis_user; + CREATE OR REPLACE RULE update_v_user_group_by_rights AS ON DELETE TO s_vitis.v_user_group_by_rights DO INSTEAD DELETE FROM s_vitis.user_group WHERE user_group.group_id = old.group_id; + CREATE OR REPLACE RULE insert_v_user_group_by_rights AS ON INSERT TO s_vitis.v_user_group_by_rights DO INSTEAD INSERT INTO s_vitis.user_group (user_id, group_id) VALUES (new.user_id, new.group_id); + DROP RULE IF EXISTS update_v_user_a ON s_vitis.v_user; + DROP RULE IF EXISTS update_v_user_u ON s_vitis.v_user; + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD (UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = new.user_id; UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, restriction = new.restriction WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id); + -- Armand 02/08/2017: donne le droit d'édition sur last_connection + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD (UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = new.user_id; UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id); + -- Armand 02/08/2017: correction bug: un utilisateur simple peut changer le nom, l'email la company, le departement et le last_connection d'un autre utilisateur si il passe un user_id dans les paramètres à changer + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (SELECT user_id FROM s_vitis."user" WHERE login = "current_user"()); UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id;); + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.02.00</version> + <code> + <![CDATA[ + -- Laurent le 01/08/2017 à 12h Creation de fonction générique pour récupérer l'utilisateur qui créé ou met à jour un enregistrement + CREATE OR REPLACE FUNCTION s_vitis.insert_author_date() RETURNS trigger AS $BODY$ BEGIN NEW.author = current_user; NEW.create_date = now(); RETURN NEW; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; + ALTER FUNCTION s_vitis.insert_author_date() OWNER TO u_vitis; + CREATE OR REPLACE FUNCTION s_vitis.update_modifier_date() RETURNS trigger AS $BODY$ BEGIN NEW.modifier = current_user; NEW.update_date = now(); RETURN NEW; END;$BODY$ LANGUAGE plpgsql VOLATILE COST 100; + ALTER FUNCTION s_vitis.update_modifier_date() OWNER TO u_vitis; + -- Armand 31/08/2017: correction bug: quand un administrateur met à jour les groupes d'un utilisateur, il pert lui même les groupes qu'il a enlevé à l'utilisateur + CREATE OR REPLACE RULE update_v_user_group_by_rights AS ON DELETE TO s_vitis.v_user_group_by_rights DO INSTEAD DELETE FROM s_vitis.user_group WHERE user_group.group_id = old.group_id AND user_group.user_id = old.user_id; + --Yoann 12/09/2017: attribution de la séquence s_vitis.seq_common aux champs user_id(table user) et group_id (table group) + ALTER TABLE s_vitis."user" ALTER COLUMN user_id SET DEFAULT nextval('s_vitis.seq_common'::regclass); + ALTER TABLE s_vitis."group" ALTER COLUMN group_id SET DEFAULT nextval('s_vitis.seq_common'::regclass); + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.02.01</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.02.02</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.02.03</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.02.04</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.03.00</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2017.04.00</version> + <code> + <![CDATA[ + ALTER FUNCTION s_vitis.is_vitis_admin() OWNER TO u_vitis; + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.01.00</version> + <code> + <![CDATA[ + ALTER TABLE s_vitis."user" ADD CONSTRAINT check_u_vitis CHECK (name::text != 'u_vitis'::text) + ALTER TABLE s_vitis."user" ADD CONSTRAINT check_postgres CHECK (name::text != 'postgres'::text) + -- Armand 06/02/2018 15:31 + ALTER TABLE s_vitis.domain ALTER COLUMN password TYPE character varying(255); + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.02.00</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.02.01</version> + <code> + <![CDATA[ + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.03.00</version> + <code> + <![CDATA[ + --anthony 05/04/2018 10:36 + DROP INDEX IF EXISTS s_vitis.index_vm_translation_lang; + CREATE INDEX index_vm_translation_lang ON s_vitis.vm_translation (lang); + DROP INDEX IF EXISTS s_vitis.index_vm_translation; + CREATE INDEX index_vm_translation ON s_vitis.vm_translation (translation_id); + -- Armand 13/06/2018 17h59 ajout de CREATEROLE à u_vitis pour que l'on puisse modifier les privilèges + ALTER USER u_vitis WITH CREATEROLE + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.04.00</version> + <code> + <![CDATA[ + -- Frédéric 15/06/2018 09:15 + ALTER TABLE s_vitis.user ADD COLUMN dataencrypt boolean DEFAULT FALSE; + ALTER TABLE s_vitis.user ADD COLUMN secretkey character varying(100); + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, dataencrypt, secretkey FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction, dataencrypt, secretkey) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction, new.dataencrypt, new.secretkey); + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (( SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id;); + -- Frédéric 21/06/2018 15:47 + CREATE TABLE s_vitis.billinggroup (billinggroup_id SERIAL NOT NULL, billinggroup character varying(50) NOT NULL, description text); + ALTER TABLE ONLY s_vitis.billinggroup ADD CONSTRAINT pk_billinggroup_id PRIMARY KEY (billinggroup_id); + ALTER TABLE s_vitis.billinggroup OWNER TO u_vitis; + GRANT ALL ON TABLE s_vitis.billinggroup TO u_vitis; + GRANT ALL ON TABLE s_vitis.billinggroup TO vitis_admin; + ALTER TABLE s_vitis.user ADD COLUMN billinggroup_id integer; + ALTER TABLE s_vitis."user" ALTER COLUMN billinggroup_id SET DEFAULT -1; + ALTER TABLE s_vitis.user ADD CONSTRAINT fk_billinggroup_id FOREIGN KEY (billinggroup_id) REFERENCES s_vitis.billinggroup (billinggroup_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION; + -- Frédéric 21/06/2018 16:15 + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY (SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY (SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY (SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS ROLE, dataencrypt, secretkey, "user".billinggroup_id, billinggroup.billinggroup FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction, dataencrypt, secretkey, billinggroup_id) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction, new.dataencrypt, new.secretkey, new.billinggroup_id); + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (( SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey, billinggroup_id = new.billinggroup_id WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id;); + -- Frédéric 22/06/2018 11:32 + CREATE OR REPLACE VIEW s_vitis.v_billinggroup AS SELECT billinggroup.billinggroup_id, billinggroup.billinggroup, billinggroup.description FROM s_vitis."billinggroup"; + ALTER TABLE s_vitis.v_billinggroup OWNER TO u_vitis; + GRANT ALL ON TABLE s_vitis.v_billinggroup TO vitis_admin; + GRANT SELECT ON TABLE s_vitis.v_billinggroup TO vitis_user; + CREATE OR REPLACE RULE delete_v_billinggroup AS ON DELETE TO s_vitis.v_billinggroup DO INSTEAD DELETE FROM s_vitis."billinggroup" WHERE "billinggroup".billinggroup_id = old.billinggroup_id; + CREATE OR REPLACE RULE insert_v_billinggroup AS ON INSERT TO s_vitis.v_billinggroup DO INSTEAD INSERT INTO s_vitis."billinggroup" (billinggroup_id, billinggroup, description) VALUES (new.billinggroup_id, new.billinggroup, new.description); + CREATE OR REPLACE RULE update_v_billinggroup AS ON UPDATE TO s_vitis.v_billinggroup DO INSTEAD UPDATE s_vitis."billinggroup" SET billinggroup = new.billinggroup, description = new.description WHERE "billinggroup".billinggroup_id = new.billinggroup_id; + -- Frédéric 22/06/2018 14:20 + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('onglet 4 du mode utilisateurs (users) utilisé dans la table vm_tab', 'vitis_83'); + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Titre section general pour billinggroup', 'vitis_84'); + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Champ billinggroup_id de la table billinggroup', 'vitis_85'); + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Champ billinggroup de la table billinggroup', 'vitis_86'); + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Champ description de la table billinggroup', 'vitis_87'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_83', 'fr', 'Groupes de facturation'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_83', 'en', 'Billing Groups'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_84', 'fr', 'Général'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_84', 'en', 'General'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_85', 'fr', 'ID'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_85', 'en', 'ID'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_86', 'fr', 'Groupe'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_86', 'en', 'Group'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_87', 'fr', 'Description'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_87', 'en', 'Description'); + INSERT INTO s_vitis.vm_tab (tab_id, event, index, mode_id, label_id, ressource_id, edit_column, show_column, sorted_by, sorted_dir, name) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'loadList()', 4, 'users', 'vitis_83', 'vitis/billinggroups', 'editSectionForm', 'showSectionForm', 'billinggroup_id', 'DESC', 'vitis_billinggroup'); + INSERT INTO s_vitis.vm_section (section_id, label_id, name, index, event, tab_id, template, ressource_id, module) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'vitis_84', 'general', 1, 'javascript:loadSection', (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup'), 'workspaceListTpl.html', NULL, 'vitis'); + INSERT INTO s_vitis.vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'billinggroup_id', true, true, 1, 30, 'right', 'vitis_85', NULL, 'vitis/billinggroups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup')); + INSERT INTO s_vitis.vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'billinggroup', true, true, 2, 200, 'left', 'vitis_86', 'vitis', 'vitis/billinggroups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup')); + INSERT INTO s_vitis.vm_table_field (table_field_id, name, sortable, resizeable, index, width, align, label_id, module, ressource_id, template, tab_id) VALUES ((select nextval('s_vitis.seq_vm'::regclass)), 'description', true, true, 3, 800, 'left', 'vitis_87', 'vitis', 'vitis/billinggroups', NULL, (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup')); + -- Frédéric 22/06/2018 16:39 + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Button d''ajout de la table billing group', 'vitis_88'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_88', 'fr', 'Ajouter un groupe de facturation'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_88', 'en', 'Add a billing group'); + INSERT INTO s_vitis.vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('add_smallFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'AddSectionForm', 'vitis_88', 'vitis/billinggroups', (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup')); + INSERT INTO s_vitis.vm_string (string, string_id) VALUES ('Button de suppression de la table billing group', 'vitis_89'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_89', 'fr', 'Supprimer les groupes de facturation'); + INSERT INTO s_vitis.vm_translation (translation_id, lang, translation) VALUES ('vitis_89', 'en', 'Delete billing groups'); + INSERT INTO s_vitis.vm_table_button (button_class, table_button_id, event, label_id, ressource_id, tab_id) VALUES ('deleteFlexigrid', (select nextval('s_vitis.seq_vm'::regclass)), 'DeleteSelection', 'vitis_89', 'vitis/billinggroups', (select tab_id from s_vitis.vm_tab where name = 'vitis_billinggroup')); + -- Frédéric 25/06/2018 09:44 + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, dataencrypt, secretkey, "user".billinggroup_id,billinggroup.billinggroup FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + -- Frédéric 25/06/2018 11:05 + INSERT INTO s_vitis.billinggroup (billinggroup_id, billinggroup, description) VALUES (-1, 'default', ''); + + -- Frédéric le 20/07/2018 15:30 + ALTER TABLE s_vitis."user" ADD COLUMN timezone_id character varying(40) DEFAULT 'Europe/Paris' NOT NULL; + DROP VIEW s_vitis.v_user; + ALTER TABLE s_vitis.user ALTER COLUMN last_connection TYPE timestamp with time zone; + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, dataencrypt, secretkey, "user".billinggroup_id,billinggroup.billinggroup FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + ALTER TABLE s_vitis.v_user OWNER TO u_vitis; + GRANT ALL ON TABLE s_vitis.v_user TO vitis_admin; + GRANT SELECT, UPDATE ON TABLE s_vitis.v_user TO vitis_user; + CREATE OR REPLACE RULE delete_v_user AS ON DELETE TO s_vitis.v_user DO INSTEAD DELETE FROM s_vitis."user" WHERE "user".user_id = old.user_id; + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction, dataencrypt, secretkey, billinggroup_id) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction, new.dataencrypt, new.secretkey, new.billinggroup_id); + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (( SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey, billinggroup_id = new.billinggroup_id WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id;); + + -- Frédéric le 20/07/2018 16:40 + CREATE TABLE s_vitis.rt_formatdate (formatdate_id character varying(11) NOT NULL, formatdate character varying(100)); + ALTER TABLE s_vitis.rt_formatdate OWNER TO u_vitis; + GRANT ALL ON TABLE s_vitis.rt_formatdate TO vitis_admin; + GRANT SELECT ON TABLE s_vitis.rt_formatdate TO vitis_user; + ALTER TABLE ONLY s_vitis.rt_formatdate ADD CONSTRAINT pk_formatdate_id PRIMARY KEY (formatdate_id); + INSERT INTO s_vitis.rt_formatdate (formatdate_id, formatdate) VALUES ('MM-DD-YYYY','Américain'); + INSERT INTO s_vitis.rt_formatdate (formatdate_id, formatdate) VALUES ('YYYY-MM-DDT','ISO 8601'); + INSERT INTO s_vitis.rt_formatdate (formatdate_id, formatdate) VALUES ('DD-MM-YYYY','Européen'); + + ALTER TABLE s_vitis.user ADD COLUMN formatdate_id character varying(11) DEFAULT 'YYYY-MM-DDT'; + ALTER TABLE s_vitis.user ADD CONSTRAINT fk_formatdate_id FOREIGN KEY (formatdate_id) REFERENCES s_vitis.rt_formatdate (formatdate_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION; + + -- Anthony le 23/07/2018 09:20 + ALTER TABLE s_vitis.user ADD COLUMN phone varchar(50); + ALTER TABLE s_vitis.user ADD COLUMN acceptnotification boolean DEFAULT FALSE; + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, dataencrypt, secretkey, "user".billinggroup_id ,billinggroup.billinggroup, "user".phone, "user".acceptnotification FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction, dataencrypt, secretkey, billinggroup_id, phone, acceptnotification) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction, new.dataencrypt, new.secretkey, new.billinggroup_id, new.phone, new.acceptnotification); + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection, phone = new.phone, acceptnotification = new.acceptnotification WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (( SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, phone = new.phone, acceptnotification = new.acceptnotification, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey, billinggroup_id = new.billinggroup_id, phone = new.phone, acceptnotification = new.acceptnotification WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id; ); + + -- Frédéric le 23/07/2018 10:43 + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, dataencrypt, secretkey, "user".billinggroup_id ,billinggroup.billinggroup, "user".phone, "user".acceptnotification, "user".timezone_id, "user".formatdate_id FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + CREATE OR REPLACE RULE insert_v_user AS ON INSERT TO s_vitis.v_user DO INSTEAD INSERT INTO s_vitis."user" (user_id, login, domain_id, name, email, company, department, ip_constraint, restriction, dataencrypt, secretkey, billinggroup_id, phone, acceptnotification, timezone_id, formatdate_id) VALUES (new.user_id, new.login, new.domain_id, new.name, new.email, new.company, new.department, new.ip_constraint, new.restriction, new.dataencrypt, new.secretkey, new.billinggroup_id, new.phone, new.acceptnotification, new.timezone_id, new.formatdate_id); + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection, phone = new.phone, acceptnotification = new.acceptnotification WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = (( SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, phone = new.phone, acceptnotification = new.acceptnotification, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey, billinggroup_id = new.billinggroup_id, phone = new.phone, acceptnotification = new.acceptnotification, timezone_id = new.timezone_id, formatdate_id = new.formatdate_id WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id; ); + + -- Frédéric le 23/07/2018 16:44 + UPDATE s_vitis.vm_table_field SET template = NULL WHERE tab_id = (select tab_id from s_vitis.vm_tab where name = 'vitis_users') AND name = 'last_connection'; + + -- Frédéric le 26/07/2018 10:25 + CREATE OR REPLACE VIEW s_vitis.v_user AS SELECT "user".user_id, "user".login, "user".name, "user".email, "user".company, "user".department, "user".ip_constraint, domain.domain, "user".domain_id, "user".last_connection, "user".restriction, CASE WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user|vitis_admin'::text OR array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_admin|vitis_user'::text THEN 'admin'::text WHEN array_to_string(ARRAY( SELECT pg_group.groname FROM pg_group JOIN pg_roles ON pg_roles.oid = ANY (pg_group.grolist) WHERE "user".login::name = pg_roles.rolname AND (pg_group.groname = 'vitis_admin'::name OR pg_group.groname = 'vitis_user'::name)), '|'::text) = 'vitis_user'::text THEN 'user'::text ELSE ''::text END AS role, "user".dataencrypt, "user".secretkey, "user".billinggroup_id, billinggroup.billinggroup, "user".phone, "user".acceptnotification, "user".timezone_id, "user".formatdate_id, rt_formatdate.formatdate FROM s_vitis."user" LEFT JOIN s_vitis.domain ON "user".domain_id = domain.domain_id LEFT JOIN s_vitis.billinggroup ON "user".billinggroup_id = billinggroup.billinggroup_id LEFT JOIN s_vitis.rt_formatdate ON "user".formatdate_id = rt_formatdate.formatdate_id WHERE "user".login::name = "current_user"() OR s_vitis.is_vitis_admin(); + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.04.01</version> + <code> + <![CDATA[ + -- Sofian le 30/08/2018 à 09:32 + CREATE OR REPLACE RULE update_v_user AS ON UPDATE TO s_vitis.v_user DO INSTEAD ( UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, last_connection = new.last_connection, phone = new.phone, acceptnotification = new.acceptnotification WHERE NOT s_vitis.is_vitis_admin() AND new.login::name = "current_user"() AND "user".user_id = ( (SELECT user_1.user_id FROM s_vitis."user" user_1 WHERE user_1.login::name = "current_user"())); UPDATE s_vitis."user" SET name = new.name, email = new.email, company = new.company, department = new.department, ip_constraint = new.ip_constraint, domain_id = new.domain_id, last_connection = new.last_connection, restriction = new.restriction, dataencrypt = new.dataencrypt, secretkey = new.secretkey, billinggroup_id = new.billinggroup_id, phone = new.phone, acceptnotification = new.acceptnotification, timezone_id = new.timezone_id, formatdate_id = new.formatdate_id WHERE s_vitis.is_vitis_admin() AND "user".user_id = new.user_id; ); + ]]> + </code> + </query> + <query> + <type>update</type> + <version>2018.05.00</version> + <code> + <![CDATA[ + -- Armand le 11/09/2018 à 11:35 création de la fonction s_vitis.format_date pour transformer un timestamp en fonction du format d'affichage des dates lié à l'utilisateur + CREATE OR REPLACE FUNCTION s_vitis.format_date(input_date TIMESTAMP) RETURNS TEXT AS $$ BEGIN RETURN to_char(input_date, (SELECT formatdate_id || ' HH24:MI:SS' as "formatdate" from s_vitis.user WHERE login = "current_user"())); END; $$ LANGUAGE PLPGSQL; + ALTER FUNCTION s_vitis.format_date(TIMESTAMP) OWNER TO u_vitis; + ]]> + </code> + </query> + </queriesCollection> +</sqlQueries>