Forking from Mailzu 0.8RC3

This commit is contained in:
Mikko Husari
2008-12-10 15:33:43 +02:00
commit 2572b1814b
184 changed files with 79039 additions and 0 deletions

127
lib/AmavisdEngine.class.php Normal file
View File

@@ -0,0 +1,127 @@
<?php
/**
* AmavisdEngine class
* @author Samuel Tran
* @author Jeremy Fowler
* @version 03-22-07
* @package AmavisdEngine
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* PEAR::Net_Socket Library
*/
if ($GLOBALS['conf']['app']['safeMode']) {
ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
include_once('pear/PEAR.php');
include_once('pear/Net/Socket.php');
}
else {
include_once 'PEAR.php';
include_once 'Net/Socket.php';
}
/**
* Provide all access/communication to Amavisd AM.PDP
*/
class AmavisdEngine {
var $socket; // Reference to socket
var $port; // Amavisd spam release port
var $connected; // Connection status
var $last_error; // Last error message
/**
* AmavisdEngine object constructor
* $param none
* $return object Amavisd object
*/
function AmavisdEngine($host) {
$this->socket = new Net_Socket();
$this->port = $GLOBALS['conf']['amavisd']['spam_release_port'];
$this->connected = false;
$this->last_error = '';
// Connect to the Amavisd Port or wait 5 seconds and timeout
$result = $this->socket->connect($host, $this->port, true, 5);
if (PEAR::isError($result)) {
$this->last_error = "Error connecting to $host:$this->port, " . $result->getMessage();
} else {
$this->connected = true;
}
}
/**
* Shutdown and close socket
* @param none
*/
function disconnect() {
$this->socket->disconnect();
}
/**
* Release message from quarantine
* @param $mail_id
* @param $secret_id
* @param $recipient
* @result response
*/
function release_message($mail_id, $secret_id, $recipient, $quar_type, $quar_loc) {
if (! $this->connected) {
return $this->last_error;
}
$in = "request=release\r\n";
$in .= "mail_id=$mail_id\r\n";
$in .= "secret_id=$secret_id\r\n";
$in .= "quar_type=$quar_type\r\n";
# If it is file-based quarantine, lets provide the filename on the host
if ( $quar_type == 'F' ) {
$in .= "mail_file=$quar_loc\r\n";
}
$in .= "recipient=<$recipient>\r\n";
$in .= "\r\n";
// Sending request ...
$out = $this->socket->write($in);
if (PEAR::isError($out)) {
$this->last_error = 'Error writing to socket: ' . $out->getMessage();
return $this->last_error;
}
// Set timeout of 5 seconds
$this->socket->setTimeout(5);
// Reading response
$out = $this->socket->read(512);
if (PEAR::isError($out)) {
$this->last_error = 'Error reading from socket: ' . $out->getMessage();
return $this->last_error;
}
return $out;
}
}
?>

386
lib/Auth.class.php Normal file
View File

@@ -0,0 +1,386 @@
<?php
/**
* Authorization and login functionality
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @author David Poole <David.Poole@fccc.edu>
* @version 02-19-05
* @package phpScheduleIt
*
* Copyright (C) 2003 - 2005 phpScheduleIt
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* DBEngine class
*/
include_once(BASE_DIR . '/lib/DBEngine.class.php');
/**
* PHPMailer
*/
include_once('PHPMailer.class.php');
/**
* Include Auth template functions
*/
include_once(BASE_DIR . '/templates/auth.template.php');
/**
* This class provides all authoritiative and verification
* functionality, including login/logout, registration,
* and user verification
*/
class Auth {
var $is_loggedin = false;
var $login_msg = '';
var $is_attempt = false;
//var $db;
var $success;
/**
* Create a reference to the database class
* and start the session
* @param none
*/
//function Auth() {
// $this->db = new AuthDB();
//}
/**
* Check if user is a super administrator
* This function checks to see if the currently
* logged in user is the administrator, granting
* them special permissions
* @param none
* @return boolean whether the user is a s_admin
*/
function isAdmin() {
return isset($_SESSION['sessionAdmin']);
}
/**
* Check if user is a mail administrator
* This function checks to see if the currently
* logged in user is the administrator, granting
* them special permissions
* @param none
* @return boolean whether the user is a m_admin
*/
function isMailAdmin() {
return (isset($_SESSION['sessionMailAdmin']) || isset($_SESSION['sessionAdmin']));
}
/**
* Check user login
* This function checks to see if the user has
* a valid session set (if they are logged in)
* @param none
* @return boolean whether the user is logged in
*/
function is_logged_in() {
return isset($_SESSION['sessionID']);
}
/**
* Returns the currently logged in user's userid
* @param none
* @return the userid, or null if the user is not logged in
*/
function getCurrentID() {
return $_SESSION['sessionID'];//isset($_SESSION['sessionID']) ? $_SESSION['sessionID'] : null;
}
/**
* Logs the user in
* @param string $login login
* @param string $pass password
* @param string $cookieVal y or n if we are using cookie
* @param string $isCookie id value of user stored in the cookie
* @param string $resume page to forward the user to after a login
* @param string $lang language code to set
* @return any error message that occured during login
*/
function doLogin($login, $pass, $cookieVal = null, $isCookie = false, $resume = '', $lang = '', $domain = '') {
global $conf;
$msg = '';
$allowedToLogin = true;
if (empty($resume)) $resume = 'summary.php'; // Go to control panel by default
$_SESSION['sessionID'] = null;
$_SESSION['sessionName'] = null;
$_SESSION['sessionMail'] = null;
$_SESSION['sessionAdmin'] = null;
$_SESSION['sessionMailAdmin'] = null;
$_SESSION['sessionNav'] = null;
$login = stripslashes($login);
$pass = stripslashes($pass);
$ok_user = $ok_pass = false;
$authMethod = $conf['auth']['serverType'];
if ($isCookie != false) { // Cookie is set
$id = $isCookie;
if ($this->db->verifyID($id))
$ok_user = $ok_pass = true;
else {
$ok_user = $ok_pass = false;
setcookie('ID', '', time()-3600, '/'); // Clear out all cookies
$msg .= translate('That cookie seems to be invalid') . '<br/>';
}
} else {
switch ( strtolower($authMethod) ) {
case "ad":
case "ldap":
// Added this check for LDAP servers that switch to anonymous bind whenever
// provided password is left blank
if ($pass == '') return (translate ('Invalid User Name/Password.'));
// Include LDAPEngine class
include_once('LDAPEngine.class.php');
$ldap = new LDAPEngine();
if( $ldap->connect() ) {
// Get user DN
// For AD it could be of the form of 'user@domain' or standard LDAP dn
$dn = $ldap->getUserDN($login);
// Check if user is allowed to log in
if ( ! $this->isAllowedToLogin($login) ) {
$allowedToLogin = false;
$msg .= 'User is not allowed to login';
// If user is allowed to log in try a bind
} elseif ( ($dn != '') && $ldap->authBind($dn, $pass) ) {
$ldap->logonName = $login;
$ldap->loadUserData($dn);
$data = $ldap->getUserData();
$ok_user = true; $ok_pass = true;
} else {
$msg .= 'Invalid User Name/Password.';
}
$ldap->disconnect();
}
break;
case "sql":
// Include DBAuth class
include_once('DBAuth.class.php');
$db = new DBAuth();
// Check if user is allowed to log in
if ( ! $this->isAllowedToLogin($login) ) {
$allowedToLogin = false;
$msg .= 'User is not allowed to login';
// If user is allowed to log in try to authenticate
} elseif ( $db->authUser($login, $pass) ) {
$data = $db->getUserData();
$ok_user = true; $ok_pass = true;
} else {
$msg .= 'Invalid User Name/Password.';
}
break;
case "exchange":
// Include ExchAuth class
include_once('ExchAuth.class.php');
$exch = new ExchAuth();
// Check if user is allowed to log in
if ( ! $this->isAllowedToLogin($login) ) {
$allowedToLogin = false;
$msg .= 'User is not allowed to login';
// If user is allowed to log in try to authenticate
} elseif ( $exch->authUser($login, $pass, $domain) ) {
$data = $exch->getUserData();
$ok_user = true; $ok_pass = true;
} else {
$msg .= 'Invalid User Name/Password.';
}
break;
case "imap":
// Include IMAPAuth class
include_once('IMAPAuth.class.php');
$imap = new IMAPAuth();
// Check if user is allowed to log in
if ( ! $this->isAllowedToLogin($login) ) {
$allowedToLogin = false;
$msg .= 'User is not allowed to login';
// If user is allowed to log in try to authenticate
} elseif ( $imap->authUser($login, $pass) ) {
$data = $imap->getUserData();
$ok_user = true; $ok_pass = true;
} else {
$msg .= 'Invalid User Name/Password.';
}
break;
default:
CmnFns::do_error_box(translate('Unknown server type'), '', false);
}
}
// If the login failed, notify the user and quit the app
if (!$ok_user || !$ok_pass || !$allowedToLogin) {
CmnFns::write_log('Authentication failed' . ', ' . $msg, $login);
return translate($msg);
} else {
$this->is_loggedin = true;
CmnFns::write_log('Authentication successful', $login);
/*
$user = new User($id); // Get user info
// If the user wants to set a cookie, set it
// for their ID and fname. Expires in 30 days (2592000 seconds)
if (!empty($cookieVal)) {
//die ('Setting cookie');
setcookie('ID', $user->get_id(), time() + 2592000, '/');
}
*/
// Set other session variables
$_SESSION['sessionID'] = $data['logonName'];
$_SESSION['sessionName'] = $data['firstName'];
$_SESSION['sessionMail'] = $data['emailAddress'];
// If it is the super admin, set session variable
foreach ($conf['auth']['s_admins'] as $s_admin) {
if (strtolower($s_admin) == strtolower($_SESSION['sessionID'])) {
$_SESSION['sessionAdmin'] = true;
}
}
// If it is the mail admin, set session variable
foreach ($conf['auth']['m_admins'] as $m_admin) {
if (strtolower($m_admin) == strtolower($_SESSION['sessionID'])) {
$_SESSION['sessionMailAdmin'] = true;
}
}
if ($lang != '') {
set_language($lang);
}
// Send them to the control panel
CmnFns::redirect(urldecode($resume));
}
}
function isAllowedToLogin( $username ) {
global $conf;
// If not defined or set to false, $username is allowed to log in
if ( ! isset($conf['auth']['login_restriction']) || ! $conf['auth']['login_restriction'] ) return true;
// merge the allowed users together and match case-insensitive
$allowed = array_merge($conf['auth']['s_admins'], $conf['auth']['m_admins'], $conf['auth']['restricted_users']);
foreach ($allowed as $allow) {
if ( strtolower($username) == strtolower($allow) ) {
return(true);
}
}
}
/**
* Log the user out of the system
* @param none
*/
function doLogout() {
// Check for valid session
if (!$this->is_logged_in()) {
$this->print_login_msg();
die;
}
else {
$login = $_SESSION['sessionID'];
// Destroy all session variables
unset($_SESSION['sessionID']);
unset($_SESSION['sessionName']);
unset($_SESSION['sessionMail']);
unset($_SESSION['sessionNav']);
if (isset($_SESSION['sessionAdmin'])) unset($_SESSION['sessionAdmin']);
session_destroy();
// Clear out all cookies
setcookie('ID', '', time()-3600, '/');
// Log in logfile
CmnFns::write_log('Logout successful', $login);
// Refresh page
CmnFns::redirect($_SERVER['PHP_SELF']);
}
}
/**
* Returns whether the user is attempting to log in
* @param none
* @return whether the user is attempting to log in
*/
function isAttempting() {
return $this->is_attempt;
}
/**
* Kills app
* @param none
*/
function kill() {
die;
}
/**
* Destroy any lingering sessions
* @param none
*/
function clean() {
// Destroy all session variables
unset($_SESSION['sessionID']);
unset($_SESSION['sessionName']);
unset($_SESSION['sessionMail']);
if (isset($_SESSION['sessionAdmin'])) unset($_SESSION['sessionAdmin']);
session_destroy();
}
/**
* Wrapper function to call template 'printLoginForm' function
* @param string $msg error messages to display for user
* @param string $resume page to resume after a login
*/
function printLoginForm($msg = '', $resume = '') {
printLoginForm($msg, $resume);
}
/**
* Prints a message telling the user to log in
* @param boolean $kill whether to end the program or not
*/
function print_login_msg($kill = true) {
CmnFns::redirect(CmnFns::getScriptURL() . '/index.php?auth=no&resume=' . urlencode($_SERVER['PHP_SELF']) . '?' . urlencode($_SERVER['QUERY_STRING']));
}
/**
* Prints out the latest success box
* @param none
*/
function print_success_box() {
CmnFns::do_message_box($this->success);
}
}
?>

708
lib/CmnFns.class.php Normal file
View File

@@ -0,0 +1,708 @@
<?php
/**
* These functions common to most pages
*
* @author Samuel Tran <stran2005@users.sourceforge.net>
* @author Brian Wong <bwsource@users.sourceforge.net>
* @author Jeremy Fowler <jfowler06@users.sourceforge.net>
* @package MailZu
*
* Following functions taken from PhpScheduleIt,
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @version 04-03-07:
* formatTime(), formatDate(), formatDateTime(), minutes_to_hours(), getScriptURL(),
* do_error_box(), do_message_box(), getNewLink(), getNewPager(), cleanPostVals(),
* get_vert_order(), get_value_order(), write_log(), get_day_name(), redirect(),
* print_language_pulldown(), html_activate_links()
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* Include configuration file
**/
include_once(BASE_DIR . '/config/config.php');
/**
* Include Link class
*/
include_once('Link.class.php');
/**
* Include Pager class
*/
include_once('Pager.class.php');
// Define constants for method getGlobalVar()
@define('INORDER',0);
@define('GET',1);
@define('POST',2);
@define('SESSION',3);
@define('SERVER',4);
@define('FORM',5);
/**
* Provides functions common to most pages
*/
class CmnFns {
/**
* Convert minutes to hours
* @param double $time time to convert in minutes
* @return string time in 12 hour time
*/
function formatTime($time) {
global $conf;
// Set up time array with $timeArray[0]=hour, $timeArray[1]=minute
// If time does not contain decimal point
// then set time array manually
// else explode on the decimal point
$hour = intval($time / 60);
$min = $time % 60;
if ($conf['app']['timeFormat'] == 24) {
$a = ''; // AM/PM does not exist
if ($hour < 10) $hour = '0' . $hour;
}
else {
$a = ($hour < 12 || $hour == 24) ? translate('am') : translate('pm'); // Set am/pm
if ($hour > 12) $hour = $hour - 12; // Take out of 24hr clock
if ($hour == 0) $hour = 12; // Don't show 0hr, show 12 am
}
// Set proper minutes (the same for 12/24 format)
if ($min < 10) $min = 0 . $min;
// Put into a string and return
return $hour . ':' . $min . $a;
}
/**
* Convert ISO8601 date to date format
* @param string $date string (yyyy-mm-dd)
* @return int timestamp
*/
function formatDateISO($date) {
$time = strtotime($date);
return $time;
}
/**
* Convert timestamp to date format
* @param string $date timestamp
* @param string $format format to put datestamp into
* @return string date as $format or as default format
*/
function formatDate($date, $format = '') {
global $dates;
if (empty($format)) $format = $dates['general_date'];
return strftime($format, $date);
}
/**
* Convert UNIX timestamp to datetime format
* @param string $ts MySQL timestamp
* @param string $format format to put datestamp into
* @return string date/time as $format or as default format
*/
function formatDateTime($ts, $format = '') {
global $conf;
global $dates;
if (empty($format))
$format = $dates['general_datetime'] . ' ' . (($conf['app']['timeFormat'] ==24) ? '%H' : '%I') . ':%M:%S' . (($conf['app']['timeFormat'] == 24) ? '' : ' %p');
return strftime($format, $ts);
}
/**
* Convert minutes to hours/minutes
* @param int $minutes minutes to convert
* @return string version of hours and minutes
*/
function minutes_to_hours($minutes) {
if ($minutes == 0)
return '0 ' . translate('hours');
$hours = (intval($minutes / 60) != 0) ? intval($minutes / 60) . ' ' . translate('hours') : '';
$min = (intval($minutes % 60) != 0) ? intval($minutes % 60) . ' ' . translate('minutes') : '';
return ($hours . ' ' . $min);
}
/**
* Return the current script URL directory
* @param none
* @return url url of curent script directory
*/
function getScriptURL() {
global $conf;
$uri = $conf['app']['weburi'];
return (strrpos($uri, '/') === false) ? $uri : substr($uri, 0, strlen($uri));
}
/**
* Prints an error message box and kills the app
* @param string $msg error message to print
* @param string $style inline CSS style definition to apply to box
* @param boolean $die whether to kill the app or not
*/
function do_error_box($msg, $style='', $die = true) {
global $conf;
echo '<table border="0" cellspacing="0" cellpadding="0" align="center" class="alert" style="' . $style . '"><tr><td>' . $msg . '</td></tr></table>';
if ($die) {
echo '</td></tr></table>'; // endMain() in Template
echo '<p align="center"><a href="http://www.mailzu.net">' . $conf['app']['title'] .' v' . $conf['app']['version'] . '</a></p></body></html>'; // printHTMLFooter() in Template
//$t = new Template();
//$t->endMain();
//$t->printHTMLFooter();
die();
}
}
/**
* Prints out a box with notification message
* @param string $msg message to print out
* @param string $style inline CSS style definition to apply to box
*/
function do_message_box($msg, $style='') {
echo '<table border="0" cellspacing="0" cellpadding="0" align="center" class="message" style="' . $style . '"><tr><td>' . $msg . '</td></tr></table>';
}
/**
* Returns a reference to a new Link object
* Used to make HTML links
* @param none
* @return Link object
*/
function getNewLink() {
return new Link();
}
/**
* Returns a reference to a new Pager object
* Used to iterate over limited recordesets
* @param none
* @return Pager object
*/
function getNewPager() {
return new Pager();
}
/**
* Strip out slahses from POST values
* @param none
* @return array of cleaned up POST values
*/
function cleanPostVals() {
$return = array();
foreach ($_POST as $key => $val)
$return[$key] = stripslashes(trim($val));
return $return;
}
/**
* Strip out slahses from an array of data
* @param none
* @return array of cleaned up data
*/
function cleanVals($data) {
$return = array();
foreach ($data as $key => $val)
$return[$key] = stripslashes($val);
return $return;
}
/**
* Verifies vertical order and returns value
* @param string $vert value of vertical order
* @return string vertical order
*/
function get_vert_order($get_name = 'vert') {
// If no vertical value is specified, use DESC
$vert = isset($_GET[$get_name]) ? $_GET[$get_name] : 'DESC';
// Validate vert value, default to DESC if invalid
switch($vert) {
case 'DESC';
case 'ASC';
break;
default :
$vert = 'DESC';
break;
}
return $vert;
}
/**
* Verifies and returns the order to list recordset results by
* If none of the values are valid, it will return the 1st element in the array
* @param array $orders all valid order names
* @return string order of recorset
*/
function get_value_order($orders = array(), $get_name = 'order') {
if (empty($orders)) // Return null if the order array is empty
return NULL;
// Set default order value
// If a value is specifed in GET, use that. Else use the first element in the array
$order = isset($_GET[$get_name]) ? $_GET[$get_name] : $orders[0];
if (in_array($order, $orders))
$order = $order;
else
$order = $orders[0];
return $order;
}
/**
* Opposite of php's nl2br function.
* Subs in a newline for all brs
* @param string $subject line to make subs on
* @return reformatted line
*/
function br2nl($subject) {
return str_replace('<br />', "\n", $subject);
}
/**
* Writes a log string to the log file specified in config.php
* @param string $string log entry to write to file
* @param string $userid memeber id of user performing the action
* @param string $ip ip address of user performing the action
*/
function write_log($string, $userid = NULL, $ip = NULL) {
global $conf;
$delim = "\t";
$file = $conf['app']['logfile'];
$values = '';
if (!$conf['app']['use_log']) // Return if we aren't going to log
return;
if (empty($ip))
$ip = $_SERVER['REMOTE_ADDR'];
clearstatcache(); // Clear cached results
if (!is_dir(dirname($file)))
mkdir(dirname($file), 0777); // Create the directory
if (!touch($file))
return; // Return if we cant touch the file
if (!$fp = fopen($file, 'a'))
return; // Return if the fopen fails
flock($fp, LOCK_EX); // Lock file for writing
if (!fwrite($fp, '[' . date('D, d M Y H:i:s') . ']' . $delim . $ip . $delim . $userid . $delim . $string . "\r\n")) // Write log entry
return; // Return if we cant write to the file
flock($fp, LOCK_UN); // Unlock file
fclose($fp);
}
/**
* Returns the day name
* @param int $day_of_week day of the week
* @param int $type how to return the day name (0 = full, 1 = one letter, 2 = two letter, 3 = three letter)
*/
function get_day_name($day_of_week, $type = 0) {
global $days_full;
global $days_abbr;
global $days_letter;
global $days_two;
$names = array (
$days_full, $days_letter, $days_two, $days_letter
/*
array ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),
array ('S', 'M', 'T', 'W', 'T', 'F', 'S'),
array ('Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'),
array ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
*/
);
return $names[$type][$day_of_week];
}
/**
* Redirects a user to a new location
* @param string $location new http location
* @param int $time time in seconds to wait before redirect
*/
function redirect($location, $time = 0, $die = true) {
header("Refresh: $time; URL=$location");
if ($die) exit;
}
/**
* Prints out the HTML to choose a language
* @param none
*/
function print_language_pulldown() {
global $conf;
?>
<select name="language" class="textbox" onchange="changeLanguage(this);">
<?
$languages = get_language_list();
foreach ($languages as $lang => $settings) {
echo '<option value="' . $lang . '"'
. ((determine_language() == $lang) ? ' selected="selected"' : '' )
. '>' . $settings[3] . ($lang == $conf['app']['defaultLanguage'] ? ' ' . translate('(Default)') : '') . "</option>\n";
}
?>
</select>
<?
}
/**
* Searches the input string and creates links out of any properly formatted 'URL-like' text
* Written by Fredrik Kristiansen (russlndr at online.no)
* and Albrecht Guenther (ag at phprojekt.de).
* @param string $str string to search for links to create
* @return string with 'URL-like' text changed into clickable links
*/
function html_activate_links($str) {
$str = eregi_replace('(((f|ht){1}tp://)[-a-zA-Z0-9@:%_+.~#?&//=]+)', '<a href="\1" target="_blank">\1</a>', $str);
$str = eregi_replace('([[:space:]()[{}])(www.[-a-zA-Z0-9@:%_+.~#?&//=]+)', '\1<a href="http://\2" target="_blank">\2</a>', $str);
$str = eregi_replace('([_.0-9a-z-]+@([0-9a-z][0-9a-z-]+.)+[a-z]{2,3})','<a href="mailto:\1">\1</a>', $str);
return $str;
}
/**
* Verifies current page number and returns value
* @param integer $page value of current page number
* @return integer current page number
*/
function get_current_page_number($get_name = 'page') {
// If no page number is specified, use 0
$page = ( isset($_GET[$get_name]) && is_numeric($_GET[$get_name]) ) ? $_GET[$get_name] : 0;
return $page;
}
/**
* Gets the requested mail_id
* @param none
* @return string mail_id
*/
function get_mail_id($get_name = 'mail_id') {
// If there isnt one set, return NULL
$mail_id = (isset($_GET[$get_name])) ? $_GET[$get_name] : NULL;
return $mail_id;
}
/**
* Verifies and returns the order to list recordset results by
/**
* Convert an array to a query string
* @param array $array
* @param array $exclude_vars to be excluded from the resulting string
* @param boolean $url_encode_ampersands
*/
function array_to_query_string( $array, $exclude_vars=array(), $url_encode_ampersands=true )
{
if( ! is_array( $array ) )
return '';
if( ! $array )
return '';
$str = '';
$i=0;
foreach( $array as $name => $val ) {
if( ! in_array( $name, $exclude_vars ) ) {
if( $i>0 )
if( $url_encode_ampersands )
$str .= '&amp;';
else
$str .= '&';
$str .= urlencode( $name ) . '=' . urlencode( $val );
$i++;
}
}
return $str;
}
/**
* Generate HTML for multipage links
* @param integer $page current page
* @param integer $sizeLimit maximum number of messages per page
* @param integer $count total number of messages
*/
function genMultiPagesLinks( $page, $sizeLimit, $count) {
global $link;
$total_pages = $count / $sizeLimit;
$php_self = $_SERVER['PHP_SELF'];
if( $page != 0 ) {
$query_string = CmnFns::array_to_query_string( $_GET, array( 'page' ) );
$query_string_first = $query_string . '&page=0';
$query_string_previous = $query_string . '&page=' . ($page-1);
$pager_html .= $link->getLink($php_self . '?' . $query_string_first, translate('first'), '', '', translate('Go to first page')) . " | ";
$pager_html .= $link->getLink($php_self . '?' . $query_string_previous, translate('previous'), '', '', translate('Go to previous page')) . " | ";
} else {
$pager_html .= translate('first') . " | " . translate('previous') ." | ";
}
$pager_html .= '&nbsp;&nbsp;';
// for large search results where we page beyone the first 20 pages,
// print elipsis instead of making the pager be super wide.
$elipsis_printed = false;
for( $i=0; $i<$count; $i+=$sizeLimit ) {
$page_num = $i/$sizeLimit;
if( $count > $size_limit * 20 && abs( $page_num - $page ) > 10 ) {
if( ! $elipsis_printed ) {
$pager_html .= '...&nbsp;&nbsp;';
$elipsis_printed = true;
}
} else if( $page == $page_num ) {
$pager_html .= '<b>' . ($page_num + 1) . '</b>';
$pager_html .= '&nbsp;&nbsp;';
$elipsis_printed = false;
} else {
$query_string = CmnFns::array_to_query_string( $_GET, array( 'page' ) );
$query_string .= '&page=' . $page_num;
$pager_html .= $link->getLink($php_self . '?' . $query_string, ($page_num+1), '', '', translate('Go to page') . ' ' . ($page_num+1));
$pager_html .= '&nbsp;&nbsp;';
$elipsis_printed = false;
}
}
if( $page+1 < $total_pages ) {
$query_string = CmnFns::array_to_query_string( $_GET, array( 'page' ) );
$query_string_next .= $query_string . '&page=' . ($page+1);
$query_string_last .= $query_string . '&page=' . (ceil($total_pages)-1);
$pager_html .= ' | ' . $link->getLink($php_self . '?' . $query_string_next, strtolower(translate('Next')), '', '', translate('Go to next page'));
$pager_html .= ' | ' . $link->getLink($php_self . '?' . $query_string_last, translate('last'), '', '', translate('Go to last page'));
} else {
$pager_html .= " | " . strtolower(translate('Next')) . " | " . translate('last');
}
return $pager_html;
}
/**
* Generate HTML for search engine
* @param $content_type: 'B' (attachment) or 'S' (spam)
*/
function searchEngine($content_type, $submit_page, $full_search = false) {
global $conf;
$fields_array = array("f" => translate('From'),
"s" => translate('Subject')
);
if (Auth::isMailAdmin() || $conf['app']['allowMailid']) {
$fields_array = array_merge(array("m" => "Mail ID"), $fields_array);
}
if ($full_search) $fields_array = array_merge(array("t" => translate('To')), $fields_array);
?>
<table border=0 width="100%">
<form action="<? echo $submit_page ?>" method="get" name="quarantine">
<tr><td colspan=2 align="center"><? echo translate('Search for messages whose:'); ?>&nbsp;</td></tr>
<tr><td align="right">&nbsp;
<?
$i = 1;
$array_size = count($fields_array);
foreach ($fields_array as $k => $name) {
echo "\t\t\t$name: \n";
echo "\t\t\t<select name='" . $k . "_criterion' class='button'>\n";
echo "\t\t\t<option value='contains'";
echo "contains" == CmnFns::getGlobalVar($k . '_criterion', GET) ? " selected='true'>" : ">";
echo translate('contains') . "</option>\n";
echo "\t\t\t<option value='not_contain'";
echo "not_contain" == CmnFns::getGlobalVar($k . '_criterion', GET) ? " selected='true'>" : ">";
echo translate('doesn\'t contain') . "</option>\n";
echo "\t\t\t<option value='equals'";
echo "equals" == CmnFns::getGlobalVar($k . '_criterion', GET) ? " selected='true'>" : ">";
echo translate('equals') . "</option>\n";
echo "\t\t\t<option value='not_equal'";
echo "not_equal" == CmnFns::getGlobalVar($k . '_criterion', GET) ? " selected='true'>" : ">";
echo translate('doesn\'t equal') . "</option>\n";
echo "\t\t\t</select>\n";
echo "\t\t\t<input type='text' name='" . $k . "_string' size='20' value='"
. CmnFns::getGlobalVar($k . '_string', GET) . "' />\n";
echo ($i % 2) ? "\t\t\t&nbsp;</td>\n\t\t\t<td align='left'>&nbsp\n" : "\t\t\t&nbsp;</td></tr>\n\t\t\t<tr><td align='right'>&nbsp\n";
$i ++;
}
?>
<? echo translate('Content Type'); ?>:
<select name="ctype" class="button">
<option value="A" <? echo ($content_type == 'A' ? ' selected="true"':''); ?>>
<? echo translate('All'); ?></option>
<option value="S" <? echo ($content_type == 'S' ? ' selected="true"':''); ?>>
<? echo translate('Spam'); ?></option>
<option value="B" <? echo ($content_type == 'B' ? ' selected="true"':''); ?>>
<? echo translate('Banned'); ?></option>
<? if (Auth::isMailAdmin() || $conf['app']['allowViruses']) { ?>
<option value="V" <? echo ($content_type == 'V' ? ' selected="true"':''); ?>>
<? echo translate('Virus'); ?></option>
<? }
if (Auth::isMailAdmin() || $conf['app']['allowBadHeaders']) { ?>
<option value="H" <? echo ($content_type == 'H' ? ' selected="true"':''); ?>>
<? echo translate('Bad Header'); ?></option>
<? }
echo "</select>";
$i ++;
echo ($i % 2) ? "&nbsp;</td></tr>\n\t\t\t<tr><td colspan='2' align='center'>&nbsp\n" : "&nbsp;</td><td align='left'>&nbsp";
?>
<input type="submit" class="button" name="search_action" value="<? echo translate('Search'); ?>" />
<? if (CmnFns::didSearch())
echo "<input type=\"submit\" class=\"button\" name=\"search_action\" value=\"" . translate('Clear search results') . "\" />";
?>
&nbsp;</td></tr>
</form>
</table>
<?
}
/**
* Did we do a search?
* @param none
* @return value boolean
*/
function didSearch() {
$return = false;
$strings = array('f_string','s_string','t_string','m_string');
foreach ($strings as $string) {
if ( CmnFns::getGlobalVar($string, GET) != '') $return = true;
}
return $return;
}
/**
* Function that convert $_GET into query string and exclude array
* @param array of variables to exclude
* @return query string
*/
function querystring_exclude_vars( $excl_array = array() ) {
return CmnFns::array_to_query_string( $_GET, $excl_array );
}
/**
* Gets the 'ctype' value
* @param none
* @return value
*/
function get_ctype($get_name = 'ctype') {
// If there isnt one set, return NULL
$result = NULL;
if ( isset($_GET[$get_name]) )
$result = $_GET[$get_name];
elseif ( isset($_POST[$get_name]) )
$result = $_POST[$get_name];
return $result;
}
/**
* Gets the 'action' value
* @param none
* @return value
*/
function get_action($get_name = 'action') {
// If there isnt one set, return NULL
$result = (isset($_POST[$get_name])) ? $_POST[$get_name] : NULL;
return $result;
}
/**
* Gets the 'query_string' value
* @param none
* @return value
*/
function get_query_string($get_name = 'query_string') {
// If there isnt one set, return NULL
$result = (isset($_POST[$get_name])) ? $_POST[$get_name] : NULL;
return $result;
}
/*
* Search for the var $name in $_SESSION, $_POST, $_GET,
* $_SERVER and set it in provided var.
*
* If $search is not provided, or == INORDER, it will search
* $_SESSION, then $_POST, then $_GET. Otherwise,
* use one of the defined constants to look for
* a var in one place specifically.
*
* Note: $search is an int value equal to one of the
* constants defined above.
*
* example:
* getGlobalVar('page', GET);
* -- no quotes around last param!
*
* @param string $name the name of the var to search
* @param int search constant defining where to look:
* INORDER, SESSION, FORM, POST, GET, SERVER
* @return value of var
*/
function getGlobalVar($name, $search = INORDER) {
switch ($search) {
/* we want the default case to be first here,
so that if a valid value isn't specified,
all four arrays will be searched. */
default:
case INORDER: // check session, post, get
case SESSION:
if( isset($_SESSION[$name]) )
return $_SESSION[$name];
elseif ( $search == SESSION )
break;
case FORM: // check post, get
case POST:
if( isset($_POST[$name]) )
return $_POST[$name];
elseif ( $search == POST )
break;
case GET:
if( isset($_GET[$name]) )
return $_GET[$name];
/* For INORDER case, exit after GET */
break;
case SERVER:
if( isset($_SERVER[$name]) )
return $_SERVER[$name];
break;
}
return NULL;
}
/*
* Redirect using javascript
* @param $location string
*/
function redirect_js($location) {
echo "<SCRIPT LANGUAGE=\"JavaScript\">";
echo "parent.location.href = '" . $location . "';";
echo "</SCRIPT>";
}
}
?>

237
lib/DBAuth.class.php Normal file
View File

@@ -0,0 +1,237 @@
<?php
/**
* DBAuth class
* @author Samuel Tran
* @version 04-26-2005
* @package DBAuth
*
* Following functions taken from PhpScheduleIt,
* Nick Korbel <lqqkout13@users.sourceforge.net>:
* db_connect(), cleanRow(), get_err()
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Pear::DB
*/
if ($GLOBALS['conf']['app']['safeMode']) {
ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
include_once('pear/DB.php');
}
else {
include_once('DB.php');
}
/**
* Provide all database access/manipulation functionality for SQL Auth
*/
class DBAuth {
// Reference to the database object
var $db;
// The database hostname with port (hostname[:port])
var $dbHost;
// Database type
var $dbType;
// Database name
var $dbName;
// Database user
var $dbUser;
// Password for database user
var $dbPass;
// Name for auth table that contains usernames and passwords
var $dbTable;
// Name of the Username field of the MySQL table
var $dbTableUsername;
// Name of the password field of the MySQL table
var $dbTablePassword;
// Name of the 'first name' or 'full name' field of the MySQL table
var $dbTableName;
// Name of the email address field of the MySQL table
var $dbTableMail;
// Hash configuration
// 1 = passwords will be stored md5 encrypted on database
// other number = passwords will be stored as is on database
var $isMd5;
// The user's logon name
var $logonName;
// The user's first name
var $firstName;
// The user's mail address
var $emailAddress;
var $err_msg = '';
/**
* DBEngine constructor to initialize object
* @param none
*/
function DBAuth() {
global $conf;
$this->dbType = $conf['auth']['dbType'];
$this->dbHost = $conf['auth']['dbHostSpec'];
$this->dbName = $conf['auth']['dbName'];
$this->dbUser = $conf['auth']['dbUser'];
$this->dbPass = $conf['auth']['dbPass'];
$this->isMd5 = $conf['auth']['dbIsMd5'];
$this->dbTable = $conf['auth']['dbTable'];
$this->dbTableUsername = $conf['auth']['dbTableUsername'];
$this->dbTablePassword = $conf['auth']['dbTablePassword'];
$this->dbTableName = $conf['auth']['dbTableName'];
$this->dbTableMail = $conf['auth']['dbTableMail'];
$this->db_connect();
}
// Connection handling methods -------------------------------------------
/**
* Create a persistent connection to the database
* @param none
*/
function db_connect() {
/***********************************************************
/ This uses PEAR::DB
/ See http://www.pear.php.net/manual/en/package.database.php#package.database.db
/ for more information and syntax on PEAR::DB
/**********************************************************/
// Data Source Name: This is the universal connection string
// See http://www.pear.php.net/manual/en/package.database.php#package.database.db
// for more information on DSN
$dsn = $this->dbType . '://' . $this->dbUser . ':' . $this->dbPass
. '@' . $this->dbHost . '/' . $this->dbName;
// Make persistant connection to database
$db = DB::connect($dsn, true);
// If there is an error, print to browser, print to logfile and kill app
if (DB::isError($db)) {
die ('Error connecting to database: ' . $db->getMessage() );
}
// Set fetch mode to return associatve array
$db->setFetchMode(DB_FETCHMODE_ASSOC);
$this->db = $db;
}
// User methods -------------------------------------------
/**
* Authenticates user
* @param string $username
* @param string $password
* @return boolean
*/
function authUser($username, $password) {
if ( $this->isMd5 )
$password = md5( $password );
$query = "SELECT $this->dbTableUsername, $this->dbTableMail"
. (! empty($this->dbTableName) ? ", $this->dbTableName" : '')
. " FROM $this->dbTable"
. " WHERE $this->dbTableUsername=?"
. " AND $this->dbTablePassword=?";
$values = array($username, $password);
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q, $values);
// Check if error
$this->check_for_error($result);
if ($result->numRows() <= 0) {
$this->err_msg = translate('There are no records in the table.');
return false;
} else {
// Fetch the first row of data
$rs = $this->cleanRow($result->fetchRow());
$this->logonName = $rs[$this->dbTableUsername];
$this->firstName = ( !empty($rs[$this->dbTableName]) ?
$rs[$this->dbTableName] : $rs[$this->dbTableUsername] );
$this->emailAddress = array( $rs[$this->dbTableMail] );
$result->free();
return true;
}
}
/**
* Checks to see if there was a database error and die if there was
* @param object $result result object of query
*/
function check_for_error($result) {
if (DB::isError($result))
CmnFns::do_error_box(translate('There was an error executing your query') . '<br />'
. $result->getMessage()
. '<br />' . '<a href="javascript: history.back();">' . translate('Back') . '</a>');
return false;
}
/**
* Strips out slashes for all data in the return row
* - THIS MUST ONLY BE ONE ROW OF DATA -
* @param array $data array of data to clean up
* @return array with same key => value pairs (except slashes)
*/
function cleanRow($data) {
$return = array();
foreach ($data as $key => $val)
$return[$key] = stripslashes($val);
return $return;
}
/**
* Returns the last database error message
* @param none
* @return last error message generated
*/
function get_err() {
return $this->err_msg;
}
// Helper methods -------------------------------------------
/**
* Returns user information
* @return array containing user information
*/
function getUserData() {
$return = array(
'logonName' => $this->logonName,
'firstName' => $this->firstName,
'emailAddress' => $this->emailAddress
);
return $return;
}
}
?>

770
lib/DBEngine.class.php Normal file
View File

@@ -0,0 +1,770 @@
<?php
/**
* DBEngine class
*
* @author Samuel Tran <stran2005@users.sourceforge.net>
* @author Brian Wong <bwsource@users.sourceforge.net>
* @author Jeremy Fowler <jfowler06@users.sourceforge.net>
* @version 02-21-2007
* @package DBEngine
*
* Following functions taken from PhpScheduleIt,
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @version 03-29-05:
* db_connect(), check_for_error(), cleanRow(), get_err()
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Auth class
*/
include_once('lib/Auth.class.php');
/**
* Pear::DB
*/
if ($GLOBALS['conf']['app']['safeMode']) {
ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
include_once('pear/DB.php');
}
else {
include_once('DB.php');
}
/**
* Provide all database access/manipulation functionality
*/
class DBEngine {
// Reference to the database object
var $db;
// The database hostname with port (hostname[:port])
var $dbHost;
// Database type
var $dbType;
// Database name
var $dbName;
// Database user
var $dbUser;
// Password for database user
var $dbPass;
var $err_msg = '';
var $numRows;
/**
* DBEngine constructor to initialize object
* @param none
*/
function DBEngine() {
global $conf;
$this->dbType = $conf['db']['dbType'];
$this->dbName = $conf['db']['dbName'];
$this->dbUser = $conf['db']['dbUser'];
$this->dbPass = $conf['db']['dbPass'];
$this->dbHost = $conf['db']['hostSpec'];
$this->db_connect();
}
/**
* Create a persistent connection to the database
* @param none
* @global $conf
*/
function db_connect() {
/***********************************************************
/ This uses PEAR::DB
/ See http://www.pear.php.net/manual/en/package.database.php#package.database.db
/ for more information and syntax on PEAR::DB
/**********************************************************/
// Data Source Name: This is the universal connection string
// See http://www.pear.php.net/manual/en/package.database.php#package.database.db
// for more information on DSN
$dsn = $this->dbType . '://' . $this->dbUser . ':' . $this->dbPass
. '@' . $this->dbHost . '/' . $this->dbName;
// Make persistant connection to database
$db = DB::connect($dsn, true);
// If there is an error, print to browser, print to logfile and kill app
if (DB::isError($db)) {
CmnFns::write_log('Error connecting to database: ' . $db->getMessage(), $_SESSION['sessionID']);
die ('Error connecting to database: ' . $db->getMessage() );
}
// Set fetch mode to return associatve array
$db->setFetchMode(DB_FETCHMODE_ASSOC);
$this->db = $db;
}
/**
* Return counts for spam, banned, viruses, bad headers, and pending
* @return array of the 5 counts
*/
function get_site_summary() {
global $conf;
$return = array();
$total = array( 'spam' => 0, 'banned' => 0, 'virus' => 0, 'header' => 0, 'pending' => 0, 'total' => 0);
$query = "SELECT date,
MAX(stattable.spam) AS spam,
MAX(stattable.banned) AS banned,
MAX(stattable.viruses) AS viruses,
MAX(stattable.badheaders) AS badheaders,
MAX(stattable.pending) AS pending
FROM (
SELECT CAST(time_iso AS DATE) AS date,
COUNT(content) AS spam,
0 AS banned,
0 AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
WHERE content='S' AND NOT (msgs.quar_type = '')
AND msgrcpt.rs IN ('','v')
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
COUNT(content) AS banned,
0 AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
WHERE content='B' AND NOT (msgs.quar_type = '')
AND msgrcpt.rs IN ('','v')
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
COUNT(content) AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
WHERE content='V' AND NOT (msgs.quar_type = '')
AND msgrcpt.rs IN ('','v')
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
0 AS viruses,
COUNT(content) AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
WHERE content='H' AND NOT (msgs.quar_type = '')
AND msgrcpt.rs IN ('','v')
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
0 AS viruses,
0 AS badheaders,
COUNT(content) AS pending
FROM msgs JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
WHERE msgrcpt.rs='p' AND NOT (msgs.quar_type = '')
GROUP BY CAST(time_iso AS DATE)
) AS stattable
GROUP BY date
ORDER BY date";
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q);
// Check if error
$this->check_for_error($result, $query);
while ($rs = $result->fetchRow()) {
$timestamp = CmnFns::formatDateISO($rs['date']);
$date = CmnFns::formatDate($timestamp);
$totalthisdate = $rs['spam'] + $rs['banned'] + $rs['viruses'] + $rs['badheaders'] + $rs['pending'];
$return[$date] = array('spam' => $rs['spam'],
'banned' => $rs['banned'],
'virus' => $rs['viruses'],
'header' => $rs['badheaders'],
'pending' => $rs['pending'],
'total' => $totalthisdate);
}
// Total the data
foreach ($return as $date => $typearray) {
foreach ($typearray as $type => $count) {
$total[$type] += $count;
}
}
$return['Total'] = $total;
$result->free();
return $return;
}
// User methods -------------------------------------------
/**
* Return counts for spam, banned, viruses, bad headers, and pending
* @param string full email address
* @return array of the 5 counts
*/
function get_user_summary($emailaddresses) {
global $conf;
$return = array();
$total = array('spam' => 0, 'banned' => 0, 'virus' => 0, 'header' => 0, 'pending' => 0, 'total' => 0);
// Get where clause for recipient email address(es)
$recipEmailClause = $this->convertEmailaddresses2SQL($emailaddresses);
# mysql seems to run faster with a left join
if ($conf['db']['dbtype'] == 'mysql') {
$join_type = ' LEFT JOIN';
} else {
$join_type = ' INNER JOIN';
}
$query = "SELECT date,
MAX(stattable.spam) AS spam,
MAX(stattable.banned) AS banned,
MAX(stattable.viruses) AS viruses,
MAX(stattable.badheaders) AS badheaders,
MAX(stattable.pending) AS pending
FROM (
SELECT CAST(time_iso AS DATE) AS date,
COUNT(content) AS spam,
0 AS banned,
0 AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE content='S' AND NOT (msgs.quar_type = '') AND msgrcpt.rs IN ('','v')
AND $recipEmailClause
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
COUNT(content) AS banned,
0 AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE content='B' AND NOT (msgs.quar_type = '') AND msgrcpt.rs IN ('','v')
AND $recipEmailClause
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
COUNT(content) AS viruses,
0 AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE content='V' AND NOT (msgs.quar_type = '') AND msgrcpt.rs IN ('','v')
AND $recipEmailClause
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
0 AS viruses,
COUNT(content) AS badheaders,
0 AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE content='H' AND NOT (msgs.quar_type = '') AND msgrcpt.rs IN ('','v')
AND $recipEmailClause
GROUP BY CAST(time_iso AS DATE)
UNION
SELECT CAST(time_iso AS DATE) AS date,
0 AS spam,
0 AS banned,
0 AS viruses,
0 AS badheaders,
COUNT(content) AS pending
FROM msgs INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE msgrcpt.rs='p' AND NOT (msgs.quar_type = '')
AND $recipEmailClause
GROUP BY CAST(time_iso AS DATE)
) AS stattable
GROUP BY date
ORDER BY date";
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q);
// Check if error
$this->check_for_error($result, $query);
while ($rs = $result->fetchRow()) {
$timestamp = CmnFns::formatDateISO($rs['date']);
$date = CmnFns::formatDate($timestamp);
$totalthisdate = $rs['spam'] + $rs['banned'] + $rs['viruses'] + $rs['badheaders'] + $rs['pending'];
$return[$date] = array('spam' => $rs['spam'],
'banned' => $rs['banned'],
'virus' => $rs['viruses'],
'header' => $rs['badheaders'],
'pending' => $rs['pending'],
'total' => $totalthisdate);
}
// Total the data
foreach ($return as $date => $typearray) {
foreach ($typearray as $type => $count) {
$total[$type] += $count;
}
}
$return['Total'] = $total;
$result->free();
return $return;
}
/**
* Return all message in quarantine associated with $emailaddress
* @param string $content_type message type ('B', 'S', ...)
* @param array $emailaddresses user email address(es)
* @param string $order sql order string
* @param string $vert sql vertical order string
* @param array $search_array for search engine
* @param boolean $msgs_all if true get messages for all users, if false get messages for users in $emailaddresses
* @param integer $rs_option: 0 for new and read messages; 1 for pending messagesr; 2 for new, read and pending
* @param integer $page: page number, 0 by default
* @param boolean $get_all, if true get all messages. False by default.
* @return array of messages in quarantine
*/
function get_user_messages($content_type, $emailaddresses, $order = 'msgs.time_num', $vert = 'DESC', $search_array = '', $msgs_all = false, $rs_option = 0, $page = 0, $get_all = false) {
global $conf;
# MySQL seems to run faster with a LEFT JOIN
if ($conf['db']['dbType'] == 'mysql') {
$join_type = ' LEFT JOIN';
} else {
$join_type = ' INNER JOIN';
}
// grab the display size limit set in config.php
$sizeLimit = isset ( $conf['app']['displaySizeLimit'] ) && is_numeric( $conf['app']['displaySizeLimit'] ) ?
$conf['app']['displaySizeLimit'] : 50;
$return = array();
if (is_array($search_array)) {
$search_clause = "";
foreach($search_array as $filter) {
$search_clause .= ' AND ' . $filter;
}
}
if ( ! $msgs_all ) {
// Get where clause for recipient email address(es)
$emailaddr_clause = ( ! empty($emailaddresses) ?
' AND ' . $this->convertEmailaddresses2SQL($emailaddresses) :
'' );
}
switch ($rs_option) {
case 0:
$rs_clause = ' AND msgrcpt.rs in (\'\', \'v\')';
break;
case 1:
$rs_clause = ' AND msgrcpt.rs=\'p\'';
break;
case 2:
$rs_clause = ' AND msgrcpt.rs in (\'\', \'v\', \'p\')';
break;
default:
$rs_clause = '';
}
if ( Auth::isMailAdmin() ) {
$type_clause = ($content_type == 'A' ? ' msgs.content in (\'S\', \'B\', \'V\', \'H\')'
: ' msgs.content=?');
} else {
if ( $content_type == 'A' ) {
$type_clause = ' msgs.content in (\'S\', \'B\'';
$type_clause = ( $conf['app']['allowBadHeaders'] ? $type_clause . ', \'H\'' : $type_clause );
$type_clause = ( $conf['app']['allowViruses'] ? $type_clause . ', \'V\')' : $type_clause . ')' );
} else {
$type_clause = ' msgs.content=?';
}
}
$query = "SELECT msgs.time_num, msgs.from_addr,
msgs.mail_id, msgs.subject, msgs.spam_level, msgs.content,
msgrcpt.rs, msgs.quar_type, recip.email
FROM msgs
INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id
$join_type maddr AS sender ON msgs.sid=sender.id
$join_type maddr AS recip ON msgrcpt.rid=recip.id
WHERE $type_clause"
// Only check against the email address when not admin
. ($msgs_all ? ' ' : $emailaddr_clause)
. " $rs_clause
$search_clause
AND msgs.quar_type <> ''
ORDER BY $order $vert ";
// Prepare query
$q = $this->db->prepare($query);
if ($content_type != 'A') {
// Prepend the content type if we want a specific type of mail
$values = array($content_type);
// Execute query
$result = $this->db->execute($q, $values);
} else {
$result = $this->db->execute($q);
}
// Check if error
$this->check_for_error($result, $query);
$this->numRows = $result->numRows();
if ($this->numRows <= 0) {
return NULL;
}
if ( $get_all ) {
while ($rs = $result->fetchRow()) {
$return[] = $this->cleanRow($rs);
}
} else {
// the row to start fetching
$from = $page * $sizeLimit;
// how many results per page
$res_per_page = $sizeLimit;
// the last row to fetch for this page
$to = $from + $res_per_page - 1;
foreach (range($from, $to) as $rownum) {
if (!$row = $result->fetchrow(DB_FETCHMODE_ASSOC, $rownum)) {
break;
}
$return[] = $this->cleanRow($row);
}
}
$result->free();
return $return;
}
/**
* Return message(s) in quarantine associated with $emailaddress and $mail_id
* @param string $emailaddress user email address
* @param string $mail_id message mail_id
* @param boolean $isAdmin is true is the logged in user is MailAdmin/SuperAdmin
* @return array of message(s)
*/
function get_message($emailaddress, $mail_id) {
global $conf;
# MySQL seems to run faster with a LEFT JOIN
if ($conf['db']['dbType'] == 'mysql') {
$join_type = ' LEFT JOIN';
} else {
$join_type = ' INNER JOIN';
}
$recipEmailClause = $this->convertEmailaddresses2SQL($emailaddresses);
$return = array();
$query = 'SELECT msgs.time_num, msgs.secret_id, msgs.subject, msgs.from_addr, msgs.spam_level,'
. ' msgrcpt.rs, recip.email, msgs.host, msgs.content, msgs.quar_type, msgs.quar_loc'
. ' FROM msgs'
. ' INNER JOIN msgrcpt ON msgs.mail_id=msgrcpt.mail_id'
. $join_type . ' maddr AS sender ON msgs.sid=sender.id'
. $join_type . ' maddr AS recip ON msgrcpt.rid=recip.id'
. ' WHERE recip.email=? '
. ' AND msgs.mail_id=? ';
$values = array($emailaddress, $mail_id);
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q, $values);
// Check if error
$this->check_for_error($result, $query);
if ($result->numRows() <= 0) {
return NULL;
}
while ($rs = $result->fetchRow()) {
$return[] = $this->cleanRow($rs);
}
$result->free();
return $return;
}
/**
* Set RS flag in table 'msgrcpt'
* @param string $mail_id message mail_id
* @param string $mail_rcpt user email address
* @param string $flag status ('', 'R', 'D' ...)
* @param boolean $isAdmin is true is the logged in user is MailAdmin/SuperAdmin
* @return array of message(s)
*/
function update_msgrcpt_rs($mail_id, $mail_rcpt, $flag) {
// If its a pending message, do not set the rs flag to 'v'
$cur_msg_array = $this->get_message($mail_rcpt, $mail_id);
$msg_status = $cur_msg_array[0];
if ($msg_status['rs'] == 'p' && $flag == 'v') return true;
$query = 'UPDATE msgrcpt SET rs=?'
. ' WHERE mail_id=?'
. ' AND rid=(SELECT id FROM maddr WHERE email=?)';
$values = array($flag, $mail_id, $mail_rcpt);
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q, $values);
// Check if error
$this->check_for_error($result, $query);
return true;
}
/**
* Function that returns number of entries for logged in user
* where RS flag is equal to $flag
* @param array $emailaddresses user email address(es)
* @param string $flag 'P', 'R', ...
* @return number of message(s)
*/
function get_count_rs($emailaddresses, $flag) {
// Get where clause for recipient email address(es)
$emailaddr_clause = $this->convertEmailaddresses2SQL($emailaddresses);
if ( $emailaddr_clause != '' )
$emailaddr_clause = ' AND ' . $emailaddr_clause;
$query = 'SELECT mail_id FROM msgrcpt, maddr as recip'
. ' WHERE msgrcpt.rid=recip.id'
. $emailaddr_clause
. ' AND rs=?';
$values = array($flag);
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q, $values);
// Check if error
$this->check_for_error($result, $query);
$count = $result->numRows();
$result->free();
return $count;
}
/**
* Get the raw email from the database
* @param string The unique identifying mail_id
* @param string The recipient's email address
* @return string The complete email string
*/
function get_raw_mail($mail_id, $email_recip) {
global $conf;
$mail_text_column = ' mail_text';
# If using the bytea or BLOB type for sql quarantine use proper conversion
# (since amavisd 2.4.4
if ($conf['db']['binquar']) {
if ($conf['db']['dbType'] == 'mysql') {
$mail_text_column = ' CONVERT(mail_text USING utf8) AS mail_text';
} else {
$mail_text_column = " encode(mail_text,'escape') AS mail_text";
}
}
if (Auth::isMailAdmin()) {
$values = array($mail_id);
$query = 'SELECT' . $mail_text_column . ' FROM quarantine ' .
'WHERE mail_id=?';
} else {
$values = array($mail_id, $email_recip);
$query = 'SELECT' . $mail_text_column . ' FROM quarantine Q, msgrcpt M, maddr recip ' .
'WHERE (Q.mail_id=?) AND (M.mail_id=Q.mail_id) AND (M.rid=recip.id) ' .
'AND (recip.email=?) ' .
'ORDER BY chunk_ind';
}
// Prepare query
$q = $this->db->prepare($query);
// Execute query
$result = $this->db->execute($q, $values);
// Check if error
$this->check_for_error($result, $query);
if ($result->numRows() <= 0){
return false;
}
while ($rs = $result->fetchRow()) {
$return .= $rs['mail_text'];
}
$result->free();
return $return;
}
/**
* Checks to see if there was a database error, log in file and die if there was
* @param object $result result object of query
* @param SQL query $query
*/
function check_for_error($result, $query) {
global $conf;
if (DB::isError($result)) {
$this->err_msg = $result->getMessage();
CmnFns::write_log($this->err_msg, $_SESSION['sessionID']);
CmnFns::write_log('There was an error executing your query' . ' '
. $query, $_SESSION['sessionID']);
CmnFns::do_error_box(translate('There was an error executing your query') . '<br />'
. $this->err_msg
. '<br />' . '<a href="javascript: history.back();">' . translate('Back') . '</a>');
} else {
if ($conf['app']['debug']) {
CmnFns::write_log("[DEBUG SQL QUERY]: $query");
}
}
return false;
}
/**
* Strips out slashes for all data in the return row
* - THIS MUST ONLY BE ONE ROW OF DATA -
* @param array $data array of data to clean up
* @return array with same key => value pairs (except slashes)
*/
function cleanRow($data) {
$return = array();
foreach ($data as $key => $val)
$return[$key] = stripslashes($val);
return $return;
}
/**
* Returns the last database error message
* @param none
* @return last error message generated
*/
function get_err() {
return $this->err_msg;
}
/**
* Convert search filter into SQL code
* @param string $field field of table to filter on
* @param string $criterion search criterion
* @param string $string search string
* @return array containing SQL code
*/
function convertSearch2SQL($field, $criterion, $string) {
$result = array();
if ( $string != '' ) {
switch ($criterion) {
case "contains":
$search_clause = "(" . $field . " LIKE '%" . $string . "%')" ;
break;
case "not_contain":
$search_clause = "(" . $field . " NOT LIKE '%" . $string . "%')" ;
break;
case "equals":
$search_clause = "(" . $field . "='" . $string . "')" ;
break;
case "not_equal":
$search_clause = "NOT (" . $field . "='" . $string . "')" ;
break;
default:
$search_clause = "";
}
array_push($result, $search_clause);
}
return $result;
}
/**
* Convert array of mail address(es) into SQL search clause
* @param array $emailaddresses list of email address(es)
* @return string containing SQL code
*/
function convertEmailaddresses2SQL($emailaddresses) {
global $conf;
$result = '';
$emailtuple = '';
if ( is_array($emailaddresses) && !empty($emailaddresses) ) {
foreach ( $emailaddresses as $value ) {
// Append an address to lookup
$emailtuple .= ( $emailtuple != '' ? ", '$value'" : "'$value'" );
}
$result = " recip.email in ($emailtuple) ";
// Configured to support recipient delimiters?
if(!empty($conf['recipient_delimiter']) ) {
$delimiter = $conf['recipient_delimiter'];
foreach ( $emailaddresses as $value ) {
// separate localpart and domain
list($localpart, $domain) = explode("@", $value);
// Append any recipient delimited addresses
$result .= "OR recip.email LIKE '$localpart$delimiter%@$domain' ";
}
}
}
// Return results within parentheses to isolate OR statements
return "($result)";
}
}
?>

126
lib/ExchAuth.class.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
/**
* ExchAuth class
* @version 07-23-2005
* @Author Bogdan Baliuc <b.baliuc@rogers.com>
* @package ExchAuth
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Provide all database access/manipulation functionality for Exchange Auth
*/
class ExchAuth {
// The exchange hostname with port (hostname[:port])
var $exchHost;
// The exchange LDAP URI (ldap://hostname[:port])
var $exchLDAP;
// The user's logon name
var $logonName;
// The user's first name
var $firstName;
// The user's mail address(es)
var $emailAddress;
var $err_msg = '';
/**
* Constructor to initialize object
* @param none
*/
function ExchAuth() {
global $conf;
$this->exchHost = $conf['auth']['exch_host'];
$this->exchLDAP = $conf['auth']['exch_ldap'];
}
// User methods -------------------------------------------
/**
* Authenticates user
* @param string $username
* @param string $password
* @param string $domain
* @return boolean
*/
function authUser($username, $password, $domain) {
$fulluser = $domain.'/'.$username;
$mbox = imap_open('{'.$this->exchHost.'/imap}Inbox', $fulluser, $password);
if ($mbox === false) {
$this->err_msg = translate('Invalid Username/Password');
return false;
} else {
$ignore = imap_errors();
imap_close($mbox);
}
$ldapconn = ldap_connect($this->exchLDAP);
if ($ldapconn === false) {
$this->err_msg = translate('Can not connect to LDAP server');
return false;
}
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
$ldapbind = ldap_bind($ldapconn);
if ($ldapbind === false) {
$this->err_msg = translate('Can not bind to LDAP server');
return false;
}
$ldapattr = array('cn', 'rfc822Mailbox' ,'otherMailbox');
$read = ldap_search($ldapconn, '', '(uid='.$username.')', $ldapattr);
if ($read === false) {
$this->err_msg = translate('Unable to search LDAP server');
return false;
}
$info = ldap_get_entries($ldapconn, $read);
$this->logonName = strtolower($username);
$this->firstName = $info[0]['cn'][0];
$this->emailAddress[] = strtolower($info[0]['rfc822mailbox'][0]);
for ($i=0; $i<$info[0]['othermailbox']['count']; $i++) {
$data = $info[0]['othermailbox'][$i];
if (strncasecmp($data, 'smtp$', 5) == 0) {
$this->emailAddress[] = strtolower(substr($data, 5));
}
}
ldap_close($ldapconn);
return true;
}
/**
* Returns the last error message
* @param none
* @return last error message generated
*/
function get_err() {
return $this->err_msg;
}
// Helper methods -------------------------------------------
/**
* Returns user information
* @return array containing user information
*/
function getUserData() {
$return = array(
'logonName' => $this->logonName,
'firstName' => $this->firstName,
'emailAddress' => $this->emailAddress
);
return $return;
}
}
?>

124
lib/IMAPAuth.class.php Normal file
View File

@@ -0,0 +1,124 @@
<?php
/**
* IMAPAuth class
* @version 08-11-2005
* @Author Samuel Tran
* @package IMAPAuth
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Provide all database access/manipulation functionality for IMAP Auth
*/
class IMAPAuth {
// The IMAP hosts with port (hostname[:port])
var $imapHosts;
// IMAP authentication type
var $imapType;
// Username
var $imapUsername;
var $err_msg = '';
/**
* Constructor to initialize object
* @param none
*/
function IMAPAuth() {
global $conf;
$this->imapHosts = $conf['auth']['imap_hosts'];
$this->imapType = $conf['auth']['imap_type'];
$this->imapDomainName = $conf['auth']['imap_domain_name'];
}
// User methods -------------------------------------------
/**
* Authenticates user
* @param string $username
* @param string $password
* @return boolean
*/
function authUser ($username, $password) {
// Returns true if the username and password work
// and false if they are wrong or don't exist.
$this->imapUsername = $username;
foreach ($this->imapHosts as $host) { // Try each host in turn
$host = trim($host);
switch ($this->imapType) {
case "imapssl":
$host = '{'.$host."/imap/ssl}INBOX";
break;
case "imapcert":
$host = '{'.$host."/imap/ssl/novalidate-cert}INBOX";
break;
case "imaptls":
$host = '{'.$host."/imap/notls}INBOX";
break;
default:
$host = '{'.$host.'}INBOX';
}
//error_reporting(0);
$connection = imap_open($host, $username, $password, OP_HALFOPEN);
if ($connection) {
imap_close($connection);
return true;
}
}
$this->err_msg = translate('IMAP Authentication: no match');
return false; // No match
}
/**
* Returns the last error message
* @param none
* @return last error message generated
*/
function get_err() {
return $this->err_msg;
}
// Helper methods -------------------------------------------
/**
* Returns user information
* @return array containing user information
*/
function getUserData() {
$return = array(
'logonName' => $this->imapUsername,
'firstName' => $this->imapUsername,
'emailAddress' => array( $this->imapUsername.
( empty($this->imapDomainName) ? '' :
'@'. $this->imapDomainName )
)
);
return $return;
}
}
?>

398
lib/LDAPEngine.class.php Normal file
View File

@@ -0,0 +1,398 @@
<?php
/**
* LDAPEngine class
* @author Samuel Tran
* @version 04-24-2005
* @package LDAPEngine
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
class LDAPEngine {
// The directory server, tested with OpenLDAP and Active Directory
var $serverType;
// An array of server IP address(es) or hostname(s)
var $hosts;
// SSL support
var $ssl;
// The base DN (e.g. "dc=example,dc=org")
var $basedn;
// The user identifier (e.g. "uid")
var $userIdentifier;
/**
/* The user to authenticate with when searching
/* if anonymous binding is not supported
/* (Active Directory doesn't support anonymous access by default)
*/
var $searchUser;
/**
/* The password to authenticate with when searching
/* if anonymous binding is not supported
/* (Active Directory doesn't support anonymous access by default)
*/
var $searchPassword;
/**
* Variable specific to Active Directory:
* Active Directory authenticates using user@domain
*/
var $domain;
/**
* Variables specific to LDAP:
* Container where the user records are kept
*/
var $userContainer;
// The login attribute to authenticate with
var $login;
// The password attribute to authenticate with
var $password;
// The name attribute of the user
var $name;
/**
* The mail attribute used as the recipient final address
* Could be the actual mail attribute or another attribute
* (in the latter case look for the "%m" token in the ldap query filter in amavisd.conf)
*/
var $mailAttr;
// The last error code returned by the LDAP server
var $ldapErrorCode;
// Text of the error message
var $ldapErrorText;
// The internal LDAP connection handle
var $connection;
// Result of any connection
var $bind;
var $connected;
// The user's logon name
var $logonName;
// The user's first name
var $firstName;
// The user's mail address ($mailAttr value)
var $emailAddress;
/**
* LDAPEngine constructor to initialize object
*/
function LDAPEngine() {
global $conf;
$this->serverType = strtolower($conf['auth']['serverType']);
switch ($this->serverType) {
case "ldap":
$this->hosts = $conf['auth']['ldap_hosts'];
$this->ssl = $conf['auth']['ldap_ssl'];
$this->basedn = $conf['auth']['ldap_basedn'];
$this->userIdentifier = $conf['auth']['ldap_user_identifier'];
$this->userContainer = $conf['auth']['ldap_user_container'];
$this->login = $conf['auth']['ldap_login'];
$this->name = $conf['auth']['ldap_name'];
$this->mailAttr = $conf['auth']['ldap_mailAttr'];
$this->searchUser = $conf['auth']['ldap_searchUser'];
$this->searchPassword = $conf['auth']['ldap_searchPassword'];
break;
case "ad":
$this->hosts = $conf['auth']['ad_hosts'];
$this->ssl = $conf['auth']['ad_ssl'];
$this->basedn = $conf['auth']['ad_basedn'];
$this->userIdentifier = $conf['auth']['ad_user_identifier'];
$this->domain = $conf['auth']['ad_domain'];
$this->login = $conf['auth']['ad_login'];
$this->name = $conf['auth']['ad_name'];
$this->mailAttr = $conf['auth']['ad_mailAttr'];
$this->searchUser = $conf['auth']['ad_searchUser'];
$this->searchPassword = $conf['auth']['ad_searchPassword'];
break;
default:
CmnFns::do_error_box(translate('Unknown server type'), '', false);
}
}
// Connection handling methods -------------------------------------------
/**
* Makes a connection to the LDAP server.
* Just creates a connection which is used in all later access.
* If it can't connect and bind anonymously, it creates an error code of -1.
* Returns true if connected, false if failed.
* Takes an array of possible servers - if one doesn't work, it tries the next and so on.
* @param none
*/
function connect() {
foreach ($this->hosts as $host) {
$ldap_url = ( $this->ssl ? "ldaps://".$host : $host );
$this->connection = ldap_connect($ldap_url);
if ($this->connection) {
ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
switch ($this->serverType) {
case "ad":
// Active Directory needs:
ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
break;
default:
break;
}
$this->connected = true;
return true;
} else {
CmnFns::write_log('LDAP connection failed', '');
}
}
$this->ldapErrorCode = -1;
$this->ldapErrorText = "Unable to connect to any server";
$this->connected = false;
return false;
}
/**
* Disconnects from the LDAP server
* @param none
*/
function disconnect() {
if( $this->connected ) {
if ( ! @ldap_close( $this->connection ) ) {
$this->ldapErrorCode = ldap_errno( $this->connection);
$this->ldapErrorText = ldap_error( $this->connection);
return false;
} else {
$this->connected = false;
return true;
}
}
return true;
}
/**
* Anonymously binds to the connection. After this is done,
* queries and searches can be done - but read-only.
*/
function anonBind() {
if ( ! $this->bind = ldap_bind($this->connection) ) {
$this->ldapErrorCode = ldap_errno( $this->connection);
$this->ldapErrorText = ldap_error( $this->connection);
CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, '');
return false;
} else {
return true;
}
}
/**
* Binds to the directory with a specific username and password:
* @param string $dn full LDAP dn or AD type 'user@domain'
* @param string $password password
* @return bool
*/
function authBind($username, $password) {
if ( ! $this->bind = @ldap_bind($this->connection, $username, $password) ) {
$this->ldapErrorCode = ldap_errno( $this->connection);
$this->ldapErrorText = ldap_error( $this->connection);
CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, '');
return false;
} else {
return true;
}
}
// User methods -------------------------------------------
/**
* Returns the full user DN to use, based on the ldap server type
* @param string $userlogin
* @return string
*/
function getUserDN($userlogin) {
switch ($this->serverType) {
case "ldap":
if ( $this->userContainer != '' && $this->userIdentifier == $this->login ) {
// If a user container is specified and the login attribute is the same
// as the user identifier attribute, build the user dn
$dn = "$this->userIdentifier=$userlogin," . "$this->userContainer," . $this->basedn;
} else {
// Search for user dn
$searchFilter = $this->login . "=" . $userlogin;
$dn = $this->searchUserDN($searchFilter);
}
break;
case "ad":
if ( strtolower($this->login) == 'samaccountname' ) {
// If the user login attribute is 'samaccountname', build the user AD login
$dn = $userlogin . "@" . $this->domain;
} else {
// Search for user dn
$searchFilter = $this->login . "=" . $userlogin;
$dn = $this->searchUserDN($searchFilter);
}
break;
default:
CmnFns::do_error_box(translate('Unknown server type'), '', false);
}
return $dn;
}
/**
* Returns the correct search base, based on the ldap server type
* @param none
* @return string
*/
function getSearchBase() {
switch ($this->serverType) {
case "ldap":
$searchBase = ( $this->userContainer != '' ? "$this->userContainer," . $this->basedn
: $this->basedn );
break;
case "ad":
$searchBase = $this->basedn;
break;
default:
CmnFns::do_error_box(translate('Unknown server type'), '', false);
}
return $searchBase;
}
/**
* Returns the correct user username that matches the search filter (array with single username)
* If several usernames are found, return the array of usernames.
* @param string $searchFilter search filter in a standard LDAP query
* @return array
*/
function searchUserDN($searchFilter) {
switch ($this->serverType) {
case "ldap":
if ( $this->searchUser != '' ) {
// If a search user is defined bind with this user
$this->authBind($this->searchUser, $this->searchPassword);
} else {
// Otherwise bind anonymously
$this->anonBind();
}
break;
case "ad":
// if the directory is AD, then bind first with the search user
$this->authBind($this->searchUser, $this->searchPassword);
break;
default:
CmnFns::do_error_box(translate('Unknown server type'), '', false);
}
$sr = ldap_search( $this->connection, $this->getSearchBase(), $searchFilter, array('dn'));
$entries = ldap_get_entries( $this->connection, $sr);
if ( $entries["count"] < 1 ) {
// If no results returned
$this->ldapErrorCode = -1;
$this->ldapErrorText = "No users found matching search criteria";
CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, '');
} else {
// The search should give an unique dn
// If several results are found get the first one
$dn = $entries[0]['dn'];
}
return $dn;
}
/**
* Queries LDAP for user information
* @param string $dn
* @return boolean indicating success or failure
*/
function loadUserData($dn) {
$this->emailAddress = array();
// We are instered in getting just the user's first name and his/her mail attribute(s)
$attributes = $this->mailAttr;
array_push( $attributes, strtolower($this->name) );
switch ($this->serverType) {
case "ldap":
$result = ldap_search( $this->connection, $dn, "objectclass=*", $attributes );
break;
case "ad":
if ( strtolower($this->login) == 'samaccountname' ) {
// dn is of the form 'user@domain'
list($samaccountname, $domain) = explode("@", $dn);
$result = ldap_search( $this->connection, $this->getSearchBase(),
$this->login . "=" . $samaccountname, $attributes );
} else {
// dn is standard LDAP dn
$result = ldap_search( $this->connection, $dn, "objectclass=*", $attributes );
}
break;
}
$entries = ldap_get_entries( $this->connection, $result );
if( $result and ( $entries["count"] > 0 ) ) {
// The search should give a single entry
// If several results are found get the first entry
$this->firstName = $entries[0][strtolower($this->name)][0];
foreach ( $this->mailAttr as $value ) {
// For single value or multiple value attribute
for ($i=0; $i<$entries[0][strtolower($value)]["count"]; $i++) {
# AD proxyAddresses attribute values have 'smtp:' string before the actual email address
if(preg_match("/^smtp:/i", strtolower($entries[0][strtolower($value)][$i])) == 1) {
array_push( $this->emailAddress, preg_replace("/^\w+:/", '', strtolower($entries[0][strtolower($value)][$i])) );
} else {
array_push( $this->emailAddress, strtolower($entries[0][strtolower($value)][$i]) );
}
}
}
} else {
// If no results returned
$this->ldapErrorCode = -1;
$this->ldapErrorText = "No entry found matching search criteria";
CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, '');
return false;
}
return true;
}
// Helper methods -------------------------------------------
/**
* Returns user information
* @return array containing user information
*/
function getUserData() {
$return = array(
'logonName' => $this->logonName,
'firstName' => $this->firstName,
'emailAddress' => $this->emailAddress
);
return $return;
}
}
?>

223
lib/Link.class.php Normal file
View File

@@ -0,0 +1,223 @@
<?php
/**
* XHTML link class
* Creates or prints an XHTML valid link
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @version 01-20-05
* @package Link
*
* Copyright (C) 2003 - 2005 phpScheduleIt
* License: GPL, see LICENSE
*/
class Link {
var $url;
var $text;
var $_class;
var $style;
var $text_on_over;
var $img_src;
var $img_alt;
/**
* Link Constructor
* Creates a new XHTML valid link
* @param string $url url to link to
* @param string $text text of link
* @param string $class link class
* @param string $style inline style of link (overrides class)
* @param string $text_on_over text to display in status bar onmouseover
* @param string $on_over javascript to call onmouseover
*/
function Link($url=null, $text=null, $class=null, $style=null, $text_on_over=null) {
$this->url = $url;
$this->text = $text;
$this->_class = $class;
$this->style = $style;
$this->text_on_over = addslashes($text_on_over);
}
//---------------------------------------------
// Setter functions
//---------------------------------------------
/**
* Set the url of the link
* @param string $url url to link to
*/
function setUrl($url) {
$this->url = $url;
}
/**
* Set the text of the link
* @param string $text text of link
*/
function setText($text) {
$this->text = $text;
}
/**
* Set the class of the link
* @param string $class link class
*/
function setClass($class) {
$this->_class = $class;
}
/**
* Set the inline style of the link
* @param string $style inline style of link (overrides class)
*/
function setStyle($style) {
$this->style = $style;
}
/**
* Set the text onmouseover
* @param string $text_on_over text to display in status bar onmouseover
*/
function setTextOnOver($text_on_over) {
$this->text_on_over = addslashes($text_on_over);
}
/**
* Set the image source "src" property
* @param string $img_src image source property
*/
function setImgSrc($img_src) {
$this->img_src = $img_src;
}
/**
* Set the image alt property
* @param string $img_alt image alt property
*/
function setImgAlt($img_alt) {
$this->img_alt = $img_alt;
}
//=============================================
//---------------------------------------------
// Getter functions
//---------------------------------------------
/**
* Return the url of the link
* @return string $url url to link to
*/
function getUrl() {
return $this->url;
}
/**
* Return the text of the link
* @return string $text text of link
*/
function getText() {
return $this->text;
}
/**
* Return the class of the link
* @return string $class link class
*/
function getClass() {
return $this->_class;
}
/**
* Return the inline style of the link
* @return string $style inline style of link (overrides class)
*/
function getStyle() {
return $this->style;
}
/**
* Return the text onmouseover
* @return string $text_on_over text to display in status bar onmouseover
*/
function getTextOnOver() {
return stripslashes($this->text_on_over);
}
/**
* Return the image source "src" property
* @return string
*/
function getImgSrc() {
return $img_src;
}
/**
* Return the image alt property
* @return string
*/
function getImgAlt() {
return $img_alt;
}
//=============================================
/**
* Print out a link without creating a new Link object
* @param string $url url to link to
* @param string $text text of link
* @param string $class link class
* @param string $style inline style of link (overrides class)
* @param string $text_on_over text to display in status bar onmouseover
*/
function doLink($url=null, $text=null, $class=null, $style=null, $text_on_over=null, $boldtext=null) {
echo $this->getLink($url, $text, $class, $style, $text_on_over, $boldtext);
}
/**
* Print out an image link without creating a new Link obejct
* @param string $url url to link to
* @param string $img_src image source "src" property
* @param string $alt image alt property
* @param string $text_on_over text to display in status bar onmouseover
*/
function doImageLink($url = null, $img_src = null, $alt = null, $text_on_over = null) {
echo $this->getImageLink($url, $img_src, $alt, $text_on_over);
}
/**
* Prints out the link using the class values
* @param none
* @see doLink()
*/
function printLink() {
$this->doLink($this->url, $this->text, $this->_class, $this->style, $this->text_on_over);
}
/**
* Returns the HTML for the link with given parameters
* @param string $url url to link to
* @param string $text text of link
* @param string $class link class
* @param string $style inline style of link (overrides class)
* @param string $text_on_over text to display in status bar onmouseover
* @return string of HTML for link
*/
function getLink($url=null, $text=null, $class=null, $style=null, $text_on_over=null, $boldtext=null) {
$text_on_over = (!is_null($text_on_over)) ? $text_on_over : $text; // Use passed in text on mouse over, else just use link text
//return "<a href=\"$url\" class=\"$class\" style=\"$style\" onmouseover=\"javascript: window.status='" . addslashes($text_on_over) . "'; return true;\" onmouseout=\"javascript: window.status=''; return true;\">$text</a>";
return "<a href=\"$url\" class=\"$class\" style=\"$style\" onmouseover=\"javascript: window.status='" . addslashes($text_on_over) . "'; return true;\" onmouseout=\"javascript: window.status=''; return true;\">" . ($boldtext ? "<b>$text</b>" : $text) . "</a>";
}
/**
* Returns the HTML for the link with given parameters
* @param string $url url to link to
* @param string $img_src image source "src" property
* @param string $alt image alt property
* @param string $text_on_over text to display in status bar onmouseover
*/
function getImageLink($url = null, $img_src = null, $alt = null, $text_on_over = null) {
$text_on_over = (!is_null($text_on_over)) ? $text_on_over : $alt; // Use passed in text on mouse over, else just use link text
return "<a href=\"$url\" onmouseover=\"javascript: window.status='" . addslashes($text_on_over) . "'; return true;\" onmouseout=\"javascript: window.status=''; return true;\"><img src=\"$img_src\" alt=\"$alt\" title=\"$alt\" border=\"0\"/></a>\n";
}
}
?>

97
lib/MailEngine.class.php Normal file
View File

@@ -0,0 +1,97 @@
<?php
/**
* MailEngine class
* @author Brian Wong <bwsource@users.sourceforge.net>
* @version 04-02-07
* @package MailEngine
*
* Copyright (C) 2003 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Pear::DB
*/
if ($GLOBALS['conf']['app']['safeMode']) {
ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
include_once('pear/PEAR.php');
include_once('pear/Mail/mimeDecode.php');
}
else {
include_once 'PEAR.php';
include_once('Mail/mimeDecode.php');
}
/**
* Provide all mail access/manipulation functionality
*/
class MailEngine {
var $raw; // Raw mail contents
var $struct; // The top-level MIME structure
var $recipient; // The recipient of the email
var $msg_found; // Msg found in database
var $msg_error; // Msg has MIME error
var $last_error; // PEAR Error Messages
/**
* MailEngine object constructor
* $param string The unique mail_id
* $param string The mail addr of the reader
* $return object MailEngine object
*/
function MailEngine($mail_id, $recip) {
$this->recipient = $recip;
$this->getRawContent($mail_id);
$this->msg_error = false;
if ($this->raw) {
$this->msg_found = true;
$this->struct = $this->getDecodedStruct($this->raw);
if (PEAR::isError($this->struct)) {
$this->msg_error = true;
$this->last_error = $this->struct->getMessage();
}
} else {
$this->msg_found = false;
}
return $this->struct;
}
/**
* Decode the raw contents to get the MIME structure
* $param string The complete raw message returned by get_raw_mail
* $return object Mail_mimeDecode::decode object
*/
function getDecodedStruct($contents) {
$message = new Mail_mimeDecode($contents);
$msg_struct = $message->decode( array ( 'include_bodies' => true,
'decode_bodies' => true,
'decode_headers' => true)
);
return $msg_struct;
}
/**
* Get the raw content through a DB call
* $param string The unique mail_id
* $return string The complete raw email
*/
function getRawContent($mail_id) {
$db = new DBEngine();
$this->raw = $db->get_raw_mail($mail_id, $this->recipient);
// Mark read
if (in_array($this->recipient, $_SESSION['sessionMail']) && $this->raw) {
$db->update_msgrcpt_rs($mail_id,$this->recipient,'v');
}
}
}

316
lib/MailMime.class.php Normal file
View File

@@ -0,0 +1,316 @@
<?php
/**
* MailEngine class
* @author Brian Wong <bwsource@users.sourceforge.net>
* @version 04-12-05
* @package MailEngine
*
* Copyright (C) 2003 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Pear::DB
*/
if ($GLOBALS['conf']['app']['safeMode']) {
ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
include_once('pear/Mail/mimeDecode.php');
}
else {
include_once('Mail/mimeDecode.php');
}
/**
* Include htmlfilter class
*/
include_once('lib/htmlfilter.php');
/**
* Provide all MIME functionality
*/
/**
* Get full MIME type
* $param The mime structure object
*/
function GetCtype($struct) {
$ctype_p = strtolower(trim($struct->ctype_primary));
$ctype_s = strtolower(trim($struct->ctype_secondary));
$type = $ctype_p . '/' . $ctype_s;
return $type;
}
/**
* Recursively parse MIME structure
* $param The mime structure object
*/
$filelist = array ();
$errors = array ();
function MsgParseBody($struct) {
global $filelist;
global $errors;
$ctype_p = strtolower(trim($struct->ctype_primary));
$ctype_s = strtolower(trim($struct->ctype_secondary));
switch ($ctype_p) {
case "multipart":
switch ($ctype_s) {
case "alternative":
// Handle multipart/alternative parts
$alt_entity = FindMultiAlt($struct->parts);
// Ignore if we return false NEEDS WORK
if ($alt_entity) MsgParseBody($alt_entity);
break;
case "related":
// Handle multipart/related parts
$rel_entities = FindMultiRel($struct);
foreach ($rel_entities as $ent) {
MsgParseBody($ent);
}
break;
default:
// Probably multipart/mixed here
// Recursively process nested mime entities
if ( is_array($struct->parts) || is_object($struct->parts) ) {
foreach ($struct->parts as $cur_part) {
MsgParseBody($cur_part);
}
} else {
$errors['Invalid or Corrupt MIME Detected.'] = true;
}
break;
}
break;
case "text":
// Do not display attached text types
if ($attachment = $struct->d_parameters['filename'] or
$attachment = $struct->d_parameters['name']) {
array_push($filelist, $attachment);
break;
}
switch ($ctype_s) {
// Plain text
case "plain":
MsgBodyPlainText($struct->body);
break;
// HTML text
case "html":
MsgBodyHtmlText($struct->body);
break;
// Text type we do not support
default:
$errors['Portions of text could not be displayed'] = true;
}
break;
default:
// Save the listed filename or notify the
// reader that this mail is not displayed completely
$attachment = $struct->d_parameters['filename'];
$attachment ? array_push($filelist, $attachment) : $errors['Unsupported MIME objects present'] = true;
}
}
/**
* Get the best MIME entity for multipart/alternative
* Adapted from SqurrelMail
* $param Array of MIME entities
* $return Single MIME entity
*/
function FindMultiAlt($parts) {
$alt_pref = array ('text/plain', 'text/html');
$best_view = 0;
// Bad Headers sometimes have invalid MIME....
if ( is_array($parts) || is_object($parts) ) {
foreach ($parts as $cur_part) {
$type = GetCtype($cur_part);
if ($type == 'multipart/related') {
$type = $cur_part->d_parameters['type'];
// Mozilla bug. Mozilla does not provide the parameter type.
if (!$type) $type = 'text/html';
}
$altCount = count($alt_pref);
for ($j = $best_view; $j < $altCount; ++$j) {
if (($alt_pref[$j] == $type) && ($j >= $best_view)) {
$best_view = $j;
$struct = $cur_part;
}
}
}
return $struct;
} else {
$errors['Invalid or Corrupt MIME Detected.'] = true;
}
}
/**
* Get the list of related entities for multipart/related
* Adapted from SqurrelMail
* $param multipart/alternative structure
* @return List of MIME entities
*/
function FindMultiRel($struct) {
$entities = array();
$type = $struct->d_parameters['type'];
// Mozilla bug. Mozilla does not provide the parameter type.
if (!$type) $type = 'text/html';
// Bad Headers sometimes have invalid MIME....
if ( is_array($struct->parts) || is_object($struct->parts) ) {
foreach ($struct->parts as $part) {
if (GetCtype($part) == $type || GetCtype($part) == "multipart/alternative") {
array_push($entities,$part);
}
}
} else {
$errors['Invalid or Corrupt MIME Detected.'] = true;
}
return $entities;
}
// Wrapper script for htmlfilter. Settings taken
// from SquirrelMail
function sanitizeHTML($body) {
if (isset($_COOKIE['lang']) &&
file_exists("img/".substr($_COOKIE['lang'],0,2).".blocked_img.png")) {
$secremoveimg = "img/".substr($_COOKIE['lang'],0,2).".blocked_img.png";
} else {
$secremoveimg = "img/blocked_img.png";
}
$tag_list = Array(
false,
"object",
"meta",
"html",
"head",
"base",
"link",
"frame",
"iframe",
"plaintext",
"marquee"
);
$rm_tags_with_content = Array(
"script",
"applet",
"embed",
"title",
"frameset",
"xml",
"style"
);
$self_closing_tags = Array(
"img",
"br",
"hr",
"input"
);
$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",
"/^([\'\"])\s*https*:.*([\'\"])/si",
"/^([\'\"])\s*cid*:.*([\'\"])/si"
),
Array(
"\\1$secremoveimg\\2",
"\\1$secremoveimg\\2",
"\\1$secremoveimg\\2",
"\\1$secremoveimg\\2",
"\\1$secremoveimg\\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",
"\\1#\\1"
)
),
"/^style/i" =>
Array(
Array(
"/expression/i",
"/binding/i",
"/behaviou*r/i",
"/include-source/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",
"/url\(([\'\"])\s*https*:.*([\'\"])\)/si"
),
Array(
"idiocy",
"idiocy",
"idiocy",
"idiocy",
"url(\\1#\\1)",
"url(\\1#\\1)",
"url(\\1#\\1)",
"url(\\1#\\1)",
"url(\\1#\\1)",
"\\1:url(\\2#\\3)",
"url(\\1$secremoveimg\\1)"
)
)
)
);
$add_attr_to_tag = Array(
"/^a$/i" =>
Array('target'=>'"_new"'
)
);
$trusted_html = sanitize($body,
$tag_list,
$rm_tags_with_content,
$self_closing_tags,
$force_tag_closing,
$rm_attnames,
$bad_attvals,
$add_attr_to_tag
);
return $trusted_html;
}

1541
lib/PHPMailer.class.php Normal file

File diff suppressed because it is too large Load Diff

629
lib/Pager.class.php Normal file
View File

@@ -0,0 +1,629 @@
<?php
/**
* Paging class to iterate through limited recordsets
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @version 02-02-05
* @package Pager
*
* Copyright (C) 2003 - 2005 phpScheduleIt
* License: GPL, see LICENSE
* /
/**
* To actually print out page links, call printPages() function
*
* In order for this object to work correctly, total records
* must be set in either the constructor or by calling
* setTotRecords()
*
* + Warning - The printPages() function cannot be called
* from within a form
*
* === EXAMPLE OF HOW TO USE PAGER ===
* // Initialize new Pager object with default values
* $pager = new Pager();
*
* // Get total # of pages
* $query = "SELECT COUNT(*) as num FROM table";
* $result = $db->query($query);
* $rs = $result->fetchRow();
* $num = $rs['num']; // # of records
*
* $pager->setTotRecords($num);
* $recordset_offset = $pager->getOffset();
* $limit = $pager->getLimit();
*
* // Execute Query (using $offset and $limit values) //
*
* $pager->printPages();
* ==========================================
*
*/
// Should we use the Link class?
$use_link = true;
if ($use_link) {
//include_once('Link.class.php');
$link = new Link();
}
class Pager {
// Application set variables
var $cur_page;
var $query_string;
var $tot_pages;
var $page_var;
var $limit_var;
// Application variables with user modify option
var $limit;
var $tot_records;
var $print_limit_select = true;
// User modifiable variables
var $prev_link = '&laquo;';
var $next_link = '&raquo;';
var $limits = array(10, 25, 50, 100);
var $view_pages = 3;
var $table_width = '100%';
var $table_align = 'center';
var $link_class;
var $tb_class;
var $tb_style;
var $text_class;
var $text_style;
/**
* Pager Constructor
* Sets up Pager variables and initializes values
*
* - All parameters are optional and have default values of:
* $tot_records = 0
* $limit = 25
* $page_var = "page"
* $limit_var = "limit"
*
* @param int $tot_records optional total number of records
* @param int $limit optional limit of recordset
* @param string $page_var optional name of var to use in querystring for page value
* @param string $limit_var optional name of var to use in querystring for limit value
*/
function Pager($tot_records=0, $limit=25, $page_var='page', $limit_var='limit') {
$this->tot_records = $tot_records;
$this->limit = $limit;
$this->page_var = $page_var;
$this->limit_var = $limit_var;
// Call all system setter functions
$this->initCurPage();
$this->initLimit();
$this->initTotPages();
$this->initQueryString();
}
/**
* Print out the pages as links
* Prints out a table of all the pages as links
* and a jump menu to change the number of records
* per page
*
* setCurPage() and setTotPages() must be called
* before this function can be called
*
* @param none
* @see printPrev()
* @see printLink()
* @see printPage()
* @see printNext()
* @see printTotal()
* @see startTable()
* @see startPagesCell()
* @see endPagesCell()
* @see printLimitCell()
* @see endTable()
*/
function printPages() {
$p = $this->view_pages; // How many pages to view
$cur_page = $this->cur_page; // Current page
$tot_pages = $this->tot_pages; // Total pages
// Open up the HTML table
$this->startTable();
// Open up cell for page links
$this->startPagesCell();
// Page to start printing bulk of links
$start = ($cur_page > $p) ? $cur_page - $p : 1;
// Page to end printing bulk of links
$end = ($cur_page + $p) < $tot_pages ? $cur_page + $p : $tot_pages;
// Print 'prev' link
$this->printPrev();
// Print link to first page, if not already there
if ($start != 1) {
$this->printPage(1);
}
// Print '...' if necessary (with link to center page)
if ($cur_page > $p+2) {
$this->printLink(ceil( ($start+1)/2 ), '...');
}
// Print links to pages before current page (up to first page)
// Print current page
// Print links to pages after current page (up to last page)
for ($pg = $start; $pg <= $end; $pg++) {
$this->printPage($pg);
}
// Print '...' if necessary (with link to center page)
if ( $cur_page < ($tot_pages - ($p+1)) ) {
$this->printLink(ceil( ($tot_pages+$end)/2 ), '...' );
}
// Print link to last page, if not already there
if ($end != $tot_pages) {
$this->printPage($tot_pages);
}
// Print 'next' link
$this->printNext();
// Print total records
$this->printTotal();
// Close page links cell
$this->endPagesCell();
// Print out cell with limit jump menu
if ($this->print_limit_select) { $this->printLimitCell(); }
// Close table
$this->endTable();
}
//-----------------------------------------
// Application setter functions
//-----------------------------------------
/**
* Sets current page variable
* @param none
*/
function initCurPage() {
$this->cur_page = isset($_GET[$this->page_var]) ? intval($_GET[$this->page_var]) : 1;
}
/**
* Sets the limit variable if it is passed from querystring
* @param none
*/
function initLimit() {
if (isset($_GET[$this->limit_var]))
$this->limit = intval($_GET[$this->limit_var]);
if (isset($_POST[$this->limit_var]))
$this->limit = intval($_POST[$this->limit_var]);
}
/**
* Pull page information from query string and set $query_string
*
* setLimit() must be called before this function for it to work correctly
* @param none
*/
function initQueryString() {
if (isset($_SERVER['QUERY_STRING'])) {
// Remove page from query string and convert all "&" to "&amp;"
$this->query_string = str_replace('&', '&amp;', preg_replace("/(&|&amp;)?$this->page_var=\d*/",'',$_SERVER['QUERY_STRING']));
// Insert limit into querystring, if it's not there
if ( !strstr($this->query_string, "$this->limit_var=") )
$this->query_string .= "&amp;$this->limit_var=" . $this->limit;
}
else {
$this->query_string = '';
}
}
/**
* Sets the tot_pages variable
*
* tot_records must be set and setLimit() must be called before
* this function can be called
*
* @param none
*/
function initTotPages() {
$this->tot_pages = ceil($this->tot_records/$this->limit);
}
//===========================================
//-------------------------------------------
// Output functions
//-------------------------------------------
/**
* Print out link to a page
* @param int $p page number to print
*/
function printPage($p) {
if ($p == $this->cur_page) {
echo " <b>[$p]</b> ";
}
else {
$this->printLink($p, $p);
}
}
/**
* Print 'prev' link, if necessary
* @param none
*/
function printPrev() {
$cur_page = $this->cur_page;
if ($cur_page > 1)
$this->printLink($cur_page-1, $this->prev_link);
}
/**
* Print 'next' link, if necessary
* @param none
*/
function printNext() {
$cur_page = $this->cur_page;
if ($cur_page < $this->tot_pages && $this->tot_records > 0)
$this->printLink($cur_page+1, $this->next_link);
}
/**
* Print out link to a certain page
* @param int $page page to link to
* @param string $text link text
*/
function printLink($page, $text) {
global $link;
global $use_link;
if ($use_link) {
$link->doLink(
$_SERVER['PHP_SELF'] . "?$this->page_var=$page&amp;" . $this->query_string . '"',
$text,
$this->link_class,
'',
'Page ' . $page
);
}
else {
echo ' <a href="' . $_SERVER['PHP_SELF'] . "?$this->page_var=$page&amp;" . $this->query_string . '"'
. ' class="$this->class"'
. '>'
. $text . '</a> ';
}
}
/**
* Prints out opening table tag
* @param none
*/
function startTable() {
echo "<table align=\"$this->table_align\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"$this->table_width\">\n"
. "<tr class=\"$this->text_class\" style=\"$this->text_style\">\n";
}
/**
* Begins cell containing page links
* @param none
*/
function startPagesCell() {
echo '<td>' . translate('Page') . ' ';
}
/**
* Closes cell containing page links
* @param none
*/
function endPagesCell() {
echo '</td>';
}
/**
* Prints out cell containing limit jump menu
* @param none
*/
function printLimitCell() {
$limits = $this->limits;
echo "<td align=\"right\">\n"
. "<form name=\"limit_jump\" id=\"limit_jump\" method=\"post\" action=\"" . $_SERVER['PHP_SELF'] . "?" . preg_replace("/(&|&amp;)?$this->limit_var=\d*/", "", $this->query_string) . "\" style=\"margin: 0px;\">\n"
. translate('Per page') . " <select name=\"$this->limit_var\" onchange=\"document.limit_jump.submit();\" class=\"$this->tb_class\" style=\"$this->tb_style\">\n";
for ($i = 0; $i < count($limits); $i++) {
echo '<option value="' . $limits[$i] . '"';
if ($limits[$i] == $this->limit)
echo ' selected="selected"';
echo '>' . $limits[$i] . "</option>\n";
}
echo "</select>\n"
. "</form>\n"
. "</td>\n";
}
/**
* Prints out the closing row and table HTML tags
* @param none
*/
function endTable() {
echo "</tr>\n</table>\n";
}
/**
* Prints out total number of records returned
* @param none
*/
function printTotal() {
echo '(' . $this->tot_records . ')';
}
//============================================
//--------------------------------------------
// User-Modified Setter Functions
//--------------------------------------------
/**
* Sets the total records for this recordset
*
* - Default setting is 0 (in constructor)
*
* @param int $tot total number of records
*/
function setTotRecords($tot) {
$this->tot_records = intval($tot);
// Call initTotPages again to reset paging
$this->initTotPages();
}
/**
* Sets the default recordset limit
* Note: A limit value set in the querystring
* or in a post value will override this
*
* - Default setting is 25 (in constructor)
*
* @param int $limit new limit value
*/
function setLimit($limit) {
$this->limit = intval($limit);
// Call initLimit() to reinitialzie limit
$this->initLimit();
}
/**
* Sets the text for 'prev' link
*
* - Default setting is "&laquo;"
*
* @param string $text link text
*/
function setPrevLink($text) {
$this->prev_link = trim($text);
}
/**
* Sets the text for 'next' link
*
* - Default setting is "&raquo;"
*
* @param string $text link text
*/
function setNextLink($text) {
$this->next_link = trim($text);
}
/**
* Sets the value of view_pages
* How many pages to print on either side of
* the currently viewed page number
*
* - Default setting is 3
*
* @param int $view_page how many pages to view
*/
function setViewPages($view_page) {
$this->view_pages = intval($view_page);
}
/**
* Sets the array of limits
* Pass in an array of ints to use
* for the limit pull down menu
*
* - Default setting is (10, 25, 50, 100)
*
* @param int $new_limits array of limits
*/
function setLimits($new_limits) {
$this->limits = $new_limits;
}
/**
* Sets the name of the class to be used for the links
*
* - Default setting is null
*
* @param string $link_class name of class
*/
function setLinkClass($link_class) {
$this->link_class = $link_class;
}
/**
* Sets the name of the class to be used for the pull down box
*
* - Default setting is null
*
* @param string $tb_class name of class
*/
function setTbClass($tb_class) {
$this->tb_class = $tb_class;
}
/**
* Sets the inline style of the limit jump menu
* This setting overrides the tb_class value
*
* - Default setting is null
* @param string $tb_style style of limit jump menu box
*/
function setTbStyle($tb_style) {
$this->tb_style = $tb_style;
}
/**
* Sets the name of the class to be used for the text
* ie) "Page:" and "Per page:"
* Should be used to modify all paging text font -amily, size, etc
*
* - Default setting is null
*
* @param string $text_class name of class
*/
function setTextClass($text_class) {
$this->text_class = $text_class;
}
/**
* Sets the inline style to be used for the text
* Should be used to modifiy all paging text font-family, size, etc
* This will override the text_class setting
*
* - Default setting is null
*
* @param string $text_style style to use for the text
*/
function setTextStyle($text_style) {
$this->text_style = $text_style;
}
/**
* Sets the width of the table bounding the pages/jump box
*
* - Default setting is "100%"
*
* @param string $table_width width of table
*/
function setTableWidth($table_width) {
$this->table_width = $table_width;
}
/**
* Sets the horizontial alignment of the table bounding the paging
*
* - Default setting is "center"
*
* @param string $table_align alignment value for table align
*/
function setTableAlign($table_align) {
$this->table_align = $table_align;
}
/**
* Sets the page variable name for the querystring
* @param string $page_var page variable name
*/
function setPageVar($page_var) {
$this->page_var = $page_var;
}
/**
* Sets the limit variable name for the querystring
* @param string $limit_var limit variable name
*/
function setLimitVar($limit_var) {
$this->limit_var = $limit_var;
}
/**
* Sets the print_limit_select variable to decide if we should show the limit select pulldown
* @param bool $view_limit_select if we should show the select pulldown or not
*/
function setViewLimitSelect($view_limit_select) {
$this->print_limit_select = $view_limit_select;
}
//============================================
//--------------------------------------------
// Getter methods
//--------------------------------------------
/**
* Returns the recordset offset
* @param none
* @return integer recorset offset
*/
function getOffset() {
return $this->limit * $this->cur_page - $this->limit;
}
/**
* Returns the total number of pages
* @param none
* @return integer number of pages total
*/
function getTotPages() {
return $this->tot_pages;
}
/**
* Returns the current page number
* @param none
* @return integer current page number
*/
function getPageNum() {
return $this->cur_page;
}
/**
* Returns the current recordset limit
* @param none
* @return integer recordset limit
*/
function getLimit() {
return $this->limit;
}
/**
* Returns value of previous link text
* @param none
* @return string previous link text
*/
function getPrevLink() {
return $this->prev_link;
}
/**
* Returns value of next link text
* @param none
* @return string next link text
*/
function getNextLink() {
return $this->next_link;
}
/**
* Returns the name used for the page querystring variable
* @param none
* @return string page variable name
*/
function getPageVar() {
return $this->page_var;
}
/**
* Returns the name used for the limit querystring variable
* @param none
* @return string limit variable name
*/
function getLimitVar() {
return $this->limit_var;
}
//===========================================
// End class
}
?>

362
lib/Quarantine.lib.php Normal file
View File

@@ -0,0 +1,362 @@
<?php
/**
* Quarantine lib
* @author Samuel Tran <stran2005@users.sourceforge.net>
* @author Brian Wong <bwsource@users.sourceforge.net>
* @author Nicolas Peyrussie <peyrouz@users.sourceforge.net>
* @version 04-03-07
*
* Copyright (C) 2005 - 2007 MailZu
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');
/**
* Include AmavisdEngine class
*/
include_once('lib/AmavisdEngine.class.php');
/**
* PHPMailer
*/
include_once('lib/PHPMailer.class.php');
/**
* Provide quarantine related functions
*/
/**
* Release messages function
* @param array $emailaddresses recipient email address(es)
* @param array $mail_id_array containing mail_id of messages to be released
* @result return array of messages whose release failed
*/
function releaseMessages($emailaddresses, $mail_id_array) {
/*** Array pertaining to the release of messages ***/
// This is an array of array, the key being the $mail_id
// and the value being an array containing all the messages info (time, subject, ...) and also the release status.
// The reason for this is that we want to keep the ordering of the messages selected for release.
$release_messages = array();
// This is an array of array, the key being the host
// and the value being an array containing all the release info such as secret_id (one row per message)
$hosts = array();
/*** Variables pertaining to the request of release ***/
// This array contains the messages that the logged in user wants the Admins to release
$release_req_messages = array();
// Counter for the number of release requests
$j = 0;
$nb_failure = 0;
$db = new DBEngine();
// Set autocommit to false to improve speed of 'RS' flag set up
$result = $db->db->autoCommit(false);
$db->check_for_error($result, 'PEAR DB autoCommit(false)');
// Fill the arrays
foreach ($mail_id_array as $mail_id_recip) {
// Get mail_id and recipient email address
$temp = preg_split('/_/', $mail_id_recip, 2);
$mail_id = $temp[0];
$recip_email = $temp[1];
// Check if logged in user is admin or logged in user is trying to release his own messages
if ( Auth::isMailAdmin() || in_array($recip_email, $emailaddresses) )
$result = $db->get_message($recip_email, $mail_id);
else
continue;
$rs = $result[0];
// if content type is 'B' or 'V' and the logged in user is not admin
// add message to array of release request
if ( in_array($rs['content'], array( 'B', 'V')) && ! Auth::isMailAdmin() ) {
$release_req_messages[ $j ] = array(
"mail_id" => $mail_id,
"from_addr" => $rs[ 'from_addr' ],
"subject" => $rs[ 'subject' ],
"time_num" => $rs[ 'time_num' ],
"spam_level" => $rs[ 'spam_level' ],
"content" => $rs['content']
);
// Try to update the RS flag to 'p' for pending
if ( ! $db->update_msgrcpt_rs($mail_id, $recip_email, 'p') ) {
$release_req_messages[ $j ]["status"] = "Error: " . $db->get_err();
} else {
$release_req_messages[ $j ]["status"] = "Pending";
}
$j++;
// Other cases where:
// - content type is 'B' or 'V' but the logged in user is admin, therefore allowed to release message
// - content type is 'S' or 'H'
} else {
// add message to be released to $hosts array
$release_messages[ $mail_id_recip ] = array(
"mail_id" => $mail_id,
"time" => $rs['time_num'],
"subject" => $rs['subject'],
"from_addr" => $rs['from_addr'],
"spam_level" => $rs['spam_level'],
"content" => $rs['content'],
);
$hosts[ $rs['host'] ][ $mail_id_recip ] = array(
"secret_id" => $rs['secret_id'],
"quar_type" => $rs['quar_type'],
"quar_loc" => $rs['quar_loc'],
"recip_email" => $rs['email']
);
}
}
global $conf;
// If release request needs to be sent to Admins
if ( is_array($release_req_messages) && !empty($release_req_messages)
&& $conf['app']['notifyAdmin'] )
sendMailToAdmin(translate('Request release'), $release_req_messages);
// If release needs to be done
if ( is_array($hosts) && !empty($hosts) ) {
// For each host create socket, connect and release all messages pertaining to that host
foreach ($hosts as $host => $message_info ) {
// Create new TCP/IP socket and try to connect to $host using this socket
$am = new AmavisdEngine($host);
if ( ! $am->connected )
foreach ($message_info as $mail_id_recip => $release_info) {
$release_messages[ $mail_id_recip ][ 'error_code' ] = 1;
$release_messages[ $mail_id_recip ][ 'status' ] = $am->last_error;
$nb_failure++;
}
else {
foreach ($message_info as $mail_id_recip => $release_info) {
$socket_binding_result = $am->release_message(
$release_messages[ $mail_id_recip ][ 'mail_id' ],
$release_info[ 'secret_id' ],
$release_info[ 'recip_email' ],
$release_info[ 'quar_type' ],
$release_info[ 'quar_loc' ]
);
if (preg_match('/^setreply=250/', $socket_binding_result)) {
if ( $db->update_msgrcpt_rs($release_messages[ $mail_id_recip ][ 'mail_id' ], $release_info[ 'recip_email' ], 'R') ) {
$release_messages[ $mail_id_recip ][ 'error_code' ] = "0";
CmnFns::write_log('Message Released [' . $release_messages[ $mail_id_recip ][ 'content' ] . ']: '
. $release_messages[ $mail_id_recip ][ 'mail_id' ], $_SESSION['sessionID']);
} else {
$release_messages[ $mail_id_recip ][ 'error_code' ] = 2;
$release_messages[ $mail_id_recip ][ 'status' ] = "Error: " . $db->get_err();
$nb_failure++;
}
} else {
$release_messages[ $mail_id_recip ][ 'error_code' ] = 3;
$release_messages[ $mail_id_recip ][ 'status' ] = $am->last_error;
$nb_failure++;
}
}
// Shuting down and closing socket
$am->disconnect();
}
}
}
// Commit, then set autocommit back to true
$result = $db->db->commit();
$db->check_for_error($result, 'PEAR DB commit()');
$result = $db->db->autoCommit(true);
$db->check_for_error($result, 'PEAR DB autoCommit(true)');
// Build array of messages whose release failed
$failed_array = array();
$i = 0;
if ( $nb_failure > 0 ) {
foreach ($mail_id_array as $mail_id_recip) {
if ($release_messages[ $mail_id_recip ][ 'error_code' ] != 0) {
$failed_array[ $i ] = array(
"mail_id" => $release_messages[ $mail_id_recip ][ 'mail_id' ],
"from_addr" => $release_messages[ $mail_id_recip ][ 'from_addr' ],
"subject" => $release_messages[ $mail_id_recip ][ 'subject' ],
"time_num" => $release_messages[ $mail_id_recip ][ 'time' ],
"spam_level" => $release_messages[ $mail_id_recip ][ 'spam_level' ],
"content" => $release_messages[ $mail_id_recip ][ 'content' ],
"status" => $release_messages[ $mail_id_recip ][ 'status' ]
);
CmnFns::write_log($release_messages[ $mail_id_recip ][ 'status' ], $_SESSION['sessionID']);
$i++;
}
}
}
// Return array of messages whose release failed
return $failed_array;
}
/**
* Update messages function
* @param string $content_type 'B', 'S', ...
* @param array $emailaddresses recipient email address(es)
* @param array $mail_id_array containing mail_id of messages to be deleted
* @param bool $all false (default) or true, if true all messages will be deleted
* @result return array of messages whose release failed
*/
function updateMessages($flag, $content_type, $emailaddresses, $mail_id_array, $all = false) {
$result_array = array();
$db = new DBEngine();
// Set autocommit to false to improve speed of $flag set
$result = $db->db->autoCommit(false);
$db->check_for_error($result, 'PEAR DB autoCommit(false)');
if ( $all ) {
$res = $db->get_user_messages($content_type, $emailaddresses, 'msgs.time_num', 'DESC', '', false, 0, 0, true);
for ($i = 0; is_array($res) && $i < count($res); $i++) {
$rs = $res[$i];
if ( Auth::isMailAdmin() || in_array($rs['email'], $emailaddresses) ) {
if ( ! $db->update_msgrcpt_rs($rs['mail_id'], $rs['email'], $flag ) ) {
$rs = $result[0];
$result_array[ $i ] = array(
"mail_id" => $mail_id,
"from_addr" => $rs[ 'from_addr' ],
"subject" => $rs[ 'subject' ],
"time_num" => $rs[ 'time_num' ],
"spam_level" => $rs[ 'spam_level' ],
"status" => "Error: " . $db->get_err()
);
}
} else {
continue;
}
}
} else {
$i = 0;
foreach ($mail_id_array as $mail_id_recip) {
// Get mail_id and recipient email address
$temp = preg_split('/_/', $mail_id_recip, 2);
$mail_id = $temp[0];
$recip_email = $temp[1];
// Check if logged in user is admin or logged in user is trying to delete his own messages
if ( Auth::isMailAdmin() || in_array($recip_email, $emailaddresses) ) {
$result = $db->get_message($recip_email, $mail_id);
} else {
continue;
}
if ( ! $db->update_msgrcpt_rs($mail_id, $recip_email, $flag) ) {
$rs = $result[0];
$result_array[ $i ] = array(
"mail_id" => $mail_id,
"from_addr" => $rs[ 'from_addr' ],
"subject" => $rs[ 'subject' ],
"time_num" => $rs[ 'time_num' ],
"spam_level" => $rs[ 'spam_level' ],
"status" => "Error: " . $db->get_err()
);
$i++;
}
}
}
// Commit, then set autocommit back to true
$result = $db->db->commit();
$db->check_for_error($result, 'PEAR DB commit()');
$result = $db->db->autoCommit(true);
$db->check_for_error($result, 'PEAR DB autoCommit(true)');
// Return array of messages whose release failed
return $result_array;
}
/**
* Function that sends:
* - an error report if $action = 'Release', 'Delete' or 'Delete All'
* - an request if $action = 'Request release'
* to $conf['app']['adminEmail']
* @param string $action 'Release', 'Delete', 'Delete All', 'Request release'
* @param $messages_array array containing messages info
*/
function sendMailToAdmin($myaction, $messages_array) {
global $conf;
$title = $conf['app']['title'];
$adminEmail = $conf['app']['adminEmail'];
$sub = "[" . $title . "] Notification from '" . $_SESSION['sessionID'] . "'";
$msg = "Mail notification sent by '" . $_SESSION['sessionID'] . "' <" . $_SESSION['sessionMail'][0] . ">.\r\n\r\n";
switch ( $myaction ) {
case translate('Release'):
case translate('Release/Request release'):
$msg .= translate('A problem occured when trying to release the following messages') . ":\r\n\r\n";
break;
case translate('Request release'):
$msg .= translate('Please release the following messages') . ":\r\n\r\n";
break;
case translate('Delete'):
case translate('Delete All'):
$msg .= translate('A problem occured when trying to delete the following messages') . ":\r\n\r\n";
break;
default:
CmnFns::do_error_box(translate('Unknown action type'), '');
}
for ($i = 0; is_array($messages_array) && $i < count($messages_array); $i++) {
$rs = $messages_array[$i];
$msg .= "Message #" . ($i+1) . ":\r\n";
$msg .= "\tmail_id = " . $rs['mail_id'] . "\r\n";
$msg .= "\t" . translate('From') . " = " . $rs['from_addr'] . "\r\n";
$msg .= "\t" . translate('Subject') . " = " . $rs['subject'] . "\r\n";
$msg .= "\t" . translate('Date') . " = " . CmnFns::formatDateTime($rs['time_num']) . "\r\n";
$msg .= "\t" . translate('Score') . " = " . $rs['spam_level'] . "\r\n";
$msg .= "\t" . translate('Status') . " = " . $rs['status'] . "\r\n";
$msg .= "\t" . translate('Content Type') . " = " . $rs['content'] . "\r\n\r\n";
}
// Send email
$mailer = new PHPMailer();
if ( is_array($adminEmail) ) {
foreach ($adminEmail as $email) {
$mailer->AddAddress($email, '');
}
} else {
$mailer->AddAddress($adminEmail, '');
}
$mailer->FromName = $_SESSION['sessionID'];
$mailer->From = $_SESSION['sessionMail'][0];
$mailer->Subject = $sub;
$mailer->Body = $msg;
$mailer->Send();
return true;
}
?>

1039
lib/Smtp.class.php Normal file

File diff suppressed because it is too large Load Diff

194
lib/Template.class.php Normal file
View File

@@ -0,0 +1,194 @@
<?php
/**
* This file provides output functions
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @version 10-21-04
* @package phpScheduleIt
*
* Copyright (C) 2003 - 2005 phpScheduleIt
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* Include Auth class
*/
include_once('Auth.class.php');
/**
* Provides functions for outputting template HTML
*/
class Template {
var $title;
var $link;
var $dir_path;
/**
* Set the page's title
* @param string $title title of page
* @param int $depth depth of the current page relative to phpScheduleIt root
*/
function Template($title = '', $depth = 0) {
global $conf;
$this->title = (!empty($title)) ? $title : $conf['ui']['welcome'];
$this->dir_path = str_repeat('../', $depth);
$this->link = CmnFns::getNewLink();
//Auth::Auth(); // Starts session
}
/**
* Print all XHTML headers
* This function prints the HTML header code, CSS link, and JavaScript link
*
* DOCTYPE is XHTML 1.0 Transitional
* @param none
*/
function printHTMLHeader() {
global $conf;
global $languages;
global $lang;
global $charset;
$path = $this->dir_path;
echo "<?xml version=\"1.0\" encoding=\"$charset\"?" . ">\n";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?=$languages[$lang][2]?>" lang="<?=$languages[$lang][2]?>">
<head>
<title>
<?=$this->title?>
</title>
<meta http-equiv="Content-Type" content="text/html; charset=<?=$charset?>" />
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" />
<script language="JavaScript" type="text/javascript" src="<?=$path?>functions.js"></script>
<!--<link href="<?=$path?>css.css" rel="stylesheet" type="text/css" />-->
<style type="text/css">
@import url(<?=$path?>css.css);
</style>
</head>
<body>
<?
}
/**
* Print welcome header message
* This function prints out a table welcoming
* the user. It prints links to My Control Panel,
* Log Out, Help, and Email Admin.
* If the user is the admin, an admin banner will
* show up
* @global $conf
*/
function printWelcome() {
global $conf;
// Print out logoImage if it exists
echo (!empty($conf['ui']['logoImage']))
? '<div align="left"><img src="' . $conf['ui']['logoImage'] . '" alt="logo" vspace="5" /></div>'
: '';
?>
<table width="100%" border="0" cellspacing="0" cellpadding="5" class="mainBorder">
<tr>
<td class="mainBkgrdClr">
<h4 class="welcomeBack">
<?=
translate('Welcome Back', array($_SESSION['sessionName'], 1));
// Notify if the person logged in is admin
echo (Auth::isMailAdmin() ? ' (' . translate('Administrator') . ')' : '');
?>
</h4>
<!--<p>
<? $this->link->doLink($this->dir_path . 'index.php?logout=true', translate('Log Out')) ?>
|
<? $this->link->doLink($this->dir_path . 'summary.php', translate('My Control Panel')) ?>
</p>-->
</td>
<td class="mainBkgrdClr" valign="top">
<div align="right">
<p>
<?= translate_date('header', mktime());?>
</p>
<!--<p>
<? $this->link->doLink('javascript: help();', translate('Help')) ?>
</p>-->
</div>
</td>
</tr>
</table>
<?
}
/**
* Start main HTML table
* @param none
*/
function startMain() {
?>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="0" cellpadding="10" style="border: solid #CCCCCC 1px;">
<tr>
<td bgcolor="#FAFAFA">
<?
}
/**
* End main HTML table
* @param none
*/
function endMain() {
?>
</td>
</tr>
</table>
<?
}
/**
* Print HTML footer
* This function prints out a tech email
* link and closes off HTML page
* @global $conf
*/
function printHTMLFooter() {
global $conf;
?>
<p align="center"><a href="http://www.mailzu.net"><?=$conf['app']['title']?> v<?=$conf['app']['version']?></a></p>
</body>
</html>
<?
}
/**
* Sets the link class variable to reference a new Link object
* @param none
*/
function set_link() {
$this->link = CmnFns::getNewLink();
}
/**
* Returns the link object
* @param none
* @return link object for this class
*/
function get_link() {
return $this->link;
}
/**
* Sets a new title for the template page
* @param string $title title of page
*/
function set_title($title) {
$this->title = $title;
}
}
?>

1021
lib/htmlfilter.php Normal file

File diff suppressed because it is too large Load Diff

0
lib/index.html Normal file
View File

1489
lib/pear/DB.php Normal file

File diff suppressed because it is too large Load Diff

2257
lib/pear/DB/common.php Normal file

File diff suppressed because it is too large Load Diff

510
lib/pear/DB/dbase.php Normal file
View File

@@ -0,0 +1,510 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's dbase extension
* for interacting with dBase databases
*
* 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 Database
* @package DB
* @author Tomas V.V. Cox <cox@idecnet.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: dbase.php,v 1.42 2007/01/11 07:43:09 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's dbase extension
* for interacting with dBase databases
*
* These methods overload the ones declared in DB_common.
*
* @category Database
* @package DB
* @author Tomas V.V. Cox <cox@idecnet.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_dbase extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'dbase';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'dbase';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => false,
'new_link' => false,
'numrows' => true,
'pconnect' => false,
'prepare' => false,
'ssl' => false,
'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* A means of emulating result resources
* @var array
*/
var $res_row = array();
/**
* The quantity of results so far
*
* For emulating result resources.
*
* @var integer
*/
var $result = 0;
/**
* Maps dbase data type id's to human readable strings
*
* The human readable values are based on the output of PHP's
* dbase_get_header_info() function.
*
* @var array
* @since Property available since Release 1.7.0
*/
var $types = array(
'C' => 'character',
'D' => 'date',
'L' => 'boolean',
'M' => 'memo',
'N' => 'number',
);
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_dbase()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database and create it if it doesn't exist
*
* Don't call this method directly. Use DB::connect() instead.
*
* PEAR DB's dbase driver supports the following extra DSN options:
* + mode An integer specifying the read/write mode to use
* (0 = read only, 1 = write only, 2 = read/write).
* Available since PEAR DB 1.7.0.
* + fields An array of arrays that PHP's dbase_create() function needs
* to create a new database. This information is used if the
* dBase file specified in the "database" segment of the DSN
* does not exist. For more info, see the PHP manual's
* {@link http://php.net/dbase_create dbase_create()} page.
* Available since PEAR DB 1.7.0.
*
* Example of how to connect and establish a new dBase file if necessary:
* <code>
* require_once 'DB.php';
*
* $dsn = array(
* 'phptype' => 'dbase',
* 'database' => '/path/and/name/of/dbase/file',
* 'mode' => 2,
* 'fields' => array(
* array('a', 'N', 5, 0),
* array('b', 'C', 40),
* array('c', 'C', 255),
* array('d', 'C', 20),
* ),
* );
* $options = array(
* 'debug' => 2,
* 'portability' => DB_PORTABILITY_ALL,
* );
*
* $db =& DB::connect($dsn, $options);
* if (PEAR::isError($db)) {
* die($db->getMessage());
* }
* </code>
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('dbase')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
/*
* Turn track_errors on for entire script since $php_errormsg
* is the only way to find errors from the dbase extension.
*/
@ini_set('track_errors', 1);
$php_errormsg = '';
if (!file_exists($dsn['database'])) {
$this->dsn['mode'] = 2;
if (empty($dsn['fields']) || !is_array($dsn['fields'])) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
'the dbase file does not exist and '
. 'it could not be created because '
. 'the "fields" element of the DSN '
. 'is not properly set');
}
$this->connection = @dbase_create($dsn['database'],
$dsn['fields']);
if (!$this->connection) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
'the dbase file does not exist and '
. 'the attempt to create it failed: '
. $php_errormsg);
}
} else {
if (!isset($this->dsn['mode'])) {
$this->dsn['mode'] = 0;
}
$this->connection = @dbase_open($dsn['database'],
$this->dsn['mode']);
if (!$this->connection) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$php_errormsg);
}
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @dbase_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ &query()
function &query($query = null)
{
// emulate result resources
$this->res_row[(int)$this->result] = 0;
$tmp =& new DB_result($this, $this->result++);
return $tmp;
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum === null) {
$rownum = $this->res_row[(int)$result]++;
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @dbase_get_record_with_names($this->connection, $rownum);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @dbase_get_record($this->connection, $rownum);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set.
*
* This method is a no-op for dbase, as there aren't result resources in
* the same sense as most other database backends.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return true;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($foo)
{
return @dbase_numfields($this->connection);
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($foo)
{
return @dbase_numrecords($this->connection);
}
// }}}
// {{{ quoteBoolean()
/**
* Formats a boolean value for use within a query in a locale-independent
* manner.
*
* @param boolean the boolean value to be quoted.
* @return string the quoted string.
* @see DB_common::quoteSmart()
* @since Method available since release 1.7.8.
*/
function quoteBoolean($boolean) {
return $boolean ? 'T' : 'F';
}
// }}}
// {{{ tableInfo()
/**
* Returns information about the current database
*
* @param mixed $result THIS IS UNUSED IN DBASE. The current database
* is examined regardless of what is provided here.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.7.0
*/
function tableInfo($result = null, $mode = null)
{
if (function_exists('dbase_get_header_info')) {
$id = @dbase_get_header_info($this->connection);
if (!$id && $php_errormsg) {
return $this->raiseError(DB_ERROR,
null, null, null,
$php_errormsg);
}
} else {
/*
* This segment for PHP 4 is loosely based on code by
* Hadi Rusiah <deegos@yahoo.com> in the comments on
* the dBase reference page in the PHP manual.
*/
$db = @fopen($this->dsn['database'], 'r');
if (!$db) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$php_errormsg);
}
$id = array();
$i = 0;
$line = fread($db, 32);
while (!feof($db)) {
$line = fread($db, 32);
if (substr($line, 0, 1) == chr(13)) {
break;
} else {
$pos = strpos(substr($line, 0, 10), chr(0));
$pos = ($pos == 0 ? 10 : $pos);
$id[$i] = array(
'name' => substr($line, 0, $pos),
'type' => $this->types[substr($line, 11, 1)],
'length' => ord(substr($line, 16, 1)),
'precision' => ord(substr($line, 17, 1)),
);
}
$i++;
}
fclose($db);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$res = array();
$count = count($id);
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $this->dsn['database'],
'name' => $case_func($id[$i]['name']),
'type' => $id[$i]['type'],
'len' => $id[$i]['length'],
'flags' => ''
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
return $res;
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

769
lib/pear/DB/fbsql.php Normal file
View File

@@ -0,0 +1,769 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's fbsql extension
* for interacting with FrontBase databases
*
* 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 Database
* @package DB
* @author Frank M. Kromann <frank@frontbase.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: fbsql.php,v 1.87 2007/03/28 08:02:35 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's fbsql extension
* for interacting with FrontBase databases
*
* These methods overload the ones declared in DB_common.
*
* @category Database
* @package DB
* @author Frank M. Kromann <frank@frontbase.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
* @since Class functional since Release 1.7.0
*/
class DB_fbsql extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'fbsql';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'fbsql';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'alter',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
22 => DB_ERROR_SYNTAX,
85 => DB_ERROR_ALREADY_EXISTS,
108 => DB_ERROR_SYNTAX,
116 => DB_ERROR_NOSUCHTABLE,
124 => DB_ERROR_VALUE_COUNT_ON_ROW,
215 => DB_ERROR_NOSUCHFIELD,
217 => DB_ERROR_INVALID_NUMBER,
226 => DB_ERROR_NOSUCHFIELD,
231 => DB_ERROR_INVALID,
239 => DB_ERROR_TRUNCATED,
251 => DB_ERROR_SYNTAX,
266 => DB_ERROR_NOT_FOUND,
357 => DB_ERROR_CONSTRAINT_NOT_NULL,
358 => DB_ERROR_CONSTRAINT,
360 => DB_ERROR_CONSTRAINT,
361 => DB_ERROR_CONSTRAINT,
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_fbsql()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('fbsql')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
$params = array(
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
$dsn['username'] ? $dsn['username'] : null,
$dsn['password'] ? $dsn['password'] : null,
);
$connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
$ini = ini_get('track_errors');
$php_errormsg = '';
if ($ini) {
$this->connection = @call_user_func_array($connect_function,
$params);
} else {
@ini_set('track_errors', 1);
$this->connection = @call_user_func_array($connect_function,
$params);
@ini_set('track_errors', $ini);
}
if (!$this->connection) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$php_errormsg);
}
if ($dsn['database']) {
if (!@fbsql_select_db($dsn['database'], $this->connection)) {
return $this->fbsqlRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @fbsql_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$this->last_query = $query;
$query = $this->modifyQuery($query);
$result = @fbsql_query("$query;", $this->connection);
if (!$result) {
return $this->fbsqlRaiseError();
}
// Determine which queries that should return data, and which
// should return an error code only.
if ($this->_checkManip($query)) {
return DB_OK;
}
return $result;
}
// }}}
// {{{ nextResult()
/**
* Move the internal fbsql result pointer to the next available result
*
* @param a valid fbsql result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return @fbsql_next_result($result);
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum !== null) {
if (!@fbsql_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @fbsql_fetch_array($result, FBSQL_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @fbsql_fetch_row($result);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? fbsql_free_result($result) : false;
}
// }}}
// {{{ autoCommit()
/**
* Enables or disables automatic commits
*
* @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
function autoCommit($onoff=false)
{
if ($onoff) {
$this->query("SET COMMIT TRUE");
} else {
$this->query("SET COMMIT FALSE");
}
}
// }}}
// {{{ commit()
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
@fbsql_commit($this->connection);
}
// }}}
// {{{ rollback()
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
@fbsql_rollback($this->connection);
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @fbsql_num_fields($result);
if (!$cols) {
return $this->fbsqlRaiseError();
}
return $cols;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$rows = @fbsql_num_rows($result);
if ($rows === null) {
return $this->fbsqlRaiseError();
}
return $rows;
}
// }}}
// {{{ affectedRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if ($this->_last_query_manip) {
$result = @fbsql_affected_rows($this->connection);
} else {
$result = 0;
}
return $result;
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_fbsql::createSequence(), DB_fbsql::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
do {
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query('SELECT UNIQUE FROM ' . $seqname);
$this->popErrorHandling();
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $result;
}
} else {
$repeat = 0;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->fbsqlRaiseError();
}
$result->fetchInto($tmp, DB_FETCHMODE_ORDERED);
return $tmp[0];
}
/**
* Creates a new sequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_fbsql::nextID(), DB_fbsql::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
. ' (id INTEGER NOT NULL,'
. ' PRIMARY KEY(id))');
if ($res) {
$res = $this->query('SET UNIQUE = 0 FOR ' . $seqname);
}
return $res;
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_fbsql::nextID(), DB_fbsql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)
. ' RESTRICT');
}
// }}}
// {{{ modifyLimitQuery()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* @param string $query the query to modify
* @param int $from the row to start to fetching (0 = the first row)
* @param int $count the numbers of rows to fetch
* @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
* parameters or 1 placeholder per array element.
*
* @return string the query string with LIMIT clauses added
*
* @access protected
*/
function modifyLimitQuery($query, $from, $count, $params = array())
{
if (DB::isManip($query) || $this->_next_query_manip) {
return preg_replace('/^([\s(])*SELECT/i',
"\\1SELECT TOP($count)", $query);
} else {
return preg_replace('/([\s(])*SELECT/i',
"\\1SELECT TOP($from, $count)", $query);
}
}
// }}}
// {{{ quoteBoolean()
/**
* Formats a boolean value for use within a query in a locale-independent
* manner.
*
* @param boolean the boolean value to be quoted.
* @return string the quoted string.
* @see DB_common::quoteSmart()
* @since Method available since release 1.7.8.
*/
function quoteBoolean($boolean) {
return $boolean ? 'TRUE' : 'FALSE';
}
// }}}
// {{{ quoteFloat()
/**
* Formats a float value for use within a query in a locale-independent
* manner.
*
* @param float the float value to be quoted.
* @return string the quoted string.
* @see DB_common::quoteSmart()
* @since Method available since release 1.7.8.
*/
function quoteFloat($float) {
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
// }}}
// {{{ fbsqlRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_fbsql::errorNative(), DB_common::errorCode()
*/
function fbsqlRaiseError($errno = null)
{
if ($errno === null) {
$errno = $this->errorCode(fbsql_errno($this->connection));
}
return $this->raiseError($errno, null, null, null,
@fbsql_error($this->connection));
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code
*/
function errorNative()
{
return @fbsql_errno($this->connection);
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @fbsql_list_fields($this->dsn['database'],
$result, $this->connection);
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = @fbsql_num_fields($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $case_func(@fbsql_field_table($id, $i)),
'name' => $case_func(@fbsql_field_name($id, $i)),
'type' => @fbsql_field_type($id, $i),
'len' => @fbsql_field_len($id, $i),
'flags' => @fbsql_field_flags($id, $i),
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
// free the result only if we were called on a table
if ($got_string) {
@fbsql_free_result($id);
}
return $res;
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'tables':
return 'SELECT "table_name" FROM information_schema.tables'
. ' t0, information_schema.schemata t1'
. ' WHERE t0.schema_pk=t1.schema_pk AND'
. ' "table_type" = \'BASE TABLE\''
. ' AND "schema_name" = current_schema';
case 'views':
return 'SELECT "table_name" FROM information_schema.tables'
. ' t0, information_schema.schemata t1'
. ' WHERE t0.schema_pk=t1.schema_pk AND'
. ' "table_type" = \'VIEW\''
. ' AND "schema_name" = current_schema';
case 'users':
return 'SELECT "user_name" from information_schema.users';
case 'functions':
return 'SELECT "routine_name" FROM'
. ' information_schema.psm_routines'
. ' t0, information_schema.schemata t1'
. ' WHERE t0.schema_pk=t1.schema_pk'
. ' AND "routine_kind"=\'FUNCTION\''
. ' AND "schema_name" = current_schema';
case 'procedures':
return 'SELECT "routine_name" FROM'
. ' information_schema.psm_routines'
. ' t0, information_schema.schemata t1'
. ' WHERE t0.schema_pk=t1.schema_pk'
. ' AND "routine_kind"=\'PROCEDURE\''
. ' AND "schema_name" = current_schema';
default:
return null;
}
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

1082
lib/pear/DB/ibase.php Normal file

File diff suppressed because it is too large Load Diff

683
lib/pear/DB/ifx.php Normal file
View File

@@ -0,0 +1,683 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's ifx extension
* for interacting with Informix databases
*
* 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 Database
* @package DB
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: ifx.php,v 1.74 2007/01/12 03:11:17 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's ifx extension
* for interacting with Informix databases
*
* These methods overload the ones declared in DB_common.
*
* More info on Informix errors can be found at:
* http://www.informix.com/answers/english/ierrors.htm
*
* TODO:
* - set needed env Informix vars on connect
* - implement native prepare/execute
*
* @category Database
* @package DB
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_ifx extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'ifx';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'ifx';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'emulate',
'new_link' => false,
'numrows' => 'emulate',
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
'-201' => DB_ERROR_SYNTAX,
'-206' => DB_ERROR_NOSUCHTABLE,
'-217' => DB_ERROR_NOSUCHFIELD,
'-236' => DB_ERROR_VALUE_COUNT_ON_ROW,
'-239' => DB_ERROR_CONSTRAINT,
'-253' => DB_ERROR_SYNTAX,
'-268' => DB_ERROR_CONSTRAINT,
'-292' => DB_ERROR_CONSTRAINT_NOT_NULL,
'-310' => DB_ERROR_ALREADY_EXISTS,
'-316' => DB_ERROR_ALREADY_EXISTS,
'-319' => DB_ERROR_NOT_FOUND,
'-329' => DB_ERROR_NODBSELECTED,
'-346' => DB_ERROR_CONSTRAINT,
'-386' => DB_ERROR_CONSTRAINT_NOT_NULL,
'-391' => DB_ERROR_CONSTRAINT_NOT_NULL,
'-554' => DB_ERROR_SYNTAX,
'-691' => DB_ERROR_CONSTRAINT,
'-692' => DB_ERROR_CONSTRAINT,
'-703' => DB_ERROR_CONSTRAINT_NOT_NULL,
'-1202' => DB_ERROR_DIVZERO,
'-1204' => DB_ERROR_INVALID_DATE,
'-1205' => DB_ERROR_INVALID_DATE,
'-1206' => DB_ERROR_INVALID_DATE,
'-1209' => DB_ERROR_INVALID_DATE,
'-1210' => DB_ERROR_INVALID_DATE,
'-1212' => DB_ERROR_INVALID_DATE,
'-1213' => DB_ERROR_INVALID_NUMBER,
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* Should data manipulation queries be committed automatically?
* @var bool
* @access private
*/
var $autocommit = true;
/**
* The quantity of transactions begun
*
* {@internal While this is private, it can't actually be designated
* private in PHP 5 because it is directly accessed in the test suite.}}
*
* @var integer
* @access private
*/
var $transaction_opcount = 0;
/**
* The number of rows affected by a data manipulation query
* @var integer
* @access private
*/
var $affected = 0;
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_ifx()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('informix') &&
!PEAR::loadExtension('Informix'))
{
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
$dbhost = $dsn['hostspec'] ? '@' . $dsn['hostspec'] : '';
$dbname = $dsn['database'] ? $dsn['database'] . $dbhost : '';
$user = $dsn['username'] ? $dsn['username'] : '';
$pw = $dsn['password'] ? $dsn['password'] : '';
$connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect';
$this->connection = @$connect_function($dbname, $user, $pw);
if (!is_resource($this->connection)) {
return $this->ifxRaiseError(DB_ERROR_CONNECT_FAILED);
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @ifx_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$ismanip = $this->_checkManip($query);
$this->last_query = $query;
$this->affected = null;
if (preg_match('/(SELECT|EXECUTE)/i', $query)) { //TESTME: Use !DB::isManip()?
// the scroll is needed for fetching absolute row numbers
// in a select query result
$result = @ifx_query($query, $this->connection, IFX_SCROLL);
} else {
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @ifx_query('BEGIN WORK', $this->connection);
if (!$result) {
return $this->ifxRaiseError();
}
}
$this->transaction_opcount++;
}
$result = @ifx_query($query, $this->connection);
}
if (!$result) {
return $this->ifxRaiseError();
}
$this->affected = @ifx_affected_rows($result);
// Determine which queries should return data, and which
// should return an error code only.
if (preg_match('/(SELECT|EXECUTE)/i', $query)) {
return $result;
}
// XXX Testme: free results inside a transaction
// may cause to stop it and commit the work?
// Result has to be freed even with a insert or update
@ifx_free_result($result);
return DB_OK;
}
// }}}
// {{{ nextResult()
/**
* Move the internal ifx result pointer to the next available result
*
* @param a valid fbsql result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return false;
}
// }}}
// {{{ affectedRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if ($this->_last_query_manip) {
return $this->affected;
} else {
return 0;
}
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if (($rownum !== null) && ($rownum < 0)) {
return null;
}
if ($rownum === null) {
/*
* Even though fetch_row() should return the next row if
* $rownum is null, it doesn't in all cases. Bug 598.
*/
$rownum = 'NEXT';
} else {
// Index starts at row 1, unlike most DBMS's starting at 0.
$rownum++;
}
if (!$arr = @ifx_fetch_row($result, $rownum)) {
return null;
}
if ($fetchmode !== DB_FETCHMODE_ASSOC) {
$i=0;
$order = array();
foreach ($arr as $val) {
$order[$i++] = $val;
}
$arr = $order;
} elseif ($fetchmode == DB_FETCHMODE_ASSOC &&
$this->options['portability'] & DB_PORTABILITY_LOWERCASE)
{
$arr = array_change_key_case($arr, CASE_LOWER);
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
if (!$cols = @ifx_num_fields($result)) {
return $this->ifxRaiseError();
}
return $cols;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? ifx_free_result($result) : false;
}
// }}}
// {{{ autoCommit()
/**
* Enables or disables automatic commits
*
* @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
function autoCommit($onoff = true)
{
// XXX if $this->transaction_opcount > 0, we should probably
// issue a warning here.
$this->autocommit = $onoff ? true : false;
return DB_OK;
}
// }}}
// {{{ commit()
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
if ($this->transaction_opcount > 0) {
$result = @ifx_query('COMMIT WORK', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->ifxRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ rollback()
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
if ($this->transaction_opcount > 0) {
$result = @ifx_query('ROLLBACK WORK', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->ifxRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ ifxRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_ifx::errorNative(), DB_ifx::errorCode()
*/
function ifxRaiseError($errno = null)
{
if ($errno === null) {
$errno = $this->errorCode(ifx_error());
}
return $this->raiseError($errno, null, null, null,
$this->errorNative());
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error code and message produced by the last query
*
* @return string the DBMS' error code and message
*/
function errorNative()
{
return @ifx_error() . ' ' . @ifx_errormsg();
}
// }}}
// {{{ errorCode()
/**
* Maps native error codes to DB's portable ones.
*
* Requires that the DB implementation's constructor fills
* in the <var>$errorcode_map</var> property.
*
* @param string $nativecode error code returned by the database
* @return int a portable DB error code, or DB_ERROR if this DB
* implementation has no mapping for the given error code.
*/
function errorCode($nativecode)
{
if (ereg('SQLCODE=(.*)]', $nativecode, $match)) {
$code = $match[1];
if (isset($this->errorcode_map[$code])) {
return $this->errorcode_map[$code];
}
}
return DB_ERROR;
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* NOTE: only supports 'table' if <var>$result</var> is a table name.
*
* If analyzing a query result and the result has duplicate field names,
* an error will be raised saying
* <samp>can't distinguish duplicate field names</samp>.
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.6.0
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @ifx_query("SELECT * FROM $result WHERE 1=0",
$this->connection);
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA);
}
$flds = @ifx_fieldproperties($id);
$count = @ifx_num_fields($id);
if (count($flds) != $count) {
return $this->raiseError("can't distinguish duplicate field names");
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$i = 0;
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
foreach ($flds as $key => $value) {
$props = explode(';', $value);
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
'name' => $case_func($key),
'type' => $props[0],
'len' => $props[1],
'flags' => $props[4] == 'N' ? 'not_null' : '',
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
$i++;
}
// free the result only if we were called on a table
if ($got_string) {
@ifx_free_result($id);
}
return $res;
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'tables':
return 'SELECT tabname FROM systables WHERE tabid >= 100';
default:
return null;
}
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

831
lib/pear/DB/msql.php Normal file
View File

@@ -0,0 +1,831 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's msql extension
* for interacting with Mini SQL databases
*
* PHP's mSQL extension did weird things with NULL values prior to PHP
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
* those versions.
*
* 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 Database
* @package DB
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: msql.php,v 1.62 2007/01/12 03:11:17 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's msql extension
* for interacting with Mini SQL databases
*
* These methods overload the ones declared in DB_common.
*
* PHP's mSQL extension did weird things with NULL values prior to PHP
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
* those versions.
*
* @category Database
* @package DB
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
* @since Class not functional until Release 1.7.0
*/
class DB_msql extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'msql';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'msql';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'emulate',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* The query result resource created by PHP
*
* Used to make affectedRows() work. Only contains the result for
* data manipulation queries. Contains false for other queries.
*
* @var resource
* @access private
*/
var $_result;
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_msql()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* Example of how to connect:
* <code>
* require_once 'DB.php';
*
* // $dsn = 'msql://hostname/dbname'; // use a TCP connection
* $dsn = 'msql:///dbname'; // use a socket
* $options = array(
* 'portability' => DB_PORTABILITY_ALL,
* );
*
* $db =& DB::connect($dsn, $options);
* if (PEAR::isError($db)) {
* die($db->getMessage());
* }
* </code>
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('msql')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
$params = array();
if ($dsn['hostspec']) {
$params[] = $dsn['port']
? $dsn['hostspec'] . ',' . $dsn['port']
: $dsn['hostspec'];
}
$connect_function = $persistent ? 'msql_pconnect' : 'msql_connect';
$ini = ini_get('track_errors');
$php_errormsg = '';
if ($ini) {
$this->connection = @call_user_func_array($connect_function,
$params);
} else {
@ini_set('track_errors', 1);
$this->connection = @call_user_func_array($connect_function,
$params);
@ini_set('track_errors', $ini);
}
if (!$this->connection) {
if (($err = @msql_error()) != '') {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$err);
} else {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$php_errormsg);
}
}
if (!@msql_select_db($dsn['database'], $this->connection)) {
return $this->msqlRaiseError();
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @msql_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$this->last_query = $query;
$query = $this->modifyQuery($query);
$result = @msql_query($query, $this->connection);
if (!$result) {
return $this->msqlRaiseError();
}
// Determine which queries that should return data, and which
// should return an error code only.
if ($this->_checkManip($query)) {
$this->_result = $result;
return DB_OK;
} else {
$this->_result = false;
return $result;
}
}
// }}}
// {{{ nextResult()
/**
* Move the internal msql result pointer to the next available result
*
* @param a valid fbsql result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return false;
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* PHP's mSQL extension did weird things with NULL values prior to PHP
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
* those versions.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum !== null) {
if (!@msql_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @msql_fetch_array($result, MSQL_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @msql_fetch_row($result);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? msql_free_result($result) : false;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @msql_num_fields($result);
if (!$cols) {
return $this->msqlRaiseError();
}
return $cols;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$rows = @msql_num_rows($result);
if ($rows === false) {
return $this->msqlRaiseError();
}
return $rows;
}
// }}}
// {{{ affected()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if (!$this->_result) {
return 0;
}
return msql_affected_rows($this->_result);
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_msql::createSequence(), DB_msql::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
$repeat = false;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result =& $this->query("SELECT _seq FROM ${seqname}");
$this->popErrorHandling();
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = true;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->createSequence($seq_name);
$this->popErrorHandling();
if (DB::isError($result)) {
return $this->raiseError($result);
}
} else {
$repeat = false;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
$result->free();
return $arr[0];
}
// }}}
// {{{ createSequence()
/**
* Creates a new sequence
*
* Also creates a new table to associate the sequence with. Uses
* a separate table to ensure portability with other drivers.
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_msql::nextID(), DB_msql::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
. ' (id INTEGER NOT NULL)');
if (DB::isError($res)) {
return $res;
}
$res = $this->query("CREATE SEQUENCE ON ${seqname}");
return $res;
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_msql::nextID(), DB_msql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
// }}}
// {{{ quoteIdentifier()
/**
* mSQL does not support delimited identifiers
*
* @param string $str the identifier name to be quoted
*
* @return object a DB_Error object
*
* @see DB_common::quoteIdentifier()
* @since Method available since Release 1.7.0
*/
function quoteIdentifier($str)
{
return $this->raiseError(DB_ERROR_UNSUPPORTED);
}
// }}}
// {{{ quoteFloat()
/**
* Formats a float value for use within a query in a locale-independent
* manner.
*
* @param float the float value to be quoted.
* @return string the quoted string.
* @see DB_common::quoteSmart()
* @since Method available since release 1.7.8.
*/
function quoteFloat($float) {
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
// }}}
// {{{ escapeSimple()
/**
* Escapes a string according to the current DBMS's standards
*
* @param string $str the string to be escaped
*
* @return string the escaped string
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.7.0
*/
function escapeSimple($str)
{
return addslashes($str);
}
// }}}
// {{{ msqlRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_msql::errorNative(), DB_msql::errorCode()
*/
function msqlRaiseError($errno = null)
{
$native = $this->errorNative();
if ($errno === null) {
$errno = $this->errorCode($native);
}
return $this->raiseError($errno, null, null, null, $native);
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error message produced by the last query
*
* @return string the DBMS' error message
*/
function errorNative()
{
return @msql_error();
}
// }}}
// {{{ errorCode()
/**
* Determines PEAR::DB error code from the database's text error message
*
* @param string $errormsg the error message returned from the database
*
* @return integer the error number from a DB_ERROR* constant
*/
function errorCode($errormsg)
{
static $error_regexps;
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
// this hack to work around it, per bug #9599.
$errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg);
if (!isset($error_regexps)) {
$error_regexps = array(
'/^Access to database denied/i'
=> DB_ERROR_ACCESS_VIOLATION,
'/^Bad index name/i'
=> DB_ERROR_ALREADY_EXISTS,
'/^Bad order field/i'
=> DB_ERROR_SYNTAX,
'/^Bad type for comparison/i'
=> DB_ERROR_SYNTAX,
'/^Can\'t perform LIKE on/i'
=> DB_ERROR_SYNTAX,
'/^Can\'t use TEXT fields in LIKE comparison/i'
=> DB_ERROR_SYNTAX,
'/^Couldn\'t create temporary table/i'
=> DB_ERROR_CANNOT_CREATE,
'/^Error creating table file/i'
=> DB_ERROR_CANNOT_CREATE,
'/^Field .* cannot be null$/i'
=> DB_ERROR_CONSTRAINT_NOT_NULL,
'/^Index (field|condition) .* cannot be null$/i'
=> DB_ERROR_SYNTAX,
'/^Invalid date format/i'
=> DB_ERROR_INVALID_DATE,
'/^Invalid time format/i'
=> DB_ERROR_INVALID,
'/^Literal value for .* is wrong type$/i'
=> DB_ERROR_INVALID_NUMBER,
'/^No Database Selected/i'
=> DB_ERROR_NODBSELECTED,
'/^No value specified for field/i'
=> DB_ERROR_VALUE_COUNT_ON_ROW,
'/^Non unique value for unique index/i'
=> DB_ERROR_CONSTRAINT,
'/^Out of memory for temporary table/i'
=> DB_ERROR_CANNOT_CREATE,
'/^Permission denied/i'
=> DB_ERROR_ACCESS_VIOLATION,
'/^Reference to un-selected table/i'
=> DB_ERROR_SYNTAX,
'/^syntax error/i'
=> DB_ERROR_SYNTAX,
'/^Table .* exists$/i'
=> DB_ERROR_ALREADY_EXISTS,
'/^Unknown database/i'
=> DB_ERROR_NOSUCHDB,
'/^Unknown field/i'
=> DB_ERROR_NOSUCHFIELD,
'/^Unknown (index|system variable)/i'
=> DB_ERROR_NOT_FOUND,
'/^Unknown table/i'
=> DB_ERROR_NOSUCHTABLE,
'/^Unqualified field/i'
=> DB_ERROR_SYNTAX,
);
}
foreach ($error_regexps as $regexp => $code) {
if (preg_match($regexp, $errormsg)) {
return $code;
}
}
return DB_ERROR;
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::setOption()
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @msql_query("SELECT * FROM $result",
$this->connection);
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = @msql_num_fields($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$tmp = @msql_fetch_field($id);
$flags = '';
if ($tmp->not_null) {
$flags .= 'not_null ';
}
if ($tmp->unique) {
$flags .= 'unique_key ';
}
$flags = trim($flags);
$res[$i] = array(
'table' => $case_func($tmp->table),
'name' => $case_func($tmp->name),
'type' => $tmp->type,
'len' => msql_field_len($id, $i),
'flags' => $flags,
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
// free the result only if we were called on a table
if ($got_string) {
@msql_free_result($id);
}
return $res;
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtain a list of a given type of objects
*
* @param string $type the kind of objects you want to retrieve
*
* @return array the array containing the list of objects requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'databases':
$id = @msql_list_dbs($this->connection);
break;
case 'tables':
$id = @msql_list_tables($this->dsn['database'],
$this->connection);
break;
default:
return null;
}
if (!$id) {
return $this->msqlRaiseError();
}
$out = array();
while ($row = @msql_fetch_row($id)) {
$out[] = $row[0];
}
return $out;
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

963
lib/pear/DB/mssql.php Normal file
View File

@@ -0,0 +1,963 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's mssql extension
* for interacting with Microsoft SQL Server databases
*
* 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 Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: mssql.php,v 1.90 2007/01/12 05:16:22 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's mssql extension
* for interacting with Microsoft SQL Server databases
*
* These methods overload the ones declared in DB_common.
*
* DB's mssql driver is only for Microsfoft SQL Server databases.
*
* If you're connecting to a Sybase database, you MUST specify "sybase"
* as the "phptype" in the DSN.
*
* This class only works correctly if you have compiled PHP using
* --with-mssql=[dir_to_FreeTDS].
*
* @category Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_mssql extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'mssql';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'mssql';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'emulate',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
// XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
var $errorcode_map = array(
102 => DB_ERROR_SYNTAX,
110 => DB_ERROR_VALUE_COUNT_ON_ROW,
155 => DB_ERROR_NOSUCHFIELD,
156 => DB_ERROR_SYNTAX,
170 => DB_ERROR_SYNTAX,
207 => DB_ERROR_NOSUCHFIELD,
208 => DB_ERROR_NOSUCHTABLE,
245 => DB_ERROR_INVALID_NUMBER,
319 => DB_ERROR_SYNTAX,
321 => DB_ERROR_NOSUCHFIELD,
325 => DB_ERROR_SYNTAX,
336 => DB_ERROR_SYNTAX,
515 => DB_ERROR_CONSTRAINT_NOT_NULL,
547 => DB_ERROR_CONSTRAINT,
1018 => DB_ERROR_SYNTAX,
1035 => DB_ERROR_SYNTAX,
1913 => DB_ERROR_ALREADY_EXISTS,
2209 => DB_ERROR_SYNTAX,
2223 => DB_ERROR_SYNTAX,
2248 => DB_ERROR_SYNTAX,
2256 => DB_ERROR_SYNTAX,
2257 => DB_ERROR_SYNTAX,
2627 => DB_ERROR_CONSTRAINT,
2714 => DB_ERROR_ALREADY_EXISTS,
3607 => DB_ERROR_DIVZERO,
3701 => DB_ERROR_NOSUCHTABLE,
7630 => DB_ERROR_SYNTAX,
8134 => DB_ERROR_DIVZERO,
9303 => DB_ERROR_SYNTAX,
9317 => DB_ERROR_SYNTAX,
9318 => DB_ERROR_SYNTAX,
9331 => DB_ERROR_SYNTAX,
9332 => DB_ERROR_SYNTAX,
15253 => DB_ERROR_SYNTAX,
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* Should data manipulation queries be committed automatically?
* @var bool
* @access private
*/
var $autocommit = true;
/**
* The quantity of transactions begun
*
* {@internal While this is private, it can't actually be designated
* private in PHP 5 because it is directly accessed in the test suite.}}
*
* @var integer
* @access private
*/
var $transaction_opcount = 0;
/**
* The database specified in the DSN
*
* It's a fix to allow calls to different databases in the same script.
*
* @var string
* @access private
*/
var $_db = null;
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_mssql()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase')
&& !PEAR::loadExtension('sybase_ct'))
{
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
$params = array(
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
$dsn['username'] ? $dsn['username'] : null,
$dsn['password'] ? $dsn['password'] : null,
);
if ($dsn['port']) {
$params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':')
. $dsn['port'];
}
$connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
$this->connection = @call_user_func_array($connect_function, $params);
if (!$this->connection) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
@mssql_get_last_message());
}
if ($dsn['database']) {
if (!@mssql_select_db($dsn['database'], $this->connection)) {
return $this->raiseError(DB_ERROR_NODBSELECTED,
null, null, null,
@mssql_get_last_message());
}
$this->_db = $dsn['database'];
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @mssql_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$ismanip = $this->_checkManip($query);
$this->last_query = $query;
if (!@mssql_select_db($this->_db, $this->connection)) {
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
}
$query = $this->modifyQuery($query);
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @mssql_query('BEGIN TRAN', $this->connection);
if (!$result) {
return $this->mssqlRaiseError();
}
}
$this->transaction_opcount++;
}
$result = @mssql_query($query, $this->connection);
if (!$result) {
return $this->mssqlRaiseError();
}
// Determine which queries that should return data, and which
// should return an error code only.
return $ismanip ? DB_OK : $result;
}
// }}}
// {{{ nextResult()
/**
* Move the internal mssql result pointer to the next available result
*
* @param a valid fbsql result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return @mssql_next_result($result);
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum !== null) {
if (!@mssql_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @mssql_fetch_assoc($result);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @mssql_fetch_row($result);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? mssql_free_result($result) : false;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @mssql_num_fields($result);
if (!$cols) {
return $this->mssqlRaiseError();
}
return $cols;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$rows = @mssql_num_rows($result);
if ($rows === false) {
return $this->mssqlRaiseError();
}
return $rows;
}
// }}}
// {{{ autoCommit()
/**
* Enables or disables automatic commits
*
* @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
function autoCommit($onoff = false)
{
// XXX if $this->transaction_opcount > 0, we should probably
// issue a warning here.
$this->autocommit = $onoff ? true : false;
return DB_OK;
}
// }}}
// {{{ commit()
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
if ($this->transaction_opcount > 0) {
if (!@mssql_select_db($this->_db, $this->connection)) {
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
}
$result = @mssql_query('COMMIT TRAN', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mssqlRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ rollback()
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
if ($this->transaction_opcount > 0) {
if (!@mssql_select_db($this->_db, $this->connection)) {
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
}
$result = @mssql_query('ROLLBACK TRAN', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mssqlRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ affectedRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if ($this->_last_query_manip) {
$res = @mssql_query('select @@rowcount', $this->connection);
if (!$res) {
return $this->mssqlRaiseError();
}
$ar = @mssql_fetch_row($res);
if (!$ar) {
$result = 0;
} else {
@mssql_free_result($res);
$result = $ar[0];
}
} else {
$result = 0;
}
return $result;
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_mssql::createSequence(), DB_mssql::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
if (!@mssql_select_db($this->_db, $this->connection)) {
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
}
$repeat = 0;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
$this->popErrorHandling();
if ($ondemand && DB::isError($result) &&
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
{
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
}
} elseif (!DB::isError($result)) {
$result =& $this->query("SELECT IDENT_CURRENT('$seqname')");
if (DB::isError($result)) {
/* Fallback code for MS SQL Server 7.0, which doesn't have
* IDENT_CURRENT. This is *not* safe for concurrent
* requests, and really, if you're using it, you're in a
* world of hurt. Nevertheless, it's here to ensure BC. See
* bug #181 for the gory details.*/
$result =& $this->query("SELECT @@IDENTITY FROM $seqname");
}
$repeat = 0;
} else {
$repeat = false;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$result = $result->fetchRow(DB_FETCHMODE_ORDERED);
return $result[0];
}
/**
* Creates a new sequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_mssql::nextID(), DB_mssql::dropSequence()
*/
function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
. $this->getSequenceName($seq_name)
. ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
. ' [vapor] [int] NULL)');
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_mssql::nextID(), DB_mssql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
// }}}
// {{{ quoteIdentifier()
/**
* Quotes a string so it can be safely used as a table or column name
*
* @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
* @see DB_common::quoteIdentifier()
* @since Method available since Release 1.6.0
*/
function quoteIdentifier($str)
{
return '[' . str_replace(']', ']]', $str) . ']';
}
// }}}
// {{{ mssqlRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_mssql::errorNative(), DB_mssql::errorCode()
*/
function mssqlRaiseError($code = null)
{
$message = @mssql_get_last_message();
if (!$code) {
$code = $this->errorNative();
}
return $this->raiseError($this->errorCode($code, $message),
null, null, null, "$code - $message");
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code
*/
function errorNative()
{
$res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
if (!$res) {
return DB_ERROR;
}
$row = @mssql_fetch_row($res);
return $row[0];
}
// }}}
// {{{ errorCode()
/**
* Determines PEAR::DB error code from mssql's native codes.
*
* If <var>$nativecode</var> isn't known yet, it will be looked up.
*
* @param mixed $nativecode mssql error code, if known
* @return integer an error number from a DB error constant
* @see errorNative()
*/
function errorCode($nativecode = null, $msg = '')
{
if (!$nativecode) {
$nativecode = $this->errorNative();
}
if (isset($this->errorcode_map[$nativecode])) {
if ($nativecode == 3701
&& preg_match('/Cannot drop the index/i', $msg))
{
return DB_ERROR_NOT_FOUND;
}
return $this->errorcode_map[$nativecode];
} else {
return DB_ERROR;
}
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
if (!@mssql_select_db($this->_db, $this->connection)) {
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
}
$id = @mssql_query("SELECT * FROM $result WHERE 1=0",
$this->connection);
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = @mssql_num_fields($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
if ($got_string) {
$flags = $this->_mssql_field_flags($result,
@mssql_field_name($id, $i));
if (DB::isError($flags)) {
return $flags;
}
} else {
$flags = '';
}
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
'name' => $case_func(@mssql_field_name($id, $i)),
'type' => @mssql_field_type($id, $i),
'len' => @mssql_field_length($id, $i),
'flags' => $flags,
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
// free the result only if we were called on a table
if ($got_string) {
@mssql_free_result($id);
}
return $res;
}
// }}}
// {{{ _mssql_field_flags()
/**
* Get a column's flags
*
* Supports "not_null", "primary_key",
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
* "unique_key" (mssql unique index, unique check or primary_key) and
* "multiple_key" (multikey index)
*
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe
* not useful at all - is the behaviour of mysql_field_flags that primary
* keys are alway unique? is the interpretation of multiple_key correct?
*
* @param string $table the table name
* @param string $column the field name
*
* @return string the flags
*
* @access private
* @author Joern Barthel <j_barthel@web.de>
*/
function _mssql_field_flags($table, $column)
{
static $tableName = null;
static $flags = array();
if ($table != $tableName) {
$flags = array();
$tableName = $table;
// get unique and primary keys
$res = $this->getAll("EXEC SP_HELPINDEX $table", DB_FETCHMODE_ASSOC);
if (DB::isError($res)) {
return $res;
}
foreach ($res as $val) {
$keys = explode(', ', $val['index_keys']);
if (sizeof($keys) > 1) {
foreach ($keys as $key) {
$this->_add_flag($flags[$key], 'multiple_key');
}
}
if (strpos($val['index_description'], 'primary key')) {
foreach ($keys as $key) {
$this->_add_flag($flags[$key], 'primary_key');
}
} elseif (strpos($val['index_description'], 'unique')) {
foreach ($keys as $key) {
$this->_add_flag($flags[$key], 'unique_key');
}
}
}
// get auto_increment, not_null and timestamp
$res = $this->getAll("EXEC SP_COLUMNS $table", DB_FETCHMODE_ASSOC);
if (DB::isError($res)) {
return $res;
}
foreach ($res as $val) {
$val = array_change_key_case($val, CASE_LOWER);
if ($val['nullable'] == '0') {
$this->_add_flag($flags[$val['column_name']], 'not_null');
}
if (strpos($val['type_name'], 'identity')) {
$this->_add_flag($flags[$val['column_name']], 'auto_increment');
}
if (strpos($val['type_name'], 'timestamp')) {
$this->_add_flag($flags[$val['column_name']], 'timestamp');
}
}
}
if (array_key_exists($column, $flags)) {
return(implode(' ', $flags[$column]));
}
return '';
}
// }}}
// {{{ _add_flag()
/**
* Adds a string to the flags array if the flag is not yet in there
* - if there is no flag present the array is created
*
* @param array &$array the reference to the flag-array
* @param string $value the flag value
*
* @return void
*
* @access private
* @author Joern Barthel <j_barthel@web.de>
*/
function _add_flag(&$array, $value)
{
if (!is_array($array)) {
$array = array($value);
} elseif (!in_array($value, $array)) {
array_push($array, $value);
}
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'tables':
return "SELECT name FROM sysobjects WHERE type = 'U'"
. ' ORDER BY name';
case 'views':
return "SELECT name FROM sysobjects WHERE type = 'V'";
default:
return null;
}
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

1038
lib/pear/DB/mysql.php Normal file

File diff suppressed because it is too large Load Diff

1085
lib/pear/DB/mysqli.php Normal file

File diff suppressed because it is too large Load Diff

1154
lib/pear/DB/oci8.php Normal file

File diff suppressed because it is too large Load Diff

883
lib/pear/DB/odbc.php Normal file
View File

@@ -0,0 +1,883 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's odbc extension
* for interacting with databases via ODBC connections
*
* 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 Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: odbc.php,v 1.80 2007/01/12 03:11:17 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's odbc extension
* for interacting with databases via ODBC connections
*
* These methods overload the ones declared in DB_common.
*
* More info on ODBC errors could be found here:
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_odbc extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'odbc';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'sql92';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* NOTE: The feature set of the following drivers are different than
* the default:
* + solid: 'transactions' = true
* + navision: 'limit' = false
*
* @var array
*/
var $features = array(
'limit' => 'emulate',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
'01004' => DB_ERROR_TRUNCATED,
'07001' => DB_ERROR_MISMATCH,
'21S01' => DB_ERROR_VALUE_COUNT_ON_ROW,
'21S02' => DB_ERROR_MISMATCH,
'22001' => DB_ERROR_INVALID,
'22003' => DB_ERROR_INVALID_NUMBER,
'22005' => DB_ERROR_INVALID_NUMBER,
'22008' => DB_ERROR_INVALID_DATE,
'22012' => DB_ERROR_DIVZERO,
'23000' => DB_ERROR_CONSTRAINT,
'23502' => DB_ERROR_CONSTRAINT_NOT_NULL,
'23503' => DB_ERROR_CONSTRAINT,
'23504' => DB_ERROR_CONSTRAINT,
'23505' => DB_ERROR_CONSTRAINT,
'24000' => DB_ERROR_INVALID,
'34000' => DB_ERROR_INVALID,
'37000' => DB_ERROR_SYNTAX,
'42000' => DB_ERROR_SYNTAX,
'42601' => DB_ERROR_SYNTAX,
'IM001' => DB_ERROR_UNSUPPORTED,
'S0000' => DB_ERROR_NOSUCHTABLE,
'S0001' => DB_ERROR_ALREADY_EXISTS,
'S0002' => DB_ERROR_NOSUCHTABLE,
'S0011' => DB_ERROR_ALREADY_EXISTS,
'S0012' => DB_ERROR_NOT_FOUND,
'S0021' => DB_ERROR_ALREADY_EXISTS,
'S0022' => DB_ERROR_NOSUCHFIELD,
'S1009' => DB_ERROR_INVALID,
'S1090' => DB_ERROR_INVALID,
'S1C00' => DB_ERROR_NOT_CAPABLE,
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* The number of rows affected by a data manipulation query
* @var integer
* @access private
*/
var $affected = 0;
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_odbc()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* PEAR DB's odbc driver supports the following extra DSN options:
* + cursor The type of cursor to be used for this connection.
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('odbc')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
switch ($this->dbsyntax) {
case 'access':
case 'db2':
case 'solid':
$this->features['transactions'] = true;
break;
case 'navision':
$this->features['limit'] = false;
}
/*
* This is hear for backwards compatibility. Should have been using
* 'database' all along, but prior to 1.6.0RC3 'hostspec' was used.
*/
if ($dsn['database']) {
$odbcdsn = $dsn['database'];
} elseif ($dsn['hostspec']) {
$odbcdsn = $dsn['hostspec'];
} else {
$odbcdsn = 'localhost';
}
$connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect';
if (empty($dsn['cursor'])) {
$this->connection = @$connect_function($odbcdsn, $dsn['username'],
$dsn['password']);
} else {
$this->connection = @$connect_function($odbcdsn, $dsn['username'],
$dsn['password'],
$dsn['cursor']);
}
if (!is_resource($this->connection)) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$this->errorNative());
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$err = @odbc_close($this->connection);
$this->connection = null;
return $err;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$this->last_query = $query;
$query = $this->modifyQuery($query);
$result = @odbc_exec($this->connection, $query);
if (!$result) {
return $this->odbcRaiseError(); // XXX ERRORMSG
}
// Determine which queries that should return data, and which
// should return an error code only.
if ($this->_checkManip($query)) {
$this->affected = $result; // For affectedRows()
return DB_OK;
}
$this->affected = 0;
return $result;
}
// }}}
// {{{ nextResult()
/**
* Move the internal odbc result pointer to the next available result
*
* @param a valid fbsql result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return @odbc_next_result($result);
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
$arr = array();
if ($rownum !== null) {
$rownum++; // ODBC first row is 1
if (version_compare(phpversion(), '4.2.0', 'ge')) {
$cols = @odbc_fetch_into($result, $arr, $rownum);
} else {
$cols = @odbc_fetch_into($result, $rownum, $arr);
}
} else {
$cols = @odbc_fetch_into($result, $arr);
}
if (!$cols) {
return null;
}
if ($fetchmode !== DB_FETCHMODE_ORDERED) {
for ($i = 0; $i < count($arr); $i++) {
$colName = @odbc_field_name($result, $i+1);
$a[$colName] = $arr[$i];
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$a = array_change_key_case($a, CASE_LOWER);
}
$arr = $a;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? odbc_free_result($result) : false;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @odbc_num_fields($result);
if (!$cols) {
return $this->odbcRaiseError();
}
return $cols;
}
// }}}
// {{{ affectedRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if (empty($this->affected)) { // In case of SELECT stms
return 0;
}
$nrows = @odbc_num_rows($this->affected);
if ($nrows == -1) {
return $this->odbcRaiseError();
}
return $nrows;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* Not all ODBC drivers support this functionality. If they don't
* a DB_Error object for DB_ERROR_UNSUPPORTED is returned.
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$nrows = @odbc_num_rows($result);
if ($nrows == -1) {
return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED);
}
if ($nrows === false) {
return $this->odbcRaiseError();
}
return $nrows;
}
// }}}
// {{{ quoteIdentifier()
/**
* Quotes a string so it can be safely used as a table or column name
*
* Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
* "Use ANSI quoted identifiers" when setting up the ODBC data source.
*
* @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
* @see DB_common::quoteIdentifier()
* @since Method available since Release 1.6.0
*/
function quoteIdentifier($str)
{
switch ($this->dsn['dbsyntax']) {
case 'access':
return '[' . $str . ']';
case 'mssql':
case 'sybase':
return '[' . str_replace(']', ']]', $str) . ']';
case 'mysql':
case 'mysqli':
return '`' . $str . '`';
default:
return '"' . str_replace('"', '""', $str) . '"';
}
}
// }}}
// {{{ quote()
/**
* @deprecated Deprecated in release 1.6.0
* @internal
*/
function quote($str)
{
return $this->quoteSmart($str);
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_odbc::createSequence(), DB_odbc::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
$repeat = 0;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("update ${seqname} set id = id + 1");
$this->popErrorHandling();
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = 1;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->createSequence($seq_name);
$this->popErrorHandling();
if (DB::isError($result)) {
return $this->raiseError($result);
}
$result = $this->query("insert into ${seqname} (id) values(0)");
} else {
$repeat = 0;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$result = $this->query("select id from ${seqname}");
if (DB::isError($result)) {
return $result;
}
$row = $result->fetchRow(DB_FETCHMODE_ORDERED);
if (DB::isError($row || !$row)) {
return $row;
}
return $row[0];
}
/**
* Creates a new sequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_odbc::nextID(), DB_odbc::dropSequence()
*/
function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
. $this->getSequenceName($seq_name)
. ' (id integer NOT NULL,'
. ' PRIMARY KEY(id))');
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_odbc::nextID(), DB_odbc::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
// }}}
// {{{ autoCommit()
/**
* Enables or disables automatic commits
*
* @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
function autoCommit($onoff = false)
{
if (!@odbc_autocommit($this->connection, $onoff)) {
return $this->odbcRaiseError();
}
return DB_OK;
}
// }}}
// {{{ commit()
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
if (!@odbc_commit($this->connection)) {
return $this->odbcRaiseError();
}
return DB_OK;
}
// }}}
// {{{ rollback()
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
if (!@odbc_rollback($this->connection)) {
return $this->odbcRaiseError();
}
return DB_OK;
}
// }}}
// {{{ odbcRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_odbc::errorNative(), DB_common::errorCode()
*/
function odbcRaiseError($errno = null)
{
if ($errno === null) {
switch ($this->dbsyntax) {
case 'access':
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
$this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD;
} else {
// Doing this in case mode changes during runtime.
$this->errorcode_map['07001'] = DB_ERROR_MISMATCH;
}
$native_code = odbc_error($this->connection);
// S1000 is for "General Error." Let's be more specific.
if ($native_code == 'S1000') {
$errormsg = odbc_errormsg($this->connection);
static $error_regexps;
if (!isset($error_regexps)) {
$error_regexps = array(
'/includes related records.$/i' => DB_ERROR_CONSTRAINT,
'/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL,
);
}
foreach ($error_regexps as $regexp => $code) {
if (preg_match($regexp, $errormsg)) {
return $this->raiseError($code,
null, null, null,
$native_code . ' ' . $errormsg);
}
}
$errno = DB_ERROR;
} else {
$errno = $this->errorCode($native_code);
}
break;
default:
$errno = $this->errorCode(odbc_error($this->connection));
}
}
return $this->raiseError($errno, null, null, null,
$this->errorNative());
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error code and message produced by the last query
*
* @return string the DBMS' error code and message
*/
function errorNative()
{
if (!is_resource($this->connection)) {
return @odbc_error() . ' ' . @odbc_errormsg();
}
return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.7.0
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @odbc_exec($this->connection, "SELECT * FROM $result");
if (!$id) {
return $this->odbcRaiseError();
}
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = @odbc_num_fields($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$col = $i + 1;
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
'name' => $case_func(@odbc_field_name($id, $col)),
'type' => @odbc_field_type($id, $col),
'len' => @odbc_field_len($id, $col),
'flags' => '',
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
// free the result only if we were called on a table
if ($got_string) {
@odbc_free_result($id);
}
return $res;
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com.
*
* @param string $type the kind of objects you want to retrieve
*
* @return string the list of objects requested
*
* @access protected
* @see DB_common::getListOf()
* @since Method available since Release 1.7.0
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'databases':
if (!function_exists('odbc_data_source')) {
return null;
}
$res = @odbc_data_source($this->connection, SQL_FETCH_FIRST);
if (is_array($res)) {
$out = array($res['server']);
while($res = @odbc_data_source($this->connection,
SQL_FETCH_NEXT))
{
$out[] = $res['server'];
}
return $out;
} else {
return $this->odbcRaiseError();
}
break;
case 'tables':
case 'schema.tables':
$keep = 'TABLE';
break;
case 'views':
$keep = 'VIEW';
break;
default:
return null;
}
/*
* Removing non-conforming items in the while loop rather than
* in the odbc_tables() call because some backends choke on this:
* odbc_tables($this->connection, '', '', '', 'TABLE')
*/
$res = @odbc_tables($this->connection);
if (!$res) {
return $this->odbcRaiseError();
}
$out = array();
while ($row = odbc_fetch_array($res)) {
if ($row['TABLE_TYPE'] != $keep) {
continue;
}
if ($type == 'schema.tables') {
$out[] = $row['TABLE_SCHEM'] . '.' . $row['TABLE_NAME'];
} else {
$out[] = $row['TABLE_NAME'];
}
}
return $out;
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

1103
lib/pear/DB/pgsql.php Normal file

File diff suppressed because it is too large Load Diff

949
lib/pear/DB/sqlite.php Normal file
View File

@@ -0,0 +1,949 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's sqlite extension
* for interacting with SQLite databases
*
* 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 Database
* @package DB
* @author Urs Gehrig <urs@circle.ch>
* @author Mika Tuupola <tuupola@appelsiini.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
* @version CVS: $Id: sqlite.php,v 1.114 2007/01/12 02:41:07 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's sqlite extension
* for interacting with SQLite databases
*
* These methods overload the ones declared in DB_common.
*
* NOTICE: This driver needs PHP's track_errors ini setting to be on.
* It is automatically turned on when connecting to the database.
* Make sure your scripts don't turn it off.
*
* @category Database
* @package DB
* @author Urs Gehrig <urs@circle.ch>
* @author Mika Tuupola <tuupola@appelsiini.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_sqlite extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'sqlite';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'sqlite';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'alter',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => false,
);
/**
* A mapping of native error codes to DB error codes
*
* {@internal Error codes according to sqlite_exec. See the online
* manual at http://sqlite.org/c_interface.html for info.
* This error handling based on sqlite_exec is not yet implemented.}}
*
* @var array
*/
var $errorcode_map = array(
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* SQLite data types
*
* @link http://www.sqlite.org/datatypes.html
*
* @var array
*/
var $keywords = array (
'BLOB' => '',
'BOOLEAN' => '',
'CHARACTER' => '',
'CLOB' => '',
'FLOAT' => '',
'INTEGER' => '',
'KEY' => '',
'NATIONAL' => '',
'NUMERIC' => '',
'NVARCHAR' => '',
'PRIMARY' => '',
'TEXT' => '',
'TIMESTAMP' => '',
'UNIQUE' => '',
'VARCHAR' => '',
'VARYING' => '',
);
/**
* The most recent error message from $php_errormsg
* @var string
* @access private
*/
var $_lasterror = '';
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_sqlite()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* PEAR DB's sqlite driver supports the following extra DSN options:
* + mode The permissions for the database file, in four digit
* chmod octal format (eg "0600").
*
* Example of connecting to a database in read-only mode:
* <code>
* require_once 'DB.php';
*
* $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
* $options = array(
* 'portability' => DB_PORTABILITY_ALL,
* );
*
* $db =& DB::connect($dsn, $options);
* if (PEAR::isError($db)) {
* die($db->getMessage());
* }
* </code>
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('sqlite')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
if (!$dsn['database']) {
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
}
if ($dsn['database'] !== ':memory:') {
if (!file_exists($dsn['database'])) {
if (!touch($dsn['database'])) {
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
}
if (!isset($dsn['mode']) ||
!is_numeric($dsn['mode']))
{
$mode = 0644;
} else {
$mode = octdec($dsn['mode']);
}
if (!chmod($dsn['database'], $mode)) {
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
}
if (!file_exists($dsn['database'])) {
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
}
}
if (!is_file($dsn['database'])) {
return $this->sqliteRaiseError(DB_ERROR_INVALID);
}
if (!is_readable($dsn['database'])) {
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
}
}
$connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
// track_errors must remain on for simpleQuery()
@ini_set('track_errors', 1);
$php_errormsg = '';
if (!$this->connection = @$connect_function($dsn['database'])) {
return $this->raiseError(DB_ERROR_NODBSELECTED,
null, null, null,
$php_errormsg);
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @sqlite_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* NOTICE: This method needs PHP's track_errors ini setting to be on.
* It is automatically turned on when connecting to the database.
* Make sure your scripts don't turn it off.
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$ismanip = $this->_checkManip($query);
$this->last_query = $query;
$query = $this->modifyQuery($query);
$php_errormsg = '';
$result = @sqlite_query($query, $this->connection);
$this->_lasterror = $php_errormsg ? $php_errormsg : '';
$this->result = $result;
if (!$this->result) {
return $this->sqliteRaiseError(null);
}
// sqlite_query() seems to allways return a resource
// so cant use that. Using $ismanip instead
if (!$ismanip) {
$numRows = $this->numRows($result);
if (is_object($numRows)) {
// we've got PEAR_Error
return $numRows;
}
return $result;
}
return DB_OK;
}
// }}}
// {{{ nextResult()
/**
* Move the internal sqlite result pointer to the next available result
*
* @param resource $result the valid sqlite result resource
*
* @return bool true if a result is available otherwise return false
*/
function nextResult($result)
{
return false;
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum !== null) {
if (!@sqlite_seek($this->result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @sqlite_fetch_array($result, SQLITE_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @sqlite_fetch_array($result, SQLITE_NUM);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
/*
* Even though this DBMS already trims output, we do this because
* a field might have intentional whitespace at the end that
* gets removed by DB_PORTABILITY_RTRIM under another driver.
*/
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult(&$result)
{
// XXX No native free?
if (!is_resource($result)) {
return false;
}
$result = null;
return true;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @sqlite_num_fields($result);
if (!$cols) {
return $this->sqliteRaiseError();
}
return $cols;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$rows = @sqlite_num_rows($result);
if ($rows === null) {
return $this->sqliteRaiseError();
}
return $rows;
}
// }}}
// {{{ affected()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
return @sqlite_changes($this->connection);
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_sqlite::nextID(), DB_sqlite::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
/**
* Creates a new sequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_sqlite::nextID(), DB_sqlite::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$query = 'CREATE TABLE ' . $seqname .
' (id INTEGER UNSIGNED PRIMARY KEY) ';
$result = $this->query($query);
if (DB::isError($result)) {
return($result);
}
$query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
BEGIN
DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
END ";
$result = $this->query($query);
if (DB::isError($result)) {
return($result);
}
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_sqlite::createSequence(), DB_sqlite::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
do {
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
$this->popErrorHandling();
if ($result === DB_OK) {
$id = @sqlite_last_insert_rowid($this->connection);
if ($id != 0) {
return $id;
}
} elseif ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE)
{
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
} else {
$repeat = 1;
}
}
} while ($repeat);
return $this->raiseError($result);
}
// }}}
// {{{ getDbFileStats()
/**
* Get the file stats for the current database
*
* Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
* atime, mtime, ctime, blksize, blocks or a numeric key between
* 0 and 12.
*
* @param string $arg the array key for stats()
*
* @return mixed an array on an unspecified key, integer on a passed
* arg and false at a stats error
*/
function getDbFileStats($arg = '')
{
$stats = stat($this->dsn['database']);
if ($stats == false) {
return false;
}
if (is_array($stats)) {
if (is_numeric($arg)) {
if (((int)$arg <= 12) & ((int)$arg >= 0)) {
return false;
}
return $stats[$arg ];
}
if (array_key_exists(trim($arg), $stats)) {
return $stats[$arg ];
}
}
return $stats;
}
// }}}
// {{{ escapeSimple()
/**
* Escapes a string according to the current DBMS's standards
*
* In SQLite, this makes things safe for inserts/updates, but may
* cause problems when performing text comparisons against columns
* containing binary data. See the
* {@link http://php.net/sqlite_escape_string PHP manual} for more info.
*
* @param string $str the string to be escaped
*
* @return string the escaped string
*
* @since Method available since Release 1.6.1
* @see DB_common::escapeSimple()
*/
function escapeSimple($str)
{
return @sqlite_escape_string($str);
}
// }}}
// {{{ modifyLimitQuery()
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* @param string $query the query to modify
* @param int $from the row to start to fetching (0 = the first row)
* @param int $count the numbers of rows to fetch
* @param mixed $params array, string or numeric data to be used in
* execution of the statement. Quantity of items
* passed must match quantity of placeholders in
* query: meaning 1 placeholder for non-array
* parameters or 1 placeholder per array element.
*
* @return string the query string with LIMIT clauses added
*
* @access protected
*/
function modifyLimitQuery($query, $from, $count, $params = array())
{
return "$query LIMIT $count OFFSET $from";
}
// }}}
// {{{ modifyQuery()
/**
* Changes a query string for various DBMS specific reasons
*
* This little hack lets you know how many rows were deleted
* when running a "DELETE FROM table" query. Only implemented
* if the DB_PORTABILITY_DELETE_COUNT portability option is on.
*
* @param string $query the query string to modify
*
* @return string the modified query string
*
* @access protected
* @see DB_common::setOption()
*/
function modifyQuery($query)
{
if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
$query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
'DELETE FROM \1 WHERE 1=1', $query);
}
}
return $query;
}
// }}}
// {{{ sqliteRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_sqlite::errorNative(), DB_sqlite::errorCode()
*/
function sqliteRaiseError($errno = null)
{
$native = $this->errorNative();
if ($errno === null) {
$errno = $this->errorCode($native);
}
$errorcode = @sqlite_last_error($this->connection);
$userinfo = "$errorcode ** $this->last_query";
return $this->raiseError($errno, null, null, $userinfo, $native);
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error message produced by the last query
*
* {@internal This is used to retrieve more meaningfull error messages
* because sqlite_last_error() does not provide adequate info.}}
*
* @return string the DBMS' error message
*/
function errorNative()
{
return $this->_lasterror;
}
// }}}
// {{{ errorCode()
/**
* Determines PEAR::DB error code from the database's text error message
*
* @param string $errormsg the error message returned from the database
*
* @return integer the DB error number
*/
function errorCode($errormsg)
{
static $error_regexps;
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
// this hack to work around it, per bug #9599.
$errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg);
if (!isset($error_regexps)) {
$error_regexps = array(
'/^no such table:/' => DB_ERROR_NOSUCHTABLE,
'/^no such index:/' => DB_ERROR_NOT_FOUND,
'/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
'/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
'/is not unique/' => DB_ERROR_CONSTRAINT,
'/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
'/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
'/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
'/^no such column:/' => DB_ERROR_NOSUCHFIELD,
'/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
'/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
'/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
);
}
foreach ($error_regexps as $regexp => $code) {
if (preg_match($regexp, $errormsg)) {
return $code;
}
}
// Fall back to DB_ERROR if there was no mapping.
return DB_ERROR;
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table
*
* @param string $result a string containing the name of a table
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.7.0
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @sqlite_array_query($this->connection,
"PRAGMA table_info('$result');",
SQLITE_ASSOC);
$got_string = true;
} else {
$this->last_query = '';
return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null,
'This DBMS can not obtain tableInfo' .
' from result sets');
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = count($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
if (strpos($id[$i]['type'], '(') !== false) {
$bits = explode('(', $id[$i]['type']);
$type = $bits[0];
$len = rtrim($bits[1],')');
} else {
$type = $id[$i]['type'];
$len = 0;
}
$flags = '';
if ($id[$i]['pk']) {
$flags .= 'primary_key ';
}
if ($id[$i]['notnull']) {
$flags .= 'not_null ';
}
if ($id[$i]['dflt_value'] !== null) {
$flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
}
$flags = trim($flags);
$res[$i] = array(
'table' => $case_func($result),
'name' => $case_func($id[$i]['name']),
'type' => $type,
'len' => $len,
'flags' => $flags,
);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
return $res;
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* @param string $type the kind of objects you want to retrieve
* @param array $args SQLITE DRIVER ONLY: a private array of arguments
* used by the getSpecialQuery(). Do not use
* this directly.
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type, $args = array())
{
if (!is_array($args)) {
return $this->raiseError('no key specified', null, null, null,
'Argument has to be an array.');
}
switch ($type) {
case 'master':
return 'SELECT * FROM sqlite_master;';
case 'tables':
return "SELECT name FROM sqlite_master WHERE type='table' "
. 'UNION ALL SELECT name FROM sqlite_temp_master '
. "WHERE type='table' ORDER BY name;";
case 'schema':
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
. 'UNION ALL SELECT * FROM sqlite_temp_master) '
. "WHERE type!='meta' "
. 'ORDER BY tbl_name, type DESC, name;';
case 'schemax':
case 'schema_x':
/*
* Use like:
* $res = $db->query($db->getSpecialQuery('schema_x',
* array('table' => 'table3')));
*/
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
. 'UNION ALL SELECT * FROM sqlite_temp_master) '
. "WHERE tbl_name LIKE '{$args['table']}' "
. "AND type!='meta' "
. 'ORDER BY type DESC, name;';
case 'alter':
/*
* SQLite does not support ALTER TABLE; this is a helper query
* to handle this. 'table' represents the table name, 'rows'
* the news rows to create, 'save' the row(s) to keep _with_
* the data.
*
* Use like:
* $args = array(
* 'table' => $table,
* 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
* 'save' => "NULL, titel, content, datetime"
* );
* $res = $db->query( $db->getSpecialQuery('alter', $args));
*/
$rows = strtr($args['rows'], $this->keywords);
$q = array(
'BEGIN TRANSACTION',
"CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
"INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
"DROP TABLE {$args['table']}",
"CREATE TABLE {$args['table']} ({$args['rows']})",
"INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
"DROP TABLE {$args['table']}_backup",
'COMMIT',
);
/*
* This is a dirty hack, since the above query will not get
* executed with a single query call so here the query method
* will be called directly and return a select instead.
*/
foreach ($q as $query) {
$this->query($query);
}
return "SELECT * FROM {$args['table']};";
default:
return null;
}
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

506
lib/pear/DB/storage.php Normal file
View File

@@ -0,0 +1,506 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Provides an object interface to a table row
*
* 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 Database
* @package DB
* @author Stig Bakken <stig@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: storage.php,v 1.22 2005/07/10 13:38:51 danielc Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB class so it can be extended from
*/
require_once 'DB.php';
/**
* Provides an object interface to a table row
*
* It lets you add, delete and change rows using objects rather than SQL
* statements.
*
* @category Database
* @package DB
* @author Stig Bakken <stig@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_storage extends PEAR
{
// {{{ properties
/** the name of the table (or view, if the backend database supports
updates in views) we hold data from */
var $_table = null;
/** which column(s) in the table contains primary keys, can be a
string for single-column primary keys, or an array of strings
for multiple-column primary keys */
var $_keycolumn = null;
/** DB connection handle used for all transactions */
var $_dbh = null;
/** an assoc with the names of database fields stored as properties
in this object */
var $_properties = array();
/** an assoc with the names of the properties in this object that
have been changed since they were fetched from the database */
var $_changes = array();
/** flag that decides if data in this object can be changed.
objects that don't have their table's key column in their
property lists will be flagged as read-only. */
var $_readonly = false;
/** function or method that implements a validator for fields that
are set, this validator function returns true if the field is
valid, false if not */
var $_validator = null;
// }}}
// {{{ constructor
/**
* Constructor
*
* @param $table string the name of the database table
*
* @param $keycolumn mixed string with name of key column, or array of
* strings if the table has a primary key of more than one column
*
* @param $dbh object database connection object
*
* @param $validator mixed function or method used to validate
* each new value, called with three parameters: the name of the
* field/column that is changing, a reference to the new value and
* a reference to this object
*
*/
function DB_storage($table, $keycolumn, &$dbh, $validator = null)
{
$this->PEAR('DB_Error');
$this->_table = $table;
$this->_keycolumn = $keycolumn;
$this->_dbh = $dbh;
$this->_readonly = false;
$this->_validator = $validator;
}
// }}}
// {{{ _makeWhere()
/**
* Utility method to build a "WHERE" clause to locate ourselves in
* the table.
*
* XXX future improvement: use rowids?
*
* @access private
*/
function _makeWhere($keyval = null)
{
if (is_array($this->_keycolumn)) {
if ($keyval === null) {
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
$keyval[] = $this->{$this->_keycolumn[$i]};
}
}
$whereclause = '';
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
if ($i > 0) {
$whereclause .= ' AND ';
}
$whereclause .= $this->_keycolumn[$i];
if (is_null($keyval[$i])) {
// there's not much point in having a NULL key,
// but we support it anyway
$whereclause .= ' IS NULL';
} else {
$whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
}
}
} else {
if ($keyval === null) {
$keyval = @$this->{$this->_keycolumn};
}
$whereclause = $this->_keycolumn;
if (is_null($keyval)) {
// there's not much point in having a NULL key,
// but we support it anyway
$whereclause .= ' IS NULL';
} else {
$whereclause .= ' = ' . $this->_dbh->quote($keyval);
}
}
return $whereclause;
}
// }}}
// {{{ setup()
/**
* Method used to initialize a DB_storage object from the
* configured table.
*
* @param $keyval mixed the key[s] of the row to fetch (string or array)
*
* @return int DB_OK on success, a DB error if not
*/
function setup($keyval)
{
$whereclause = $this->_makeWhere($keyval);
$query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
$sth = $this->_dbh->query($query);
if (DB::isError($sth)) {
return $sth;
}
$row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
if (DB::isError($row)) {
return $row;
}
if (!$row) {
return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null,
$query, null, true);
}
foreach ($row as $key => $value) {
$this->_properties[$key] = true;
$this->$key = $value;
}
return DB_OK;
}
// }}}
// {{{ insert()
/**
* Create a new (empty) row in the configured table for this
* object.
*/
function insert($newpk)
{
if (is_array($this->_keycolumn)) {
$primarykey = $this->_keycolumn;
} else {
$primarykey = array($this->_keycolumn);
}
settype($newpk, "array");
for ($i = 0; $i < sizeof($primarykey); $i++) {
$pkvals[] = $this->_dbh->quote($newpk[$i]);
}
$sth = $this->_dbh->query("INSERT INTO $this->_table (" .
implode(",", $primarykey) . ") VALUES(" .
implode(",", $pkvals) . ")");
if (DB::isError($sth)) {
return $sth;
}
if (sizeof($newpk) == 1) {
$newpk = $newpk[0];
}
$this->setup($newpk);
}
// }}}
// {{{ toString()
/**
* Output a simple description of this DB_storage object.
* @return string object description
*/
function toString()
{
$info = strtolower(get_class($this));
$info .= " (table=";
$info .= $this->_table;
$info .= ", keycolumn=";
if (is_array($this->_keycolumn)) {
$info .= "(" . implode(",", $this->_keycolumn) . ")";
} else {
$info .= $this->_keycolumn;
}
$info .= ", dbh=";
if (is_object($this->_dbh)) {
$info .= $this->_dbh->toString();
} else {
$info .= "null";
}
$info .= ")";
if (sizeof($this->_properties)) {
$info .= " [loaded, key=";
$keyname = $this->_keycolumn;
if (is_array($keyname)) {
$info .= "(";
for ($i = 0; $i < sizeof($keyname); $i++) {
if ($i > 0) {
$info .= ",";
}
$info .= $this->$keyname[$i];
}
$info .= ")";
} else {
$info .= $this->$keyname;
}
$info .= "]";
}
if (sizeof($this->_changes)) {
$info .= " [modified]";
}
return $info;
}
// }}}
// {{{ dump()
/**
* Dump the contents of this object to "standard output".
*/
function dump()
{
foreach ($this->_properties as $prop => $foo) {
print "$prop = ";
print htmlentities($this->$prop);
print "<br />\n";
}
}
// }}}
// {{{ &create()
/**
* Static method used to create new DB storage objects.
* @param $data assoc. array where the keys are the names
* of properties/columns
* @return object a new instance of DB_storage or a subclass of it
*/
function &create($table, &$data)
{
$classname = strtolower(get_class($this));
$obj =& new $classname($table);
foreach ($data as $name => $value) {
$obj->_properties[$name] = true;
$obj->$name = &$value;
}
return $obj;
}
// }}}
// {{{ loadFromQuery()
/**
* Loads data into this object from the given query. If this
* object already contains table data, changes will be saved and
* the object re-initialized first.
*
* @param $query SQL query
*
* @param $params parameter list in case you want to use
* prepare/execute mode
*
* @return int DB_OK on success, DB_WARNING_READ_ONLY if the
* returned object is read-only (because the object's specified
* key column was not found among the columns returned by $query),
* or another DB error code in case of errors.
*/
// XXX commented out for now
/*
function loadFromQuery($query, $params = null)
{
if (sizeof($this->_properties)) {
if (sizeof($this->_changes)) {
$this->store();
$this->_changes = array();
}
$this->_properties = array();
}
$rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
if (DB::isError($rowdata)) {
return $rowdata;
}
reset($rowdata);
$found_keycolumn = false;
while (list($key, $value) = each($rowdata)) {
if ($key == $this->_keycolumn) {
$found_keycolumn = true;
}
$this->_properties[$key] = true;
$this->$key = &$value;
unset($value); // have to unset, or all properties will
// refer to the same value
}
if (!$found_keycolumn) {
$this->_readonly = true;
return DB_WARNING_READ_ONLY;
}
return DB_OK;
}
*/
// }}}
// {{{ set()
/**
* Modify an attriute value.
*/
function set($property, $newvalue)
{
// only change if $property is known and object is not
// read-only
if ($this->_readonly) {
return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
null, null, null, true);
}
if (@isset($this->_properties[$property])) {
if (empty($this->_validator)) {
$valid = true;
} else {
$valid = @call_user_func($this->_validator,
$this->_table,
$property,
$newvalue,
$this->$property,
$this);
}
if ($valid) {
$this->$property = $newvalue;
if (empty($this->_changes[$property])) {
$this->_changes[$property] = 0;
} else {
$this->_changes[$property]++;
}
} else {
return $this->raiseError(null, DB_ERROR_INVALID, null,
null, "invalid field: $property",
null, true);
}
return true;
}
return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null,
null, "unknown field: $property",
null, true);
}
// }}}
// {{{ &get()
/**
* Fetch an attribute value.
*
* @param string attribute name
*
* @return attribute contents, or null if the attribute name is
* unknown
*/
function &get($property)
{
// only return if $property is known
if (isset($this->_properties[$property])) {
return $this->$property;
}
$tmp = null;
return $tmp;
}
// }}}
// {{{ _DB_storage()
/**
* Destructor, calls DB_storage::store() if there are changes
* that are to be kept.
*/
function _DB_storage()
{
if (sizeof($this->_changes)) {
$this->store();
}
$this->_properties = array();
$this->_changes = array();
$this->_table = null;
}
// }}}
// {{{ store()
/**
* Stores changes to this object in the database.
*
* @return DB_OK or a DB error
*/
function store()
{
$params = array();
$vars = array();
foreach ($this->_changes as $name => $foo) {
$params[] = &$this->$name;
$vars[] = $name . ' = ?';
}
if ($vars) {
$query = 'UPDATE ' . $this->_table . ' SET ' .
implode(', ', $vars) . ' WHERE ' .
$this->_makeWhere();
$stmt = $this->_dbh->prepare($query);
$res = $this->_dbh->execute($stmt, $params);
if (DB::isError($res)) {
return $res;
}
$this->_changes = array();
}
return DB_OK;
}
// }}}
// {{{ remove()
/**
* Remove the row represented by this object from the database.
*
* @return mixed DB_OK or a DB error
*/
function remove()
{
if ($this->_readonly) {
return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
null, null, null, true);
}
$query = 'DELETE FROM ' . $this->_table .' WHERE '.
$this->_makeWhere();
$res = $this->_dbh->query($query);
if (DB::isError($res)) {
return $res;
}
foreach ($this->_properties as $prop => $foo) {
unset($this->$prop);
}
$this->_properties = array();
$this->_changes = array();
return DB_OK;
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

942
lib/pear/DB/sybase.php Normal file
View File

@@ -0,0 +1,942 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The PEAR DB driver for PHP's sybase extension
* for interacting with Sybase databases
*
* 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 Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
* @author Ant<6E>nio Carlos Ven<65>ncio J<>nior <floripa@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: sybase.php,v 1.85 2007/02/06 07:35:07 aharvey Exp $
* @link http://pear.php.net/package/DB
*/
/**
* Obtain the DB_common class so it can be extended from
*/
require_once 'DB/common.php';
/**
* The methods PEAR DB uses to interact with PHP's sybase extension
* for interacting with Sybase databases
*
* These methods overload the ones declared in DB_common.
*
* WARNING: This driver may fail with multiple connections under the
* same user/pass/host and different databases.
*
* @category Database
* @package DB
* @author Sterling Hughes <sterling@php.net>
* @author Ant<6E>nio Carlos Ven<65>ncio J<>nior <floripa@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.7.11
* @link http://pear.php.net/package/DB
*/
class DB_sybase extends DB_common
{
// {{{ properties
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'sybase';
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'sybase';
/**
* The capabilities of this DB implementation
*
* The 'new_link' element contains the PHP version that first provided
* new_link support for this DBMS. Contains false if it's unsupported.
*
* Meaning of the 'limit' element:
* + 'emulate' = emulate with fetch row by number
* + 'alter' = alter the query
* + false = skip rows
*
* @var array
*/
var $features = array(
'limit' => 'emulate',
'new_link' => false,
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => false,
'transactions' => true,
);
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
);
/**
* The raw database connection created by PHP
* @var resource
*/
var $connection;
/**
* The DSN information for connecting to a database
* @var array
*/
var $dsn = array();
/**
* Should data manipulation queries be committed automatically?
* @var bool
* @access private
*/
var $autocommit = true;
/**
* The quantity of transactions begun
*
* {@internal While this is private, it can't actually be designated
* private in PHP 5 because it is directly accessed in the test suite.}}
*
* @var integer
* @access private
*/
var $transaction_opcount = 0;
/**
* The database specified in the DSN
*
* It's a fix to allow calls to different databases in the same script.
*
* @var string
* @access private
*/
var $_db = '';
// }}}
// {{{ constructor
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_sybase()
{
$this->DB_common();
}
// }}}
// {{{ connect()
/**
* Connect to the database server, log in and open the database
*
* Don't call this method directly. Use DB::connect() instead.
*
* PEAR DB's sybase driver supports the following extra DSN options:
* + appname The application name to use on this connection.
* Available since PEAR DB 1.7.0.
* + charset The character set to use on this connection.
* Available since PEAR DB 1.7.0.
*
* @param array $dsn the data source name
* @param bool $persistent should the connection be persistent?
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('sybase') &&
!PEAR::loadExtension('sybase_ct'))
{
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
$dsn['hostspec'] = $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost';
$dsn['password'] = !empty($dsn['password']) ? $dsn['password'] : false;
$dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : false;
$dsn['appname'] = isset($dsn['appname']) ? $dsn['appname'] : false;
$connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect';
if ($dsn['username']) {
$this->connection = @$connect_function($dsn['hostspec'],
$dsn['username'],
$dsn['password'],
$dsn['charset'],
$dsn['appname']);
} else {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
'The DSN did not contain a username.');
}
if (!$this->connection) {
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
@sybase_get_last_message());
}
if ($dsn['database']) {
if (!@sybase_select_db($dsn['database'], $this->connection)) {
return $this->raiseError(DB_ERROR_NODBSELECTED,
null, null, null,
@sybase_get_last_message());
}
$this->_db = $dsn['database'];
}
return DB_OK;
}
// }}}
// {{{ disconnect()
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @sybase_close($this->connection);
$this->connection = null;
return $ret;
}
// }}}
// {{{ simpleQuery()
/**
* Sends a query to the database server
*
* @param string the SQL query string
*
* @return mixed + a PHP result resrouce for successful SELECT queries
* + the DB_OK constant for other successful queries
* + a DB_Error object on failure
*/
function simpleQuery($query)
{
$ismanip = $this->_checkManip($query);
$this->last_query = $query;
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
}
$query = $this->modifyQuery($query);
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @sybase_query('BEGIN TRANSACTION', $this->connection);
if (!$result) {
return $this->sybaseRaiseError();
}
}
$this->transaction_opcount++;
}
$result = @sybase_query($query, $this->connection);
if (!$result) {
return $this->sybaseRaiseError();
}
if (is_resource($result)) {
return $result;
}
// Determine which queries that should return data, and which
// should return an error code only.
return $ismanip ? DB_OK : $result;
}
// }}}
// {{{ nextResult()
/**
* Move the internal sybase result pointer to the next available result
*
* @param a valid sybase result resource
*
* @access public
*
* @return true if a result is available otherwise return false
*/
function nextResult($result)
{
return false;
}
// }}}
// {{{ fetchInto()
/**
* Places a row from the result set into the given array
*
* Formating of the array and the data therein are configurable.
* See DB_result::fetchInto() for more information.
*
* This method is not meant to be called directly. Use
* DB_result::fetchInto() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result the query result resource
* @param array $arr the referenced array to put the data in
* @param int $fetchmode how the resulting array should be indexed
* @param int $rownum the row number to fetch (0 = first row)
*
* @return mixed DB_OK on success, NULL when the end of a result set is
* reached or on failure
*
* @see DB_result::fetchInto()
*/
function fetchInto($result, &$arr, $fetchmode, $rownum = null)
{
if ($rownum !== null) {
if (!@sybase_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
if (function_exists('sybase_fetch_assoc')) {
$arr = @sybase_fetch_assoc($result);
} else {
if ($arr = @sybase_fetch_array($result)) {
foreach ($arr as $key => $value) {
if (is_int($key)) {
unset($arr[$key]);
}
}
}
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @sybase_fetch_row($result);
}
if (!$arr) {
return null;
}
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
$this->_rtrimArrayValues($arr);
}
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
$this->_convertNullArrayValuesToEmpty($arr);
}
return DB_OK;
}
// }}}
// {{{ freeResult()
/**
* Deletes the result set and frees the memory occupied by the result set
*
* This method is not meant to be called directly. Use
* DB_result::free() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_result::free()
*/
function freeResult($result)
{
return is_resource($result) ? sybase_free_result($result) : false;
}
// }}}
// {{{ numCols()
/**
* Gets the number of columns in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numCols() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of columns. A DB_Error object on failure.
*
* @see DB_result::numCols()
*/
function numCols($result)
{
$cols = @sybase_num_fields($result);
if (!$cols) {
return $this->sybaseRaiseError();
}
return $cols;
}
// }}}
// {{{ numRows()
/**
* Gets the number of rows in a result set
*
* This method is not meant to be called directly. Use
* DB_result::numRows() instead. It can't be declared "protected"
* because DB_result is a separate object.
*
* @param resource $result PHP's query result resource
*
* @return int the number of rows. A DB_Error object on failure.
*
* @see DB_result::numRows()
*/
function numRows($result)
{
$rows = @sybase_num_rows($result);
if ($rows === false) {
return $this->sybaseRaiseError();
}
return $rows;
}
// }}}
// {{{ affectedRows()
/**
* Determines the number of rows affected by a data maniuplation query
*
* 0 is returned for queries that don't manipulate data.
*
* @return int the number of rows. A DB_Error object on failure.
*/
function affectedRows()
{
if ($this->_last_query_manip) {
$result = @sybase_affected_rows($this->connection);
} else {
$result = 0;
}
return $result;
}
// }}}
// {{{ nextId()
/**
* Returns the next free id in a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_sybase::createSequence(), DB_sybase::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
}
$repeat = 0;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
$this->popErrorHandling();
if ($ondemand && DB::isError($result) &&
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
{
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
}
} elseif (!DB::isError($result)) {
$result =& $this->query("SELECT @@IDENTITY FROM $seqname");
$repeat = 0;
} else {
$repeat = false;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$result = $result->fetchRow(DB_FETCHMODE_ORDERED);
return $result[0];
}
/**
* Creates a new sequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_sybase::nextID(), DB_sybase::dropSequence()
*/
function createSequence($seq_name)
{
return $this->query('CREATE TABLE '
. $this->getSequenceName($seq_name)
. ' (id numeric(10, 0) IDENTITY NOT NULL,'
. ' vapor int NULL)');
}
// }}}
// {{{ dropSequence()
/**
* Deletes a sequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_sybase::nextID(), DB_sybase::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
// }}}
// {{{ quoteFloat()
/**
* Formats a float value for use within a query in a locale-independent
* manner.
*
* @param float the float value to be quoted.
* @return string the quoted string.
* @see DB_common::quoteSmart()
* @since Method available since release 1.7.8.
*/
function quoteFloat($float) {
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
}
// }}}
// {{{ autoCommit()
/**
* Enables or disables automatic commits
*
* @param bool $onoff true turns it on, false turns it off
*
* @return int DB_OK on success. A DB_Error object if the driver
* doesn't support auto-committing transactions.
*/
function autoCommit($onoff = false)
{
// XXX if $this->transaction_opcount > 0, we should probably
// issue a warning here.
$this->autocommit = $onoff ? true : false;
return DB_OK;
}
// }}}
// {{{ commit()
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
if ($this->transaction_opcount > 0) {
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
}
$result = @sybase_query('COMMIT', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->sybaseRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ rollback()
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
if ($this->transaction_opcount > 0) {
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
}
$result = @sybase_query('ROLLBACK', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->sybaseRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ sybaseRaiseError()
/**
* Produces a DB_Error object regarding the current problem
*
* @param int $errno if the error is being manually raised pass a
* DB_ERROR* constant here. If this isn't passed
* the error information gathered from the DBMS.
*
* @return object the DB_Error object
*
* @see DB_common::raiseError(),
* DB_sybase::errorNative(), DB_sybase::errorCode()
*/
function sybaseRaiseError($errno = null)
{
$native = $this->errorNative();
if ($errno === null) {
$errno = $this->errorCode($native);
}
return $this->raiseError($errno, null, null, null, $native);
}
// }}}
// {{{ errorNative()
/**
* Gets the DBMS' native error message produced by the last query
*
* @return string the DBMS' error message
*/
function errorNative()
{
return @sybase_get_last_message();
}
// }}}
// {{{ errorCode()
/**
* Determines PEAR::DB error code from the database's text error message.
*
* @param string $errormsg error message returned from the database
* @return integer an error number from a DB error constant
*/
function errorCode($errormsg)
{
static $error_regexps;
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
// this hack to work around it, per bug #9599.
$errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg);
if (!isset($error_regexps)) {
$error_regexps = array(
'/Incorrect syntax near/'
=> DB_ERROR_SYNTAX,
'/^Unclosed quote before the character string [\"\'].*[\"\']\./'
=> DB_ERROR_SYNTAX,
'/Implicit conversion (from datatype|of NUMERIC value)/i'
=> DB_ERROR_INVALID_NUMBER,
'/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
=> DB_ERROR_NOSUCHTABLE,
'/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
=> DB_ERROR_ACCESS_VIOLATION,
'/^.+ permission denied on object .+, database .+, owner .+/'
=> DB_ERROR_ACCESS_VIOLATION,
'/^.* permission denied, database .+, owner .+/'
=> DB_ERROR_ACCESS_VIOLATION,
'/[^.*] not found\./'
=> DB_ERROR_NOSUCHTABLE,
'/There is already an object named/'
=> DB_ERROR_ALREADY_EXISTS,
'/Invalid column name/'
=> DB_ERROR_NOSUCHFIELD,
'/does not allow null values/'
=> DB_ERROR_CONSTRAINT_NOT_NULL,
'/Command has been aborted/'
=> DB_ERROR_CONSTRAINT,
'/^Cannot drop the index .* because it doesn\'t exist/i'
=> DB_ERROR_NOT_FOUND,
'/^There is already an index/i'
=> DB_ERROR_ALREADY_EXISTS,
'/^There are fewer columns in the INSERT statement than values specified/i'
=> DB_ERROR_VALUE_COUNT_ON_ROW,
'/Divide by zero/i'
=> DB_ERROR_DIVZERO,
);
}
foreach ($error_regexps as $regexp => $code) {
if (preg_match($regexp, $errormsg)) {
return $code;
}
}
return DB_ERROR;
}
// }}}
// {{{ tableInfo()
/**
* Returns information about a table or a result set
*
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.6.0
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
}
$id = @sybase_query("SELECT * FROM $result WHERE 1=0",
$this->connection);
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = @sybase_num_fields($id);
$res = array();
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$f = @sybase_fetch_field($id, $i);
// column_source is often blank
$res[$i] = array(
'table' => $got_string
? $case_func($result)
: $case_func($f->column_source),
'name' => $case_func($f->name),
'type' => $f->type,
'len' => $f->max_length,
'flags' => '',
);
if ($res[$i]['table']) {
$res[$i]['flags'] = $this->_sybase_field_flags(
$res[$i]['table'], $res[$i]['name']);
}
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
// free the result only if we were called on a table
if ($got_string) {
@sybase_free_result($id);
}
return $res;
}
// }}}
// {{{ _sybase_field_flags()
/**
* Get the flags for a field
*
* Currently supports:
* + <samp>unique_key</samp> (unique index, unique check or primary_key)
* + <samp>multiple_key</samp> (multi-key index)
*
* @param string $table the table name
* @param string $column the field name
*
* @return string space delimited string of flags. Empty string if none.
*
* @access private
*/
function _sybase_field_flags($table, $column)
{
static $tableName = null;
static $flags = array();
if ($table != $tableName) {
$flags = array();
$tableName = $table;
/* We're running sp_helpindex directly because it doesn't exist in
* older versions of ASE -- unfortunately, we can't just use
* DB::isError() because the user may be using callback error
* handling. */
$res = @sybase_query("sp_helpindex $table", $this->connection);
if ($res === false || $res === true) {
// Fake a valid response for BC reasons.
return '';
}
while (($val = sybase_fetch_assoc($res)) !== false) {
if (!isset($val['index_keys'])) {
/* No useful information returned. Break and be done with
* it, which preserves the pre-1.7.9 behaviour. */
break;
}
$keys = explode(', ', trim($val['index_keys']));
if (sizeof($keys) > 1) {
foreach ($keys as $key) {
$this->_add_flag($flags[$key], 'multiple_key');
}
}
if (strpos($val['index_description'], 'unique')) {
foreach ($keys as $key) {
$this->_add_flag($flags[$key], 'unique_key');
}
}
}
sybase_free_result($res);
}
if (array_key_exists($column, $flags)) {
return(implode(' ', $flags[$column]));
}
return '';
}
// }}}
// {{{ _add_flag()
/**
* Adds a string to the flags array if the flag is not yet in there
* - if there is no flag present the array is created
*
* @param array $array reference of flags array to add a value to
* @param mixed $value value to add to the flag array
*
* @return void
*
* @access private
*/
function _add_flag(&$array, $value)
{
if (!is_array($array)) {
$array = array($value);
} elseif (!in_array($value, $array)) {
array_push($array, $value);
}
}
// }}}
// {{{ getSpecialQuery()
/**
* Obtains the query string needed for listing a given type of objects
*
* @param string $type the kind of objects you want to retrieve
*
* @return string the SQL query string or null if the driver doesn't
* support the object type requested
*
* @access protected
* @see DB_common::getListOf()
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'tables':
return "SELECT name FROM sysobjects WHERE type = 'U'"
. ' ORDER BY name';
case 'views':
return "SELECT name FROM sysobjects WHERE type = 'V'";
default:
return null;
}
}
// }}}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

1005
lib/pear/Mail/mime.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,849 @@
<?php
/**
* The Mail_mimeDecode class is used to decode mail/mime messages
*
* This class will parse a raw mime email and return
* the structure. Returned structure is similar to
* that returned by imap_fetchstructure().
*
* +----------------------------- IMPORTANT ------------------------------+
* | Usage of this class compared to native php extensions such as |
* | mailparse or imap, is slow and may be feature deficient. If available|
* | you are STRONGLY recommended to use the php extensions. |
* +----------------------------------------------------------------------+
*
* 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 George Schlossnagle <george@omniti.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 CVS: $Id: mimeDecode.php,v 1.48 2006/12/03 13:43:33 cipri Exp $
* @link http://pear.php.net/package/Mail_mime
*/
/**
* require PEAR
*
* This package depends on PEAR to raise errors.
*/
require_once 'PEAR.php';
/**
* The Mail_mimeDecode class is used to decode mail/mime messages
*
* This class will parse a raw mime email and return the structure.
* Returned structure is similar to that returned by imap_fetchstructure().
*
* +----------------------------- IMPORTANT ------------------------------+
* | Usage of this class compared to native php extensions such as |
* | mailparse or imap, is slow and may be feature deficient. If available|
* | you are STRONGLY recommended to use the php extensions. |
* +----------------------------------------------------------------------+
*
* @category Mail
* @package Mail_Mime
* @author Richard Heyes <richard@phpguru.org>
* @author George Schlossnagle <george@omniti.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_mimeDecode extends PEAR
{
/**
* The raw email to decode
*
* @var string
* @access private
*/
var $_input;
/**
* The header part of the input
*
* @var string
* @access private
*/
var $_header;
/**
* The body part of the input
*
* @var string
* @access private
*/
var $_body;
/**
* If an error occurs, this is used to store the message
*
* @var string
* @access private
*/
var $_error;
/**
* Flag to determine whether to include bodies in the
* returned object.
*
* @var boolean
* @access private
*/
var $_include_bodies;
/**
* Flag to determine whether to decode bodies
*
* @var boolean
* @access private
*/
var $_decode_bodies;
/**
* Flag to determine whether to decode headers
*
* @var boolean
* @access private
*/
var $_decode_headers;
/**
* Constructor.
*
* Sets up the object, initialise the variables, and splits and
* stores the header and body of the input.
*
* @param string The input to decode
* @access public
*/
function Mail_mimeDecode($input)
{
list($header, $body) = $this->_splitBodyHeader($input);
$this->_input = $input;
$this->_header = $header;
$this->_body = $body;
$this->_decode_bodies = false;
$this->_include_bodies = true;
}
/**
* Begins the decoding process. If called statically
* it will create an object and call the decode() method
* of it.
*
* @param array An array of various parameters that determine
* various things:
* include_bodies - Whether to include the body in the returned
* object.
* decode_bodies - Whether to decode the bodies
* of the parts. (Transfer encoding)
* decode_headers - Whether to decode headers
* input - If called statically, this will be treated
* as the input
* @return object Decoded results
* @access public
*/
function decode($params = null)
{
// determine if this method has been called statically
$isStatic = !(isset($this) && get_class($this) == __CLASS__);
// Have we been called statically?
// If so, create an object and pass details to that.
if ($isStatic AND isset($params['input'])) {
$obj = new Mail_mimeDecode($params['input']);
$structure = $obj->decode($params);
// Called statically but no input
} elseif ($isStatic) {
return PEAR::raiseError('Called statically and no input given');
// Called via an object
} else {
$this->_include_bodies = isset($params['include_bodies']) ?
$params['include_bodies'] : false;
$this->_decode_bodies = isset($params['decode_bodies']) ?
$params['decode_bodies'] : false;
$this->_decode_headers = isset($params['decode_headers']) ?
$params['decode_headers'] : false;
$structure = $this->_decode($this->_header, $this->_body);
if ($structure === false) {
$structure = $this->raiseError($this->_error);
}
}
return $structure;
}
/**
* Performs the decoding. Decodes the body string passed to it
* If it finds certain content-types it will call itself in a
* recursive fashion
*
* @param string Header section
* @param string Body section
* @return object Results of decoding process
* @access private
*/
function _decode($headers, $body, $default_ctype = 'text/plain')
{
$return = new stdClass;
$return->headers = array();
$headers = $this->_parseHeaders($headers);
foreach ($headers as $value) {
if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
$return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
$return->headers[strtolower($value['name'])][] = $value['value'];
} elseif (isset($return->headers[strtolower($value['name'])])) {
$return->headers[strtolower($value['name'])][] = $value['value'];
} else {
$return->headers[strtolower($value['name'])] = $value['value'];
}
}
reset($headers);
while (list($key, $value) = each($headers)) {
$headers[$key]['name'] = strtolower($headers[$key]['name']);
switch ($headers[$key]['name']) {
case 'content-type':
$content_type = $this->_parseHeaderValue($headers[$key]['value']);
if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
$return->ctype_primary = $regs[1];
$return->ctype_secondary = $regs[2];
}
if (isset($content_type['other'])) {
while (list($p_name, $p_value) = each($content_type['other'])) {
$return->ctype_parameters[$p_name] = $p_value;
}
}
break;
case 'content-disposition':
$content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
$return->disposition = $content_disposition['value'];
if (isset($content_disposition['other'])) {
while (list($p_name, $p_value) = each($content_disposition['other'])) {
$return->d_parameters[$p_name] = $p_value;
}
}
break;
case 'content-transfer-encoding':
$content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']);
break;
}
}
if (isset($content_type)) {
switch (strtolower($content_type['value'])) {
case 'text/plain':
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
break;
case 'text/html':
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
break;
case 'multipart/parallel':
case 'multipart/appledouble': // Appledouble mail
case 'multipart/report': // RFC1892
case 'multipart/signed': // PGP
case 'multipart/digest':
case 'multipart/alternative':
case 'multipart/related':
case 'multipart/mixed':
if(!isset($content_type['other']['boundary'])){
$this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
return false;
}
$default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
$parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
for ($i = 0; $i < count($parts); $i++) {
list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
$part = $this->_decode($part_header, $part_body, $default_ctype);
if($part === false)
$part = $this->raiseError($this->_error);
$return->parts[] = $part;
}
break;
case 'message/rfc822':
$obj = &new Mail_mimeDecode($body);
$return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
'decode_bodies' => $this->_decode_bodies,
'decode_headers' => $this->_decode_headers));
unset($obj);
break;
default:
if(!isset($content_transfer_encoding['value']))
$content_transfer_encoding['value'] = '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
break;
}
} else {
$ctype = explode('/', $default_ctype);
$return->ctype_primary = $ctype[0];
$return->ctype_secondary = $ctype[1];
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
}
return $return;
}
/**
* Given the output of the above function, this will return an
* array of references to the parts, indexed by mime number.
*
* @param object $structure The structure to go through
* @param string $mime_number Internal use only.
* @return array Mime numbers
*/
function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '')
{
$return = array();
if (!empty($structure->parts)) {
if ($mime_number != '') {
$structure->mime_id = $prepend . $mime_number;
$return[$prepend . $mime_number] = &$structure;
}
for ($i = 0; $i < count($structure->parts); $i++) {
if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
$prepend = $prepend . $mime_number . '.';
$_mime_number = '';
} else {
$_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
}
$arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend);
foreach ($arr as $key => $val) {
$no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key];
}
}
} else {
if ($mime_number == '') {
$mime_number = '1';
}
$structure->mime_id = $prepend . $mime_number;
$no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
}
return $return;
}
/**
* Given a string containing a header and body
* section, this function will split them (at the first
* blank line) and return them.
*
* @param string Input to split apart
* @return array Contains header and body section
* @access private
*/
function _splitBodyHeader($input)
{
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
return array($match[1], $match[2]);
}
$this->_error = 'Could not split header and body';
return false;
}
/**
* Parse headers given in $input and return
* as assoc array.
*
* @param string Headers to parse
* @return array Contains parsed headers
* @access private
*/
function _parseHeaders($input)
{
if ($input !== '') {
// Unfold the input
$input = preg_replace("/\r?\n/", "\r\n", $input);
$input = preg_replace("/\r\n(\t| )+/", ' ', $input);
$headers = explode("\r\n", trim($input));
foreach ($headers as $value) {
$hdr_name = substr($value, 0, $pos = strpos($value, ':'));
$hdr_value = substr($value, $pos+1);
if($hdr_value[0] == ' ')
$hdr_value = substr($hdr_value, 1);
$return[] = array(
'name' => $hdr_name,
'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value
);
}
} else {
$return = array();
}
return $return;
}
/**
* Function to parse a header value,
* extract first part, and any secondary
* parts (after ;) This function is not as
* robust as it could be. Eg. header comments
* in the wrong place will probably break it.
*
* @param string Header value to parse
* @return array Contains parsed result
* @access private
*/
function _parseHeaderValue($input)
{
if (($pos = strpos($input, ';')) !== false) {
$return['value'] = trim(substr($input, 0, $pos));
$input = trim(substr($input, $pos+1));
if (strlen($input) > 0) {
// This splits on a semi-colon, if there's no preceeding backslash
// Now works with quoted values; had to glue the \; breaks in PHP
// the regex is already bordering on incomprehensible
$splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/';
preg_match_all($splitRegex, $input, $matches);
$parameters = array();
for ($i=0; $i<count($matches[0]); $i++) {
$param = $matches[0][$i];
while (substr($param, -2) == '\;') {
$param .= $matches[0][++$i];
}
$parameters[] = $param;
}
for ($i = 0; $i < count($parameters); $i++) {
$param_name = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ ");
$param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ ");
if ($param_value[0] == '"') {
$param_value = substr($param_value, 1, -1);
}
$return['other'][$param_name] = $param_value;
$return['other'][strtolower($param_name)] = $param_value;
}
}
} else {
$return['value'] = trim($input);
}
return $return;
}
/**
* This function splits the input based
* on the given boundary
*
* @param string Input to parse
* @return array Contains array of resulting mime parts
* @access private
*/
function _boundarySplit($input, $boundary)
{
$parts = array();
$bs_possible = substr($boundary, 2, -2);
$bs_check = '\"' . $bs_possible . '\"';
if ($boundary == $bs_check) {
$boundary = $bs_possible;
}
$tmp = explode('--' . $boundary, $input);
for ($i = 1; $i < count($tmp) - 1; $i++) {
$parts[] = $tmp[$i];
}
return $parts;
}
/**
* Given a header, this function will decode it
* according to RFC2047. Probably not *exactly*
* conformant, but it does pass all the given
* examples (in RFC2047).
*
* @param string Input header value to decode
* @return string Decoded header value
* @access private
*/
function _decodeHeader($input)
{
// Remove white space between encoded-words
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
// For each encoded-word...
while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
$encoded = $matches[1];
$charset = $matches[2];
$encoding = $matches[3];
$text = $matches[4];
switch (strtolower($encoding)) {
case 'b':
$text = base64_decode($text);
break;
case 'q':
$text = str_replace('_', ' ', $text);
preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
foreach($matches[1] as $value)
$text = str_replace('='.$value, chr(hexdec($value)), $text);
break;
}
$input = str_replace($encoded, $text, $input);
}
return $input;
}
/**
* Given a body string and an encoding type,
* this function will decode and return it.
*
* @param string Input body to decode
* @param string Encoding type to use.
* @return string Decoded body
* @access private
*/
function _decodeBody($input, $encoding = '7bit')
{
switch (strtolower($encoding)) {
case '7bit':
return $input;
break;
case 'quoted-printable':
return $this->_quotedPrintableDecode($input);
break;
case 'base64':
return base64_decode($input);
break;
default:
return $input;
}
}
/**
* Given a quoted-printable string, this
* function will decode and return it.
*
* @param string Input body to decode
* @return string Decoded body
* @access private
*/
function _quotedPrintableDecode($input)
{
// Remove soft line breaks
$input = preg_replace("/=\r?\n/", '', $input);
// Replace encoded characters
$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
return $input;
}
/**
* Checks the input for uuencoded files and returns
* an array of them. Can be called statically, eg:
*
* $files =& Mail_mimeDecode::uudecode($some_text);
*
* It will check for the begin 666 ... end syntax
* however and won't just blindly decode whatever you
* pass it.
*
* @param string Input body to look for attahcments in
* @return array Decoded bodies, filenames and permissions
* @access public
* @author Unknown
*/
function &uudecode($input)
{
// Find all uuencoded sections
preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);
for ($j = 0; $j < count($matches[3]); $j++) {
$str = $matches[3][$j];
$filename = $matches[2][$j];
$fileperm = $matches[1][$j];
$file = '';
$str = preg_split("/\r?\n/", trim($str));
$strlen = count($str);
for ($i = 0; $i < $strlen; $i++) {
$pos = 1;
$d = 0;
$len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);
while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
$file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
$file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077));
$pos += 4;
$d += 3;
}
if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
$file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
$pos += 3;
$d += 2;
}
if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
}
}
$files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
}
return $files;
}
/**
* getSendArray() returns the arguments required for Mail::send()
* used to build the arguments for a mail::send() call
*
* Usage:
* $mailtext = Full email (for example generated by a template)
* $decoder = new Mail_mimeDecode($mailtext);
* $parts = $decoder->getSendArray();
* if (!PEAR::isError($parts) {
* list($recipents,$headers,$body) = $parts;
* $mail = Mail::factory('smtp');
* $mail->send($recipents,$headers,$body);
* } else {
* echo $parts->message;
* }
* @return mixed array of recipeint, headers,body or Pear_Error
* @access public
* @author Alan Knowles <alan@akbkhome.com>
*/
function getSendArray()
{
// prevent warning if this is not set
$this->_decode_headers = FALSE;
$headerlist =$this->_parseHeaders($this->_header);
$to = "";
if (!$headerlist) {
return $this->raiseError("Message did not contain headers");
}
foreach($headerlist as $item) {
$header[$item['name']] = $item['value'];
switch (strtolower($item['name'])) {
case "to":
case "cc":
case "bcc":
$to = ",".$item['value'];
default:
break;
}
}
if ($to == "") {
return $this->raiseError("Message did not contain any recipents");
}
$to = substr($to,1);
return array($to,$header,$this->_body);
}
/**
* Returns a xml copy of the output of
* Mail_mimeDecode::decode. Pass the output in as the
* argument. This function can be called statically. Eg:
*
* $output = $obj->decode();
* $xml = Mail_mimeDecode::getXML($output);
*
* The DTD used for this should have been in the package. Or
* alternatively you can get it from cvs, or here:
* http://www.phpguru.org/xmail/xmail.dtd.
*
* @param object Input to convert to xml. This should be the
* output of the Mail_mimeDecode::decode function
* @return string XML version of input
* @access public
*/
function getXML($input)
{
$crlf = "\r\n";
$output = '<?xml version=\'1.0\'?>' . $crlf .
'<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
'<email>' . $crlf .
Mail_mimeDecode::_getXML($input) .
'</email>';
return $output;
}
/**
* Function that does the actual conversion to xml. Does a single
* mimepart at a time.
*
* @param object Input to convert to xml. This is a mimepart object.
* It may or may not contain subparts.
* @param integer Number of tabs to indent
* @return string XML version of input
* @access private
*/
function _getXML($input, $indent = 1)
{
$htab = "\t";
$crlf = "\r\n";
$output = '';
$headers = @(array)$input->headers;
foreach ($headers as $hdr_name => $hdr_value) {
// Multiple headers with this name
if (is_array($headers[$hdr_name])) {
for ($i = 0; $i < count($hdr_value); $i++) {
$output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
}
// Only one header of this sort
} else {
$output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
}
}
if (!empty($input->parts)) {
for ($i = 0; $i < count($input->parts); $i++) {
$output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) .
str_repeat($htab, $indent) . '</mimepart>' . $crlf;
}
} elseif (isset($input->body)) {
$output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
$input->body . ']]></body>' . $crlf;
}
return $output;
}
/**
* Helper function to _getXML(). Returns xml of a header.
*
* @param string Name of header
* @param string Value of header
* @param integer Number of tabs to indent
* @return string XML version of input
* @access private
*/
function _getXML_helper($hdr_name, $hdr_value, $indent)
{
$htab = "\t";
$crlf = "\r\n";
$return = '';
$new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
$new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));
// Sort out any parameters
if (!empty($new_hdr_value['other'])) {
foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
$params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
}
$params = implode('', $params);
} else {
$params = '';
}
$return = str_repeat($htab, $indent) . '<header>' . $crlf .
str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
$params .
str_repeat($htab, $indent) . '</header>' . $crlf;
return $return;
}
} // End of class

341
lib/pear/Mail/mimePart.php Normal file
View File

@@ -0,0 +1,341 @@
<?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>
* @copyright 2003-2006 PEAR <pear-group@php.net>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version CVS: $Id: mimePart.php,v 1.19 2006/12/03 20:22:48 cipri Exp $
* @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>
* @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;
/**
* Constructor.
*
* Sets up the object.
*
* @param $body - The body of the mime part if any.
* @param $params - An associative array of parameters:
* content_type - The content type for this part eg multipart/mixed
* encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable
* cid - Content ID to apply
* disposition - Content disposition, inline or attachment
* dfilename - Optional filename parameter for content disposition
* description - Content description
* charset - Character set to use
* @access public
*/
function Mail_mimePart($body = '', $params = array())
{
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
}
foreach ($params as $key => $value) {
switch ($key) {
case 'content_type':
$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
break;
case 'encoding':
$this->_encoding = $value;
$headers['Content-Transfer-Encoding'] = $value;
break;
case 'cid':
$headers['Content-ID'] = '<' . $value . '>';
break;
case 'disposition':
$headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
break;
case 'dfilename':
if (isset($headers['Content-Disposition'])) {
$headers['Content-Disposition'] .= '; filename="' . $value . '"';
} else {
$dfilename = $value;
}
break;
case 'description':
$headers['Content-Description'] = $value;
break;
case 'charset':
if (isset($headers['Content-Type'])) {
$headers['Content-Type'] .= '; charset="' . $value . '"';
} else {
$charset = $value;
}
break;
}
}
// Default content-type
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'text/plain';
}
//Default encoding
if (!isset($this->_encoding)) {
$this->_encoding = '7bit';
}
// Assign stuff to member variables
$this->_encoded = array();
$this->_headers = $headers;
$this->_body = $body;
}
/**
* encode()
*
* Encodes and returns the email. Also stores
* it in the encoded member variable
*
* @return An associative array containing two elements,
* body and headers. The headers element is itself
* an indexed array.
* @access public
*/
function encode()
{
$encoded =& $this->_encoded;
if (!empty($this->_subparts)) {
srand((double)microtime()*1000000);
$boundary = '=_' . md5(rand() . microtime());
$this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';
// Add body parts to $subparts
for ($i = 0; $i < count($this->_subparts); $i++) {
$headers = array();
$tmp = $this->_subparts[$i]->encode();
foreach ($tmp['headers'] as $key => $value) {
$headers[] = $key . ': ' . $value;
}
$subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
}
$encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
'--' . $boundary.'--' . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF;
} else {
$encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;
}
// Add headers to $encoded
$encoded['headers'] =& $this->_headers;
return $encoded;
}
/**
* &addSubPart()
*
* Adds a subpart to current mime part and returns
* a reference to it
*
* @param $body The body of the subpart, if any.
* @param $params The parameters for the subpart, same
* as the $params argument for constructor.
* @return A reference to the part you just added. 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[] = new Mail_mimePart($body, $params);
return $this->_subparts[count($this->_subparts) - 1];
}
/**
* _getEncodedData()
*
* Returns encoded data based upon encoding passed to it
*
* @param $data The data to encode.
* @param $encoding The encoding type to use, 7bit, base64,
* or quoted-printable.
* @access private
*/
function _getEncodedData($data, $encoding)
{
switch ($encoding) {
case '8bit':
case '7bit':
return $data;
break;
case 'quoted-printable':
return $this->_quotedPrintableEncode($data);
break;
case 'base64':
return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
break;
default:
return $data;
}
}
/**
* quotedPrintableEncode()
*
* Encodes data to quoted-printable standard.
*
* @param $input The data to encode
* @param $line_max Optional max line length. Should
* not be more than 76 chars
*
* @access private
*/
function _quotedPrintableEncode($input , $line_max = 76)
{
$lines = preg_split("/\r?\n/", $input);
$eol = MAIL_MIMEPART_CRLF;
$escape = '=';
$output = '';
while(list(, $line) = each($lines)){
$line = preg_split('||', $line, -1, PREG_SPLIT_NO_EMPTY);
$linlen = count($line);
$newline = '';
for ($i = 0; $i < $linlen; $i++) {
$char = $line[$i];
$dec = ord($char);
if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only
$char = '=20';
} elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only
$char = '=09';
} elseif($dec == 9) {
; // Do nothing if a tab.
} elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
$char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
}
if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted
$output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay
$newline = '';
}
$newline .= $char;
} // end of for
$output .= $newline . $eol;
}
$output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
return $output;
}
} // End of class

528
lib/pear/Net/Socket.php Normal file
View File

@@ -0,0 +1,528 @@
<?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.24 2005/02/03 20:40:16 chagenbu Exp $
require_once 'PEAR.php';
define('NET_SOCKET_READ', 1);
define('NET_SOCKET_WRITE', 2);
define('NET_SOCKET_ERROR', 3);
/**
* 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 = '';
if ($options && function_exists('stream_context_create')) {
if ($this->timeout) {
$timeout = $this->timeout;
} else {
$timeout = 0;
}
$context = stream_context_create($options);
$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) {
return $this->raiseError($errstr, $errno);
}
$this->fp = $fp;
return $this->setBlocking($this->blocking);
}
/**
* Disconnects from the peer, closes the socket.
*
* @access public
* @return mixed true on success or an error object 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 an error object 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 an error object otherwise
*/
function setTimeout($seconds, $microseconds)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}
return socket_set_timeout($this->fp, $seconds, $microseconds);
}
/**
* 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 an error object 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 true on success or an error object otherwise
*/
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.
*
* @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 formated string
*
* @access public
* @return Dot formated 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("%s.%s.%s.%s", 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;
}
}

345
lib/pear/OS/Guess.php Normal file
View File

@@ -0,0 +1,345 @@
<?php
/**
* The OS_Guess 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 Gregory Beaver <cellog@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Guess.php,v 1.20.2.1 2006/06/16 11:41:16 pajoye Exp $
* @link http://pear.php.net/package/PEAR
* @since File available since PEAR 0.1
*/
// {{{ uname examples
// php_uname() without args returns the same as 'uname -a', or a PHP-custom
// string for Windows.
// PHP versions prior to 4.3 return the uname of the host where PHP was built,
// as of 4.3 it returns the uname of the host running the PHP code.
//
// PC RedHat Linux 7.1:
// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
//
// PC Debian Potato:
// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
//
// PC FreeBSD 3.3:
// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
//
// PC FreeBSD 4.3:
// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
//
// PC FreeBSD 4.5:
// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
//
// PC FreeBSD 4.5 w/uname from GNU shellutils:
// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
//
// HP 9000/712 HP-UX 10:
// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
//
// HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
// HP-UX host B.10.10 A 9000/712 unknown
//
// IBM RS6000/550 AIX 4.3:
// AIX host 3 4 000003531C00
//
// AIX 4.3 w/uname from GNU shellutils:
// AIX host 3 4 000003531C00 unknown
//
// SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
// IRIX64 host 6.5 01091820 IP19 mips
//
// SGI Onyx IRIX 6.5:
// IRIX64 host 6.5 01091820 IP19
//
// SparcStation 20 Solaris 8 w/uname from GNU shellutils:
// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
//
// SparcStation 20 Solaris 8:
// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
//
// Mac OS X (Darwin)
// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
//
// Mac OS X early versions
//
// }}}
/* TODO:
* - define endianness, to allow matchSignature("bigend") etc.
*/
/**
* Retrieves information about the current operating system
*
* This class uses php_uname() to grok information about the current OS
*
* @category pear
* @package PEAR
* @author Stig Bakken <ssb@php.net>
* @author Gregory Beaver <cellog@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @link http://pear.php.net/package/PEAR
* @since Class available since Release 0.1
*/
class OS_Guess
{
var $sysname;
var $nodename;
var $cpu;
var $release;
var $extra;
function OS_Guess($uname = null)
{
list($this->sysname,
$this->release,
$this->cpu,
$this->extra,
$this->nodename) = $this->parseSignature($uname);
}
function parseSignature($uname = null)
{
static $sysmap = array(
'HP-UX' => 'hpux',
'IRIX64' => 'irix',
);
static $cpumap = array(
'i586' => 'i386',
'i686' => 'i386',
'ppc' => 'powerpc',
);
if ($uname === null) {
$uname = php_uname();
}
$parts = split('[[:space:]]+', trim($uname));
$n = count($parts);
$release = $machine = $cpu = '';
$sysname = $parts[0];
$nodename = $parts[1];
$cpu = $parts[$n-1];
$extra = '';
if ($cpu == 'unknown') {
$cpu = $parts[$n-2];
}
switch ($sysname) {
case 'AIX' :
$release = "$parts[3].$parts[2]";
break;
case 'Windows' :
switch ($parts[1]) {
case '95/98':
$release = '9x';
break;
default:
$release = $parts[1];
break;
}
$cpu = 'i386';
break;
case 'Linux' :
$extra = $this->_detectGlibcVersion();
// use only the first two digits from the kernel version
$release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
break;
case 'Mac' :
$sysname = 'darwin';
$nodename = $parts[2];
$release = $parts[3];
if ($cpu == 'Macintosh') {
if ($parts[$n - 2] == 'Power') {
$cpu = 'powerpc';
}
}
break;
case 'Darwin' :
if ($cpu == 'Macintosh') {
if ($parts[$n - 2] == 'Power') {
$cpu = 'powerpc';
}
}
$release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
break;
default:
$release = ereg_replace('-.*', '', $parts[2]);
break;
}
if (isset($sysmap[$sysname])) {
$sysname = $sysmap[$sysname];
} else {
$sysname = strtolower($sysname);
}
if (isset($cpumap[$cpu])) {
$cpu = $cpumap[$cpu];
}
return array($sysname, $release, $cpu, $extra, $nodename);
}
function _detectGlibcVersion()
{
static $glibc = false;
if ($glibc !== false) {
return $glibc; // no need to run this multiple times
}
include_once "System.php";
if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
// Use glibc's <features.h> header file to
// get major and minor version number:
if (@file_exists('/usr/include/features.h') &&
@is_readable('/usr/include/features.h')) {
$features_file = fopen('/usr/include/features.h', 'rb');
while (!feof($features_file)) {
$line = fgets($features_file, 8192);
if (!$line || (strpos($line, '#define') === false)) {
continue;
}
if (strpos($line, '__GLIBC__')) {
// major version number #define __GLIBC__ version
$line = preg_split('/\s+/', $line);
$glibc_major = trim($line[2]);
if (isset($glibc_minor)) {
break;
}
continue;
}
if (strpos($line, '__GLIBC_MINOR__')) {
// got the minor version number
// #define __GLIBC_MINOR__ version
$line = preg_split('/\s+/', $line);
$glibc_minor = trim($line[2]);
if (isset($glibc_major)) {
break;
}
continue;
}
}
fclose($features_file);
if (!isset($glibc_major) || !isset($glibc_minor)) {
return $glibc = '';
}
return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
}
return $glibc = '';
}
$tmpfile = System::mktemp("glibctest");
$fp = fopen($tmpfile, "w");
fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
fclose($fp);
$cpp = popen("/usr/bin/cpp $tmpfile", "r");
$major = $minor = 0;
while ($line = fgets($cpp, 1024)) {
if ($line{0} == '#' || trim($line) == '') {
continue;
}
if (list($major, $minor) = explode(' ', trim($line))) {
break;
}
}
pclose($cpp);
unlink($tmpfile);
if (!($major && $minor) && is_link('/lib/libc.so.6')) {
// Let's try reading the libc.so.6 symlink
if (ereg('^libc-([.*])\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
list($major, $minor) = explode('.', $matches);
}
}
if (!($major && $minor)) {
return $glibc = '';
}
return $glibc = "glibc{$major}.{$minor}";
}
function getSignature()
{
if (empty($this->extra)) {
return "{$this->sysname}-{$this->release}-{$this->cpu}";
}
return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
}
function getSysname()
{
return $this->sysname;
}
function getNodename()
{
return $this->nodename;
}
function getCpu()
{
return $this->cpu;
}
function getRelease()
{
return $this->release;
}
function getExtra()
{
return $this->extra;
}
function matchSignature($match)
{
if (is_array($match)) {
$fragments = $match;
} else {
$fragments = explode('-', $match);
}
$n = count($fragments);
$matches = 0;
if ($n > 0) {
$matches += $this->_matchFragment($fragments[0], $this->sysname);
}
if ($n > 1) {
$matches += $this->_matchFragment($fragments[1], $this->release);
}
if ($n > 2) {
$matches += $this->_matchFragment($fragments[2], $this->cpu);
}
if ($n > 3) {
$matches += $this->_matchFragment($fragments[3], $this->extra);
}
return ($matches == $n);
}
function _matchFragment($fragment, $value)
{
if (strcspn($fragment, '*?') < strlen($fragment)) {
$reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
return eregi($reg, $value);
}
return ($fragment == '*' || !strcasecmp($fragment, $value));
}
}
/*
* Local Variables:
* indent-tabs-mode: nil
* c-basic-offset: 4
* End:
*/
?>

1101
lib/pear/PEAR.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Autoloader.php,v 1.13 2006/01/06 04:47:36 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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");
?>

455
lib/pear/PEAR/Builder.php Normal file
View File

@@ -0,0 +1,455 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Builder.php,v 1.27 2006/01/06 04:47:36 cellog Exp $
* @link http://pear.php.net/package/PEAR
* @since File available since Release 0.1
*/
/**
* 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 $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;
} else {
$pf = &new PEAR_PackageFile($this->config, $this->debug);
$pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
if (PEAR::isError($pkg)) {
return $pkg;
}
}
$dir = dirname($pkg->getArchiveFile());
$old_cwd = getcwd();
if (!@chdir($dir)) {
return $this->raiseError("could not chdir to $dir");
}
$this->log(2, "building in $dir");
$dsp = $pkg->getPackage().'.dsp';
if (!@is_file("$dir/$dsp")) {
return $this->raiseError("The DSP $dsp does not exist.");
}
// XXX TODO: make release build type configurable
$command = 'msdev '.$dsp.' /MAKE "'.$info['package']. ' - Release"';
$this->current_callback = $callback;
$err = $this->_runCommand($command, array(&$this, 'msdevCallback'));
if (PEAR::isError($err)) {
return $err;
}
// figure out the build platform and type
$platform = 'Win32';
$buildtype = 'Release';
if (preg_match('/.*?'.$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.");
}
if (@copy($outfile, "$dir/$out")) {
$outfile = "$dir/$out";
}
$built_files[] = array(
'file' => "$outfile",
'php_api' => $this->php_api_version,
'zend_mod_api' => $this->zend_module_api_no,
'zend_ext_api' => $this->zend_extension_api_no,
);
return $built_files;
}
// }}}
// {{{ msdevCallback()
function msdevCallback($what, $data)
{
if (!$this->_firstline)
$this->_firstline = $data;
$this->_lastline = $data;
}
// }}}
// {{{ _harventInstDir
/**
* @param string
* @param string
* @param array
* @access private
*/
function _harvestInstDir($dest_prefix, $dirname, &$built_files)
{
$d = opendir($dirname);
if (!$d)
return false;
$ret = true;
while (($ent = readdir($d)) !== false) {
if ($ent{0} == '.')
continue;
$full = $dirname . DIRECTORY_SEPARATOR . $ent;
if (is_dir($full)) {
if (!$this->_harvestInstDir(
$dest_prefix . DIRECTORY_SEPARATOR . $ent,
$full, $built_files)) {
$ret = false;
break;
}
} else {
$dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent;
$built_files[] = array(
'file' => $full,
'dest' => $dest,
'php_api' => $this->php_api_version,
'zend_mod_api' => $this->zend_module_api_no,
'zend_ext_api' => $this->zend_extension_api_no,
);
}
}
closedir($d);
return $ret;
}
// }}}
// {{{ build()
/**
* Build an extension from source. Runs "phpize" in the source
* directory, but compiles in a temporary directory
* (/var/tmp/pear-build-USER/PACKAGE-VERSION).
*
* @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or
* a PEAR_PackageFile object
*
* @param mixed $callback callback function used to report output,
* see PEAR_Builder::_runCommand for details
*
* @return array an array of associative arrays with built files,
* format:
* array( array( 'file' => '/path/to/ext.so',
* 'php_api' => YYYYMMDD,
* 'zend_mod_api' => YYYYMMDD,
* 'zend_ext_api' => YYYYMMDD ),
* ... )
*
* @access public
*
* @see PEAR_Builder::_runCommand
*/
function build($descfile, $callback = null)
{
if (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();
} 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 (!@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");
$this->current_callback = $callback;
putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH'));
$err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback'));
if (PEAR::isError($err)) {
return $err;
}
if (!$err) {
return $this->raiseError("`phpize' failed");
}
// {{{ start of interactive part
$configure_command = "$dir/configure";
$configure_options = $pkg->getConfigureOptions();
if ($configure_options) {
foreach ($configure_options as $o) {
list($r) = $this->ui->userDialog('build',
array($o['prompt']),
array('text'),
array(@$o['default']));
if (substr($o['name'], 0, 5) == 'with-' &&
($r == 'yes' || $r == 'autodetect')) {
$configure_command .= " --$o[name]";
} else {
$configure_command .= " --$o[name]=".trim($r);
}
}
}
// }}} end of interactive part
// FIXME make configurable
if(!$user=getenv('USER')){
$user='defaultuser';
}
$build_basedir = "/var/tmp/pear-build-$user";
$build_dir = "$build_basedir/$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\" -ls"
);
if (!@chdir($build_dir)) {
return $this->raiseError("could not chdir to $build_dir");
}
putenv('PHP_PEAR_VERSION=1.4.11');
foreach ($to_run as $cmd) {
$err = $this->_runCommand($cmd, $callback);
if (PEAR::isError($err)) {
chdir($old_cwd);
return $err;
}
if (!$err) {
chdir($old_cwd);
return $this->raiseError("`$cmd' failed");
}
}
if (!($dp = opendir("modules"))) {
chdir($old_cwd);
return $this->raiseError("no `modules' directory found");
}
$built_files = array();
$prefix = exec("php-config --prefix");
$this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
chdir($old_cwd);
return $built_files;
}
// }}}
// {{{ phpizeCallback()
/**
* Message callback function used when running the "phpize"
* program. Extracts the API numbers used. Ignores other message
* types than "cmdoutput".
*
* @param string $what the type of message
* @param mixed $data the message
*
* @return void
*
* @access public
*/
function phpizeCallback($what, $data)
{
if ($what != 'cmdoutput') {
return;
}
$this->log(1, rtrim($data));
if (preg_match('/You should update your .aclocal.m4/', $data)) {
return;
}
$matches = array();
if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) {
$member = preg_replace('/[^a-z]/', '_', strtolower($matches[1]));
$apino = (int)$matches[2];
if (isset($this->$member)) {
$this->$member = $apino;
//$msg = sprintf("%-22s : %d", $matches[1], $apino);
//$this->log(1, $msg);
}
}
}
// }}}
// {{{ _runCommand()
/**
* Run an external command, using a message callback to report
* output. The command will be run through popen and output is
* reported for every line with a "cmdoutput" message with the
* line string, including newlines, as payload.
*
* @param string $command the command to run
*
* @param mixed $callback (optional) function to use as message
* callback
*
* @return bool whether the command was successful (exit code 0
* means success, any other means failure)
*
* @access private
*/
function _runCommand($command, $callback = null)
{
$this->log(1, "running: $command");
$pp = @popen("$command 2>&1", "r");
if (!$pp) {
return $this->raiseError("failed to run `$command'");
}
if ($callback && $callback[0]->debug == 1) {
$olddbg = $callback[0]->debug;
$callback[0]->debug = 2;
}
while ($line = fgets($pp, 1024)) {
if ($callback) {
call_user_func($callback, 'cmdoutput', $line);
} else {
$this->log(2, rtrim($line));
}
}
if ($callback && isset($olddbg)) {
$callback[0]->debug = $olddbg;
}
$exitcode = @pclose($pp);
return ($exitcode == 0);
}
// }}}
// {{{ log()
function log($level, $msg)
{
if ($this->current_callback) {
if ($this->debug >= $level) {
call_user_func($this->current_callback, 'output', $msg);
}
return;
}
return PEAR_Common::log($level, $msg);
}
// }}}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Parser.php,v 1.4 2006/01/06 04:47: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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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;
}
}
?>

412
lib/pear/PEAR/Command.php Normal file
View File

@@ -0,0 +1,412 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Command.php,v 1.36.2.1 2006/06/16 13:01:59 pajoye 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 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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;
}
// }}}
}
?>

View File

@@ -0,0 +1,186 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Auth.php,v 1.23 2006/03/02 18:14:13 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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' => '
Log in to the remote server. 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();
$channel = $this->config->get('default_channel');
$chan = $reg->getChannel($channel);
if (PEAR::isError($chan)) {
return $this->raiseError($chan);
}
$server = $this->config->get('preferred_mirror');
$remote = &$this->config->getRemote();
$username = $this->config->get('username');
if (empty($username)) {
$username = @$_ENV['USER'];
}
$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);
$this->config->set('username', $username);
$this->config->set('password', $password);
if ($chan->supportsREST()) {
$ok = true;
} else {
$remote->expectError(401);
$ok = $remote->call('logintest');
$remote->popExpect();
}
if ($ok === true) {
$this->ui->outputData("Logged in.", $command);
$this->config->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;
}
// }}}
}
?>

View File

@@ -0,0 +1,25 @@
<commands version="1.0">
<login>
<summary>Connects and authenticates to remote server</summary>
<shortcut>li</shortcut>
<function>doLogin</function>
<options />
<doc>
Log in to the remote server. 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>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Build.php,v 1.13 2006/01/06 04:47: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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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');
}
}
// }}}
}

View File

@@ -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>

View File

@@ -0,0 +1,780 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Channels.php,v 1.44.2.1 2006/07/17 18:24:10 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 creates the local channel.xml.
'
),
);
// }}}
// {{{ 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();
$savechannel = $this->config->get('default_channel');
if (isset($options['channel'])) {
if (!$reg->channelExists($options['channel'])) {
return $this->raiseError('Unknown channel "' . $options['channel'] . '"');
}
$this->config->set('default_channel', $options['channel']);
} else {
$this->config->set('default_channel', 'pear.php.net');
}
$remote = &$this->config->getRemote();
$channels = $remote->call('channel.listAll');
if (PEAR::isError($channels)) {
$this->config->set('default_channel', $savechannel);
return $channels;
}
if (!is_array($channels) || isset($channels['faultCode'])) {
$this->config->set('default_channel', $savechannel);
return $this->raiseError("Incorrect channel listing returned from channel '$chan'");
}
if (!count($channels)) {
$data = 'no updates available';
}
$dl = &$this->getDownloader();
if (!class_exists('System')) {
require_once 'System.php';
}
$tmpdir = System::mktemp(array('-d'));
foreach ($channels as $channel) {
$channel = $channel[0];
$save = $channel;
if ($reg->channelExists($channel, true)) {
$this->ui->outputData("Updating channel \"$channel\"", $command);
$test = $reg->getChannel($channel, true);
if (PEAR::isError($test)) {
$this->ui->outputData("Channel '$channel' is corrupt in registry!", $command);
$lastmodified = false;
} else {
$lastmodified = $test->lastModified();
}
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
$contents = $dl->downloadHttp('http://' . $test->getName() . '/channel.xml',
$this->ui, $tmpdir, null, $lastmodified);
PEAR::staticPopErrorHandling();
if (PEAR::isError($contents)) {
$this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
$test->getName() . '"', $command);
continue;
}
if (!$contents) {
$this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
continue;
}
list($contents, $lastmodified) = $contents;
$info = implode('', file($contents));
if (!$info) {
$this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
continue;
}
if (!class_exists('PEAR_ChannelFile')) {
require_once 'PEAR/ChannelFile.php';
}
$channelinfo = new PEAR_ChannelFile;
$channelinfo->fromXmlString($info);
if ($channelinfo->getErrors()) {
$this->ui->outputData("Downloaded channel data from channel \"$channel\" " .
'is corrupt, skipping', $command);
continue;
}
$channel = $channelinfo;
if ($channel->getName() != $save) {
$this->ui->outputData('ERROR: Security risk - downloaded channel ' .
'definition file for channel "'
. $channel->getName() . ' from channel "' . $save .
'". To use anyway, use channel-update', $command);
continue;
}
$reg->updateChannel($channel, $lastmodified);
} else {
if ($reg->isAlias($channel)) {
$temp = &$reg->getChannel($channel);
if (PEAR::isError($temp)) {
return $this->raiseError($temp);
}
$temp->setAlias($temp->getName(), true); // set the alias to the channel name
if ($reg->channelExists($temp->getName())) {
$this->ui->outputData('ERROR: existing channel "' . $temp->getName() .
'" is aliased to "' . $channel . '" already and cannot be ' .
're-aliased to "' . $temp->getName() . '" because a channel with ' .
'that name or alias already exists! Please re-alias and try ' .
'again.', $command);
continue;
}
}
$this->ui->outputData("Adding new channel \"$channel\"", $command);
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
$contents = $dl->downloadHttp('http://' . $channel . '/channel.xml',
$this->ui, $tmpdir, null, false);
PEAR::staticPopErrorHandling();
if (PEAR::isError($contents)) {
$this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
$channel . '"', $command);
continue;
}
list($contents, $lastmodified) = $contents;
$info = implode('', file($contents));
if (!class_exists('PEAR_ChannelFile')) {
require_once 'PEAR/ChannelFile.php';
}
$channelinfo = new PEAR_Channelfile;
$channelinfo->fromXmlString($info);
if ($channelinfo->getErrors()) {
$this->ui->outputData("Downloaded channel data from channel \"$channel\"" .
' is corrupt, skipping', $command);
continue;
}
$channel = $channelinfo;
if ($channel->getName() != $save) {
$this->ui->outputData('ERROR: Security risk - downloaded channel ' .
'definition file for channel "'
. $channel->getName() . '" from channel "' . $save .
'". To use anyway, use channel-update', $command);
continue;
}
$reg->addChannel($channel, $lastmodified);
}
}
$this->config->set('default_channel', $savechannel);
$this->ui->outputData('update-channels complete', $command);
return true;
}
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();
if (!class_exists('System')) {
require_once 'System.php';
}
$tmpdir = System::mktemp(array('-d'));
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
$loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
PEAR::staticPopErrorHandling();
if (PEAR::isError($loc)) {
return $this->raiseError('Cannot open "' . $channel . '"');
} else {
$contents = implode('', file($loc));
}
} else {
$fp = @fopen($params[0], 'r');
if (!$fp) {
if (@file_exists($params[0])) {
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 $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'] = $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();
if (!class_exists('System')) {
require_once 'System.php';
}
$tmpdir = System::mktemp(array('-d'));
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] . '"');
} else {
list($loc, $lastmodified) = $loc;
$contents = implode('', file($loc));
}
} else {
$lastmodified = false;
$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)
{
if (!class_exists('System')) {
require_once 'System.php';
}
$tmpdir = System::mktemp(array('-d'));
$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('Retrieving channel.xml from remote server');
$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() . '"');
}
list($contents, $lastmodified) = $contents;
if (!$contents) {
$this->ui->outputData("Channel $params[0] channel.xml 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]);
} else {
list($loc, $lastmodified) = $loc;
$contents = implode('', file($loc));
}
} else {
$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]) . '"');
}
function doDiscover($command, $options, $params)
{
$reg = &$this->config->getRegistry();
if (sizeof($params) != 1) {
return $this->raiseError("No channel server specified");
}
if ($reg->channelExists($params[0])) {
if ($reg->isAlias($params[0])) {
return $this->raiseError("A channel alias named \"$params[0]\" " .
'already exists, aliasing channel "' . $reg->channelName($params[0])
. '"');
} else {
return $this->raiseError("Channel \"$params[0]\" is already initialized");
}
}
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$err = $this->doAdd($command, $options, array('http://' . $params[0] . '/channel.xml'));
$this->popErrorHandling();
if (PEAR::isError($err)) {
return $this->raiseError("Discovery of channel \"$params[0]\" failed (" .
$err->getMessage() . ')');
}
$this->ui->outputData("Discovery of channel \"$params[0]\" succeeded", $command);
}
}
?>

View File

@@ -0,0 +1,93 @@
<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>&lt;channel name&gt;
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>&lt;channel.xml&gt;
Add a private channel to the channel list. Note that all
public channels should be synced using &quot;update-channels&quot;.
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>[&lt;channel.xml&gt;|&lt;channel name&gt;]
Update a channel in the channel list directly. Note that all
public channels can be synced using &quot;update-channels&quot;.
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>&lt;package&gt;
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>&lt;channel&gt; &lt;alias&gt;
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>[&lt;channel.xml&gt;|&lt;channel name&gt;]
Initialize a Channel from its server and create the local channel.xml.
</doc>
</channel-discover>
</commands>

View File

@@ -0,0 +1,279 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Common.php,v 1.32.2.1 2006/06/08 22:27:11 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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];
}
return @$this->commands[$command]['options'];
}
// }}}
// {{{ 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();
$help = @$this->commands[$command]['doc'];
if (empty($help)) {
// XXX (cox) Fallback to summary if there is no doc (show both?)
if (!$help = @$this->commands[$command]['summary']) {
return "No help for command \"$command\"";
}
}
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);
}
// }}}
}
?>

View File

@@ -0,0 +1,418 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Config.php,v 1.51.2.1 2006/06/04 12:11:39 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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('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('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;
}
// }}}
}
?>

View File

@@ -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 &quot;user&quot;, &quot;system&quot; and &quot;default&quot;. 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>&lt;parameter&gt; [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 &quot;user&quot;, &quot;system&quot; and &quot;default&quot;. 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>&lt;parameter&gt; &lt;value&gt; [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 &quot;user&quot;. 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>&lt;root path&gt; &lt;filename&gt;
Create a default configuration file with all directory configuration
variables set to subdirectories of &lt;root path&gt;, and save it as &lt;filename&gt;.
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>

View File

@@ -0,0 +1,773 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Install.php,v 1.115 2006/03/02 18:14:13 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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), 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' => '<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' => 'doInstall',
'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;
}
// {{{ doInstall()
function doInstall($command, $options, $params)
{
if (empty($this->installer)) {
$this->installer = &$this->getInstaller($this->ui);
}
if ($command == 'upgrade') {
$options['upgrade'] = true;
}
if (isset($options['installroot']) && isset($options['packagingroot'])) {
return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
}
if (isset($options['packagingroot']) && $this->config->get('verbose') > 2) {
$this->ui->outputData('using package root: ' . $options['packagingroot']);
}
$reg = &$this->config->getRegistry();
if ($command == 'upgrade-all') {
$options['upgrade'] = true;
$reg = &$this->config->getRegistry();
$savechannel = $this->config->get('default_channel');
$params = array();
foreach ($reg->listChannels() as $channel) {
if ($channel == '__uri') {
continue;
}
$this->config->set('default_channel', $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'))) {
$dorest = true;
unset($remote);
} else {
$dorest = false;
$remote = &$this->config->getRemote($this->config);
}
$state = $this->config->get('preferred_state');
$installed = array_flip($reg->listPackages($channel));
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
if ($dorest) {
$rest = &$this->config->getREST('1.0', array());
$latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
} else {
if (empty($state) || $state == 'any') {
$latest = $remote->call("package.listLatestReleases");
} else {
$latest = $remote->call("package.listLatestReleases", $state);
}
}
PEAR::staticPopErrorHandling();
if (PEAR::isError($latest) || !is_array($latest)) {
continue;
}
foreach ($latest as $package => $info) {
$package = strtolower($package);
if (!isset($installed[$package])) {
// skip packages we don't have installed
continue;
}
$inst_version = $reg->packageInfo($package, 'version', $channel);
if (version_compare("$info[version]", "$inst_version", "le")) {
// installed version is up-to-date
continue;
}
$params[] = $reg->parsedPackageNameToString(array('package' => $package,
'channel' => $channel));
$this->ui->outputData(array('data' => "Will upgrade $package"), $command);
}
}
$this->config->set('default_channel', $savechannel);
}
$this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
$errors = array();
$downloaded = array();
$downloaded = &$this->downloader->download($params);
$errors = $this->downloader->getErrorMsgs();
if (count($errors)) {
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();
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') {
$pkg = &$param->getPackageFile();
if ($instbin = $pkg->getInstalledBinary()) {
$instpkg = &$reg->getPackage($instbin, $pkg->getChannel());
} else {
$instpkg = &$reg->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') {
$extrainfo[] = 'You should add "extension=' . $pinfo['basename']
. '" to php.ini';
break;
}
}
}
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;
}
$this->ui->outputData($param->getPackage() . ': Optional feature ' .
$group['attribs']['name'] . ' available (' .
$group['attribs']['hint'] . ')');
}
$extrainfo[] = 'To install use "pear install ' .
$reg->parsedPackageNameToString(
array('package' => $param->getPackage(),
'channel' => $param->getChannel()), true) .
'#featurename"';
}
}
if (isset($options['installroot'])) {
$reg = &$this->config->getRegistry();
}
$pkg = &$reg->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[] = 'Use "pear run-scripts ' . $pn . '" to run';
$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;
}
// }}}
// {{{ 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();
$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);
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;
}
$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), $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;
}
}
$downloader->setDownloadDir($dest);
$result = &$downloader->download(array($params[0]));
if (PEAR::isError($result)) {
return $result;
}
$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;
}
}
?>

View File

@@ -0,0 +1,254 @@
<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&apos;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&apos;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>[channel/]&lt;package&gt; ...
Installs one or more PEAR packages. You can specify a package to
install in four ways:
&quot;Package-1.0.tgz&quot; : installs from a local file
&quot;http://example.com/Package-1.0.tgz&quot; : installs from
anywhere on the net.
&quot;package.xml&quot; : installs the package described in
package.xml. Useful for testing, or for wrapping a PEAR package in
another package manager such as RPM.
&quot;Package[-version/state][.tar]&quot; : queries your default channel&apos;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 &quot;Package-1.1,&quot; to retrieve
Package state beta, use &quot;Package-beta.&quot; 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
&quot;channel/Package&quot;
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&apos;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&apos;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>&lt;package&gt; ...
Upgrades one or more PEAR packages. See documentation for the
&quot;install&quot; 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&apos;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&apos;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
&quot;preferred_state&quot; (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&apos;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/]&lt;package&gt; ...
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 &quot;ext&quot; if exists)</doc>
</destination>
<force>
<shortopt>f</shortopt>
<doc>Force the unpacking even if there were errors in the package</doc>
</force>
</options>
<doc>&lt;package&gt;
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>&lt;package&gt;
Run post-installation scripts in package &lt;package&gt;, if any exist.
</doc>
</run-scripts>
</commands>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Mirror.php,v 1.18 2006/03/02 18:14:13 cellog 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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));
} 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;
}
// }}}
}

View File

@@ -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>

File diff suppressed because it is too large Load Diff

View File

@@ -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 &quot;package.xml&quot; in the archive,
and the other as &quot;package2.xml&quot; in the archive&quot;
</doc>
</package>
<package-validate>
<summary>Validate Package Consistency</summary>
<function>doPackageValidate</function>
<shortcut>pv</shortcut>
<options />
<doc>
</doc>
</package-validate>
<cvsdiff>
<summary>Run a &quot;cvs diff&quot; 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&apos;t do anything, just pretend</doc>
</dry-run>
</options>
<doc>&lt;package.xml&gt;
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&apos;t do anything, just pretend</doc>
</dry-run>
</options>
<doc>&lt;package.xml&gt;
Sets a CVS tag on all files in a package. Use this command after you have
packaged a distribution tarball with the &quot;package&quot; 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 &quot;slide&quot; 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>&lt;package-file&gt;
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 &quot;PEAR::%s&quot;.</doc>
</rpm-pkgname>
</options>
<doc>&lt;package-file&gt;
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>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Pickle.php,v 1.5.2.1 2006/05/10 03:25:15 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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
- 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.php')) {
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') {
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 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('.');
}
}
?>

View File

@@ -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 &quot;package.xml&quot; in the archive,
and the other as &quot;package2.xml&quot; in the archive&quot;
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
- 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>

View File

@@ -0,0 +1,997 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Registry.php,v 1.70 2006/01/06 04:47: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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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',
),
),
'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)
{
if (isset($options['allchannels'])) {
return $this->doListAll($command, array(), $params);
}
$reg = &$this->config->getRegistry();
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'));
$i = $j = 0;
$data = array(
'caption' => 'Installed packages, channel ' .
$channel . ':',
'border' => true,
'headline' => array('Package', 'Version', 'State')
);
foreach ($installed 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($installed)==0) {
$data = '(no packages installed from channel ' . $channel . ')';
}
$this->ui->outputData($data, $command);
return true;
}
function doListAll($command, $options, $params)
{
$reg = &$this->config->getRegistry();
$installed = $reg->packageInfo(null, null, null);
foreach ($installed as $channel => $packages) {
usort($packages, array($this, '_sortinfo'));
$i = $j = 0;
$data = array(
'caption' => 'Installed packages, channel ' . $channel . ':',
'border' => true,
'headline' => array('Package', 'Version', 'State')
);
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)')),
);
}
$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();
if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0],
'r'))) {
@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)
{
$this->pushErrorHandling(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 {
$this->popErrorHandling();
$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 = false;
$reg = &$this->config->getRegistry();
if ((@is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) {
@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['Last 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 'extbin' :
$release = 'PECL-style PHP 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()) {
$info['Compatible with'] = '';
foreach ($compat as $package) {
$info['Compatible with'] .= $package['channel'] . '/' . $package['package'] .
"\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['package'] . "\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['Last 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');
}
}
?>

View File

@@ -0,0 +1,54 @@
<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>
</options>
<doc>&lt;package&gt;
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>&lt;package&gt;
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>&lt;package&gt; [[relation] version]
Tests if a package is installed in the system. Will exit(1) if it is not.
&lt;relation&gt; The version comparison operator. One of:
&lt;, lt, &lt;=, le, &gt;, gt, &gt;=, ge, ==, =, eq, !=, &lt;&gt;, ne
&lt;version&gt; The version to compare with
</doc>
</shell-test>
<info>
<summary>Display information about a package</summary>
<function>doInfo</function>
<shortcut>in</shortcut>
<options />
<doc>&lt;package&gt;
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>

View File

@@ -0,0 +1,670 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Remote.php,v 1.90.2.3 2006/06/04 12:27:55 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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(),
'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',
)
),
'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',
)
),
'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);
$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']);
} 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);
} 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);
} 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'),
);
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);
} 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);
} 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:',
'border' => true,
'headline' => array('Package', 'Latest', 'Local'),
);
$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;
}
$data['data'][$info['category']][] = array(
$reg->channelAlias($channel) . '/' . $name,
@$info['stable'],
@$installed['version'],
@$desc,
@$info['deps'],
);
}
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');
};
$savechannel = $channel = $this->config->get('default_channel');
$reg = &$this->config->getRegistry();
$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);
} 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) {
return $this->raiseError('no packages found that match pattern "' . $package . '"');
}
$data = array(
'caption' => 'Matched packages, channel ' . $channel . ':',
'border' => true,
'headline' => array('Package', 'Stable/(Latest)', 'Local'),
);
foreach ($available as $name => $info) {
$installed = $reg->packageInfo($name, null, $channel);
$desc = $info['summary'];
if (isset($params[$name]))
$desc .= "\n\n".$info['description'];
$unstable = '';
if ($info['unstable']) {
$unstable = '/(' . $info['unstable'] . ' ' . $info['state'] . ')';
}
if (!isset($info['stable']) || !$info['stable']) {
$info['stable'] = 'none';
}
$version = is_array($installed['version']) ? $installed['version']['release'] :
$installed['version'];
$data['data'][$info['category']][] = array(
$name,
$info['stable'] . $unstable,
$version,
$desc,
);
}
$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
$options['ignorepreferred_state'] = 1;
$downloader = &$this->getDownloader($options);
$downloader->setDownloadDir(getcwd());
$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'),
);
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 (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 (!($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}$/', $ent) ||
preg_match('/rest.cache(file|id)$/', $ent)) {
$path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
$ok = @unlink($path);
if ($ok) {
if ($verbose >= 2) {
$output .= "deleted $path\n";
}
$num++;
} elseif ($verbose >= 1) {
$output .= "failed to delete $path\n";
}
}
}
closedir($dp);
if ($verbose >= 1) {
$output .= "$num cache entries cleared\n";
}
$this->ui->outputData(rtrim($output), $command);
return $num;
}
// }}}
}
?>

View File

@@ -0,0 +1,92 @@
<commands version="1.0">
<remote-info>
<summary>Information About Remote Packages</summary>
<function>doRemoteInfo</function>
<shortcut>ri</shortcut>
<options />
<doc>&lt;package&gt;
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>
</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>
</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>
</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>&lt;package&gt;...
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>

View File

@@ -0,0 +1,275 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Test.php,v 1.9 2006/02/03 22:28:08 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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',
),
),
'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)
{
require_once 'PEAR/Common.php';
require_once 'PEAR/RunTest.php';
require_once 'System.php';
$log = new PEAR_Common;
$log->ui = &$this->ui; // slightly hacky, but it will work
$run = new PEAR_RunTest($log, $options);
$tests = array();
if (isset($options['recur'])) {
$depth = 4;
} else {
$depth = 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'])) {
if (!preg_match('/AllTests\.php$/i', $name)) {
continue;
}
} else {
if (!preg_match('/\.phpt$/', $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'));
} else {
$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$/i', $p)) {
continue;
}
$tests[] = $p;
} else {
if (!@file_exists($p)) {
if (!preg_match('/\.phpt$/', $p)) {
$p .= '.phpt';
}
$dir = System::find(array(dirname($p), '-type', 'f',
'-maxdepth', $depth,
'-name', $p));
$tests = array_merge($tests, $dir);
} else {
$tests[] = $p;
}
}
}
}
$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();
$this->ui->outputData('Running ' . count($tests) . ' tests', $command);
$start = time();
if (isset($options['realtimelog'])) {
@unlink('run-tests.log');
}
foreach ($tests as $t) {
if (isset($options['realtimelog'])) {
$fp = @fopen('run-tests.log', 'a');
if ($fp) {
fwrite($fp, "Running test $t...");
fclose($fp);
}
}
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
$result = $run->run($t, $ini_settings);
PEAR::staticPopErrorHandling();
if (PEAR::isError($result)) {
$this->ui->log(0, $result->getMessage());
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;
}
}
$total = date('i:s', time() - $start);
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";
}
if (isset($options['realtimelog'])) {
$fp = @fopen('run-tests.log', 'a');
} else {
$fp = @fopen('run-tests.log', 'w');
}
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;
}
// }}}
}
?>

View File

@@ -0,0 +1,40 @@
<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 &quot; -d setting=blah&quot;</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</doc>
</phpunit>
</options>
<doc>[testfile|dir ...]
Run regression tests with PHP&apos;s regression testing script (run-tests.php).</doc>
</run-tests>
</commands>

1129
lib/pear/PEAR/Common.php Normal file

File diff suppressed because it is too large Load Diff

2098
lib/pear/PEAR/Config.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,495 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at the following url: |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
// | Stig Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// THIS FILE IS DEPRECATED IN FAVOR OF DEPENDENCY2.PHP, AND IS NOT USED IN THE INSTALLER
// $Id: Dependency.php,v 1.41 2006/01/06 04:47:36 cellog Exp $
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;
}
// }}}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,675 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: DependencyDB.php,v 1.30.2.1 2006/05/25 22:00:05 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';
/**
* 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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)) {
$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();
foreach ($packages as $channel => $ps) {
foreach ($ps as $package) {
$package = $this->_registry->getPackage($package, $channel);
$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 (@!is_file($this->_lockfile)) {
touch($this->_lockfile);
}
$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();
if (function_exists('file_get_contents')) {
fclose($fp);
$data = unserialize(file_get_contents($this->_depdb));
} else {
$data = unserialize(fread($fp, filesize($this->_depdb)));
fclose($fp);
}
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;
}
$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';
}
$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 {
$data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
= array('channel' => strtolower($pkg->getChannel()),
'package' => strtolower($pkg->getPackage()));
}
}
}
?>

1547
lib/pear/PEAR/Downloader.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,970 @@
<?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-2006 Greg Beaver
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: ErrorStack.php,v 1.22 2006/01/06 04:47:36 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.4.11
* @package PEAR_ErrorStack
* @category Debugging
* @copyright 2004-2006 Greg Beaver
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: ErrorStack.php,v 1.22 2006/01/06 04:47:36 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|Exception
* if compatibility mode is on, a PEAR_Error is also
* thrown. If the class Exception exists, then one
* is returned to allow code like:
* <code>
* throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
* </code>
*
* The errorData property of the exception class will be set to the array
* that would normally be returned. If a PEAR_Error is returned, the userinfo
* property is set to the array
*
* Otherwise, an array is returned in this format:
* <code>
* array(
* 'code' => $code,
* 'params' => $params,
* 'package' => $this->_package,
* 'level' => $level,
* 'time' => time(),
* 'context' => $context,
* 'message' => $msg,
* //['repackage' => $err] repackaged error array/Exception class
* );
* </code>
*/
function push($code, $level = 'error', $params = array(), $msg = false,
$repackage = false, $backtrace = false)
{
$context = false;
// grab error context
if ($this->_contextCallback) {
if (!$backtrace) {
$backtrace = debug_backtrace();
}
$context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
}
// save error
$time = explode(' ', microtime());
$time = $time[1] + $time[0];
$err = array(
'code' => $code,
'params' => $params,
'package' => $this->_package,
'level' => $level,
'time' => $time,
'context' => $context,
'message' => $msg,
);
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);
$this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
}
if ($log) {
if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
$this->_log($err);
}
}
if ($die) {
die();
}
if ($this->_compat && $push) {
return $this->raiseError($msg, $code, null, null, $err);
}
return $err;
}
/**
* Static version of {@link push()}
*
* @param string $package Package name this error belongs to
* @param int $code Package-specific error code
* @param string $level Error level. This is NOT spell-checked
* @param array $params associative array of error parameters
* @param string $msg Error message, or a portion of it if the message
* is to be generated
* @param array $repackage If this error re-packages an error pushed by
* another package, place the array returned from
* {@link pop()} in this parameter
* @param array $backtrace Protected parameter: use this to pass in the
* {@link debug_backtrace()} that should be used
* to find error context
* @return PEAR_Error|null|Exception
* if compatibility mode is on, a PEAR_Error is also
* thrown. If the class Exception exists, then one
* is returned to allow code like:
* <code>
* throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
* </code>
* @static
*/
function staticPush($package, $code, $level = 'error', $params = array(),
$msg = false, $repackage = false, $backtrace = false)
{
$s = &PEAR_ErrorStack::singleton($package);
if ($s->_contextCallback) {
if (!$backtrace) {
if (function_exists('debug_backtrace')) {
$backtrace = debug_backtrace();
}
}
}
return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
}
/**
* Log an error using PEAR::Log
* @param array $err Error array
* @param array $levels Error level => Log constant map
* @access protected
*/
function _log($err)
{
if ($this->_logger) {
$logger = &$this->_logger;
} else {
$logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
}
if (is_a($logger, 'Log')) {
$levels = array(
'exception' => PEAR_LOG_CRIT,
'alert' => PEAR_LOG_ALERT,
'critical' => PEAR_LOG_CRIT,
'error' => PEAR_LOG_ERR,
'warning' => PEAR_LOG_WARNING,
'notice' => PEAR_LOG_NOTICE,
'info' => PEAR_LOG_INFO,
'debug' => PEAR_LOG_DEBUG);
if (isset($levels[$err['level']])) {
$level = $levels[$err['level']];
} else {
$level = PEAR_LOG_INFO;
}
$logger->log($err['message'], $level, $err);
} else { // support non-standard logs
call_user_func($logger, $err);
}
}
/**
* Pop an error off of the error stack
*
* @return false|array
* @since 0.4alpha it is no longer possible to specify a specific error
* level to return - the last error pushed will be returned, instead
*/
function pop()
{
return @array_shift($this->_errors);
}
/**
* Determine whether there are any errors on the stack
* @param string|array Level name. Use to determine if any errors
* of level (string), or levels (array) have been pushed
* @return boolean
*/
function hasErrors($level = false)
{
if ($level) {
return isset($this->_errorsByLevel[$level]);
}
return count($this->_errors);
}
/**
* Retrieve all errors since last purge
*
* @param boolean set in order to empty the error stack
* @param string level name, to return only errors of a particular severity
* @return array
*/
function getErrors($purge = false, $level = false)
{
if (!$purge) {
if ($level) {
if (!isset($this->_errorsByLevel[$level])) {
return array();
} else {
return $this->_errorsByLevel[$level];
}
} else {
return $this->_errors;
}
}
if ($level) {
$ret = $this->_errorsByLevel[$level];
foreach ($this->_errorsByLevel[$level] as $i => $unused) {
// entries are references to the $_errors array
$this->_errorsByLevel[$level][$i] = false;
}
// array_filter removes all entries === false
$this->_errors = array_filter($this->_errors);
unset($this->_errorsByLevel[$level]);
return $ret;
}
$ret = $this->_errors;
$this->_errors = array();
$this->_errorsByLevel = array();
return $ret;
}
/**
* Determine whether there are any errors on a single error stack, or on any error stack
*
* The optional parameter can be used to test the existence of any errors without the need of
* singleton instantiation
* @param string|false Package name to check for errors
* @param string Level name to check for a particular severity
* @return boolean
* @static
*/
function staticHasErrors($package = false, $level = false)
{
if ($package) {
if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
return false;
}
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
}
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
if ($obj->hasErrors($level)) {
return true;
}
}
return false;
}
/**
* Get a list of all errors since last purge, organized by package
* @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
* @param boolean $purge Set to purge the error stack of existing errors
* @param string $level Set to a level name in order to retrieve only errors of a particular level
* @param boolean $merge Set to return a flat array, not organized by package
* @param array $sortfunc Function used to sort a merged array - default
* sorts by time, and should be good for most cases
* @static
* @return array
*/
function staticGetErrors($purge = false, $level = false, $merge = false,
$sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
{
$ret = array();
if (!is_callable($sortfunc)) {
$sortfunc = array('PEAR_ErrorStack', '_sortErrors');
}
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
$test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
if ($test) {
if ($merge) {
$ret = array_merge($ret, $test);
} else {
$ret[$package] = $test;
}
}
}
if ($merge) {
usort($ret, $sortfunc);
}
return $ret;
}
/**
* Error sorting function, sorts by time
* @access private
*/
function _sortErrors($a, $b)
{
if ($a['time'] == $b['time']) {
return 0;
}
if ($a['time'] < $b['time']) {
return 1;
}
return -1;
}
/**
* Standard file/line number/function/class context callback
*
* This function uses a backtrace generated from {@link debug_backtrace()}
* and so will not work at all in PHP < 4.3.0. The frame should
* reference the frame that contains the source of the error.
* @return array|false either array('file' => file, 'line' => line,
* 'function' => function name, 'class' => class name) or
* if this doesn't work, then false
* @param unused
* @param integer backtrace frame.
* @param array Results of debug_backtrace()
* @static
*/
function getFileLine($code, $params, $backtrace = null)
{
if ($backtrace === null) {
return false;
}
$frame = 0;
$functionframe = 1;
if (!isset($backtrace[1])) {
$functionframe = 0;
} else {
while (isset($backtrace[$functionframe]['function']) &&
$backtrace[$functionframe]['function'] == 'eval' &&
isset($backtrace[$functionframe + 1])) {
$functionframe++;
}
}
if (isset($backtrace[$frame])) {
if (!isset($backtrace[$frame]['file'])) {
$frame++;
}
$funcbacktrace = $backtrace[$functionframe];
$filebacktrace = $backtrace[$frame];
$ret = array('file' => $filebacktrace['file'],
'line' => $filebacktrace['line']);
// rearrange for eval'd code or create function errors
if (strpos($filebacktrace['file'], '(') &&
preg_match(';^(.*?)\((\d+)\) : (.*?)$;', $filebacktrace['file'],
$matches)) {
$ret['file'] = $matches[1];
$ret['line'] = $matches[2] + 0;
}
if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
if ($funcbacktrace['function'] != 'eval') {
if ($funcbacktrace['function'] == '__lambda_func') {
$ret['function'] = 'create_function() code';
} else {
$ret['function'] = $funcbacktrace['function'];
}
}
}
if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
$ret['class'] = $funcbacktrace['class'];
}
return $ret;
}
return false;
}
/**
* Standard error message generation callback
*
* This method may also be called by a custom error message generator
* to fill in template values from the params array, simply
* set the third parameter to the error message template string to use
*
* The special variable %__msg% is reserved: use it only to specify
* where a message passed in by the user should be placed in the template,
* like so:
*
* Error message: %msg% - internal error
*
* If the message passed like so:
*
* <code>
* $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
* </code>
*
* The returned error message will be "Error message: server error 500 -
* internal error"
* @param PEAR_ErrorStack
* @param array
* @param string|false Pre-generated error message template
* @static
* @return string
*/
function getErrorMessage(&$stack, $err, $template = false)
{
if ($template) {
$mainmsg = $template;
} else {
$mainmsg = $stack->getErrorMessageTemplate($err['code']);
}
$mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
if (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'));
?>

376
lib/pear/PEAR/Exception.php Normal file
View File

@@ -0,0 +1,376 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Exception.php,v 1.23 2006/01/06 04:47:36 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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, array $causes);
* PEAR_Exception(string $message, array $causes, int $code);
*/
public function __construct($message, $p2 = null, $p3 = null)
{
if (is_int($p2)) {
$code = $p2;
$this->cause = null;
} elseif ($p2 instanceof Exception || is_array($p2)) {
$code = $p3;
if (is_array($p2) && isset($p2['message'])) {
// fix potential problem of passing in a single warning
$p2 = array($p2);
}
$this->cause = $p2;
} else {
$code = null;
$this->cause = null;
}
parent::__construct($message, $code);
$this->signal();
}
/**
* @param mixed $callback - A valid php callback, see php func is_callable()
* - A PEAR_Exception::OBSERVER_* constant
* - An array(const PEAR_Exception::OBSERVER_*,
* mixed $options)
* @param string $label The name of the observer. Use this if you want
* to remove it later with removeObserver()
*/
public static function addObserver($callback, $label = 'default')
{
self::$_observers[$label] = $callback;
}
public static function removeObserver($label = 'default')
{
unset(self::$_observers[$label]);
}
/**
* @return int unique identifier for an observer
*/
public static function getUniqueId()
{
return self::$_uniqueid++;
}
private function signal()
{
foreach (self::$_observers as $func) {
if (is_callable($func)) {
call_user_func($func, $this);
continue;
}
settype($func, 'array');
switch ($func[0]) {
case self::OBSERVER_PRINT :
$f = (isset($func[1])) ? $func[1] : '%s';
printf($f, $this->getMessage());
break;
case self::OBSERVER_TRIGGER :
$f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
trigger_error($this->getMessage(), $f);
break;
case self::OBSERVER_DIE :
$f = (isset($func[1])) ? $func[1] : '%s';
die(printf($f, $this->getMessage()));
break;
default:
trigger_error('invalid observer type', E_USER_WARNING);
}
}
}
/**
* Return specific error information that can be used for more detailed
* error messages or translation.
*
* This method may be overridden in child exception classes in order
* to add functionality not present in PEAR_Exception and is a placeholder
* to define API
*
* The returned array must be an associative array of parameter => value like so:
* <pre>
* array('name' => $name, 'context' => array(...))
* </pre>
* @return array
*/
public function getErrorData()
{
return array();
}
/**
* Returns the exception that caused this exception to be thrown
* @access public
* @return Exception|array The context of the exception
*/
public function getCause()
{
return $this->cause;
}
/**
* Function must be public to call on caused exceptions
* @param array
*/
public function getCauseMessage(&$causes)
{
$trace = $this->getTraceSafe();
$cause = array('class' => get_class($this),
'message' => $this->message,
'file' => 'unknown',
'line' => 'unknown');
if (isset($trace[0])) {
if (isset($trace[0]['file'])) {
$cause['file'] = $trace[0]['file'];
$cause['line'] = $trace[0]['line'];
}
}
$causes[] = $cause;
if ($this->cause instanceof PEAR_Exception) {
$this->cause->getCauseMessage($causes);
} elseif ($this->cause instanceof Exception) {
$causes[] = array('class' => get_class($cause),
'message' => $cause->getMessage(),
'file' => $cause->getFile(),
'line' => $cause->getLine());
} 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 (is_array($cause) && isset($cause['message'])) {
// PEAR_ErrorStack warning
$causes[] = array(
'class' => $cause['package'],
'message' => $cause['message'],
'file' => isset($cause['context']['file']) ?
$cause['context']['file'] :
'unknown',
'line' => isset($cause['context']['line']) ?
$cause['context']['line'] :
'unknown',
);
}
}
}
}
public function getTraceSafe()
{
if (!isset($this->_trace)) {
$this->_trace = $this->getTrace();
if (empty($this->_trace)) {
$backtrace = debug_backtrace();
$this->_trace = array($backtrace[count($backtrace)-1]);
}
}
return $this->_trace;
}
public function getErrorClass()
{
$trace = $this->getTraceSafe();
return $trace[0]['class'];
}
public function getErrorMethod()
{
$trace = $this->getTraceSafe();
return $trace[0]['function'];
}
public function __toString()
{
if (isset($_SERVER['REQUEST_URI'])) {
return $this->toHtml();
}
return $this->toText();
}
public function toHtml()
{
$trace = $this->getTraceSafe();
$causes = array();
$this->getCauseMessage($causes);
$html = '<table border="1" cellspacing="0">' . "\n";
foreach ($causes as $i => $cause) {
$html .= '<tr><td colspan="3" bgcolor="#ff9999">'
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
. 'on line <b>' . $cause['line'] . '</b>'
. "</td></tr>\n";
}
$html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
. '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
foreach ($trace as $k => $v) {
$html .= '<tr><td align="center">' . $k . '</td>'
. '<td>';
if (!empty($v['class'])) {
$html .= $v['class'] . $v['type'];
}
$html .= $v['function'];
$args = array();
if (!empty($v['args'])) {
foreach ($v['args'] as $arg) {
if (is_null($arg)) $args[] = 'null';
elseif (is_array($arg)) $args[] = 'Array';
elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
else {
$arg = (string)$arg;
$str = htmlspecialchars(substr($arg, 0, 16));
if (strlen($arg) > 16) $str .= '&hellip;';
$args[] = "'" . $str . "'";
}
}
}
$html .= '(' . implode(', ',$args) . ')'
. '</td>'
. '<td>' . (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>&nbsp;</td></tr>' . "\n"
. '</table>';
return $html;
}
public function toText()
{
$causes = array();
$this->getCauseMessage($causes);
$causeMsg = '';
foreach ($causes as $i => $cause) {
$causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
. $cause['message'] . ' in ' . $cause['file']
. ' on line ' . $cause['line'] . "\n";
}
return $causeMsg . $this->getTraceAsString();
}
}
?>

186
lib/pear/PEAR/Frontend.php Normal file
View File

@@ -0,0 +1,186 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Frontend.php,v 1.9 2006/03/03 13:13:07 pajoye 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
*
* Note that frontend classes must implement userConfirm(), and shoul implement
* displayFatalError() and outputData()
* @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.4.11
* @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 (method_exists($obj, 'userConfirm')) {
$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;
}
// quick test to see if this class implements a few of the most
// important frontend methods
if (method_exists($uiobject, 'userConfirm')) {
$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
$GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
return $uiobject;
} else {
$err = PEAR::raiseError("not a value frontend class: (" . get_class($uiobject)
. ')');
return $err;
}
}
/**
* @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 (!$test) { // support wrappers like phar (realpath just don't work with them)
$test = $include . DIRECTORY_SEPARATOR . $path;
}
if (file_exists($test) && is_readable($test)) {
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;
}
function log($msg, $append_crlf = true)
{
}
}
?>

View File

@@ -0,0 +1,742 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: CLI.php,v 1.59 2006/03/02 13:16:19 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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;
}
}
@$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']] = '';
}
}
do {
$ok = array('yesno' => 'no');
do {
$answers = $this->userDialog('', $prompts, $types, $answers);
} while (count(array_filter($answers)) != count($prompts));
$this->outputData('Your choices:');
foreach ($prompts as $name => $prompt) {
$this->outputData($prompt . ': ' . $answers[$name]);
}
$ok = $this->userDialog('',
array(
'yesno' => 'These Choices OK? (use "abort" to halt)'
),
array(
'yesno' => 'string',
),
array(
'yesno' => 'yes'
)
);
if ($ok['yesno'] == 'abort') {
return false;
}
} while ($ok['yesno'] != 'yes');
return $answers;
}
// {{{ userDialog(prompt, [type], [default])
function userDialog($command, $prompts, $types = array(), $defaults = array())
{
$result = array();
if (is_array($prompts)) {
// php 5.0.0 inexplicably breaks BC with this behavior
// now reading from STDIN is the intended syntax
if (version_compare(phpversion(), '5.0.0', '<')) {
$fp = fopen("php://stdin", "r");
}
foreach ($prompts as $key => $prompt) {
$type = $types[$key];
$default = @$defaults[$key];
if ($type == 'password') {
system('stty -echo');
}
print "$this->lp$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 ($type == 'password') {
system('stty echo');
print "\n";
}
if ($default && trim($line) == "") {
$result[$key] = $default;
} else {
$result[$key] = trim($line);
}
}
if (version_compare(phpversion(), '5.0.0', '<')) {
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':
$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':
$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']),
),
);
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'];
}
// }}}
}
?>

1592
lib/pear/PEAR/Installer.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Role.php,v 1.13 2006/01/06 04:47: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';
//$GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
/**
* @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.4.11
* @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($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. php files
* serve no purpose in extsrc or extbin 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)) {
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)) {
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)) {
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)
{
$parser = new PEAR_XMLParser;
if ($dir === null) {
$dir = dirname(__FILE__) . '/Role';
}
$dp = @opendir($dir);
if (empty($dp)) {
return PEAR::raiseError("registerRoles: opendir($dir) failed");
}
while ($entry = readdir($dp)) {
if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
continue;
}
$class = "PEAR_Installer_Role_".substr($entry, 0, -4);
// List of roles
if (empty($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;
}
}
?>

View File

@@ -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.10 2006/01/06 04:47:37 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.4.11
* @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'],
null, $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'],
null, $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'];
}
}
?>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Data.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,13 @@
<role version="1.0">
<releasetypes>php</releasetypes>
<releasetypes>extsrc</releasetypes>
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>data_dir</locationconfig>
<honorsbaseinstall />
<unusualbaseinstall />
<phpfile />
<executable />
<phpextension />
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Doc.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,13 @@
<role version="1.0">
<releasetypes>php</releasetypes>
<releasetypes>extsrc</releasetypes>
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>doc_dir</locationconfig>
<honorsbaseinstall />
<unusualbaseinstall />
<phpfile />
<executable />
<phpextension />
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Ext.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,11 @@
<role version="1.0">
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>ext_dir</locationconfig>
<honorsbaseinstall>1</honorsbaseinstall>
<unusualbaseinstall />
<phpfile />
<executable />
<phpextension>1</phpextension>
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Php.php,v 1.7 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,13 @@
<role version="1.0">
<releasetypes>php</releasetypes>
<releasetypes>extsrc</releasetypes>
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>php_dir</locationconfig>
<honorsbaseinstall>1</honorsbaseinstall>
<unusualbaseinstall />
<phpfile>1</phpfile>
<executable />
<phpextension />
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Script.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,13 @@
<role version="1.0">
<releasetypes>php</releasetypes>
<releasetypes>extsrc</releasetypes>
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>bin_dir</locationconfig>
<honorsbaseinstall>1</honorsbaseinstall>
<unusualbaseinstall />
<phpfile />
<executable>1</executable>
<phpextension />
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Src.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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++;
}
}
?>

View File

@@ -0,0 +1,11 @@
<role version="1.0">
<releasetypes>extsrc</releasetypes>
<installable />
<locationconfig />
<honorsbaseinstall />
<unusualbaseinstall />
<phpfile />
<executable />
<phpextension />
<config_vars />
</role>

View File

@@ -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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Test.php,v 1.6 2006/01/06 04:47:37 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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 {}
?>

View File

@@ -0,0 +1,13 @@
<role version="1.0">
<releasetypes>php</releasetypes>
<releasetypes>extsrc</releasetypes>
<releasetypes>extbin</releasetypes>
<installable>1</installable>
<locationconfig>test_dir</locationconfig>
<honorsbaseinstall />
<unusualbaseinstall />
<phpfile />
<executable />
<phpextension />
<config_vars />
</role>

View File

@@ -0,0 +1,441 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: PackageFile.php,v 1.33.2.1 2006/06/08 00:04:13 pajoye 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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 1.4.11
* @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'))) {
return PEAR::raiseError('package.xml version "' . $packageversion[1] .
'" is not supported, only 1.0 and 2.0 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) && !@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);
}
if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
$ret = PEAR::raiseError('could not extract the package.xml file from "' .
$origfile . '"');
return $ret;
}
$ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
return $ret;
}
/**
* 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 &&
!@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
if (function_exists('file_get_contents')) {
@fclose($fp);
$data = file_get_contents($descfile);
} else {
$data = '';
while (!feof($fp)) {
$data .= @fread($fp, 8192);
}
fclose($fp);
}
$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)) {
$info = PEAR::raiseError("'$info' is a directory, a file is expected");
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;
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,461 @@
<?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-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: v1.php,v 1.21 2006/01/06 04:47:37 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-2006 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) {
return PEAR::raiseError('Cannot create xml parser for parsing package.xml');
}
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);
return PEAR::raiseError(sprintf("XML error: %s at line %d",
$str = xml_error_string($code), $line), 2);
}
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";
}
}
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;
}
}
// }}}
}
?>

Some files were not shown because too many files have changed in this diff Show More