Subversion Repositories Applications.papyrus

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1973 → Rev 1974

/branches/v1.0-menes/api/pear/Auth/Container/File.php
New file
0,0 → 1,200
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Stefan Ekman <stekman@sedata.org> |
// | Martin Jansen <mj@php.net> |
// | Mika Tuupola <tuupola@appelsiini.net> |
// +----------------------------------------------------------------------+
//
// $Id: File.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "File/Passwd.php";
require_once "Auth/Container.php";
require_once "PEAR.php";
 
/**
* Storage driver for fetching login data from an encrypted password file.
*
* This storage container can handle CVS pserver style passwd files.
*
* @author Stefan Ekman <stekman@sedata.org>
* @author Michael Wallner <mike@php.net>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_File extends Auth_Container
{
/**
* Path to passwd file
*
* @var string
*/
var $pwfile = '';
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* @param string $filename path to passwd file
* @return object Auth_Container_File new Auth_Container_File object
*/
function Auth_Container_File($filename)
{
$this->pwfile = $filename;
}
 
// }}}
// {{{ fetchData()
 
/**
* Authenticate an user
*
* @param string username
* @param string password
* @return mixed boolean|PEAR_Error
*/
function fetchData($user, $pass)
{
return File_Passwd::staticAuth('Cvs', $this->pwfile, $user, $pass);
}
 
// }}}
// {{{ listUsers()
/**
* List all available users
*
* @return array
*/
function listUsers()
{
$pw_obj = &$this->_load();
if (PEAR::isError($pw_obj)) {
return array();
}
 
$users = $pw_obj->listUser();
if (!is_array($users)) {
return array();
}
 
foreach ($users as $key => $value) {
$retVal[] = array("username" => $key,
"password" => $value['passwd'],
"cvsuser" => $value['system']);
}
 
return $retVal;
}
 
// }}}
// {{{ addUser()
 
/**
* Add a new user to the storage container
*
* @param string username
* @param string password
* @param mixed CVS username
*
* @return boolean
*/
function addUser($user, $pass, $additional='')
{
$cvs = (string) (is_array($additional) && isset($additional['cvsuser'])) ?
$additional['cvsuser'] : $additional;
 
$pw_obj = &$this->_load();
if (PEAR::isError($pw_obj)) {
return false;
}
$res = $pw_obj->addUser($user, $pass, $cvs);
if(PEAR::isError($res)){
return false;
}
$res = $pw_obj->save();
if (PEAR::isError($res)) {
return false;
}
return true;
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @param string Username
* @return boolean
*/
function removeUser($user)
{
$pw_obj = &$this->_load();
if (PEAR::isError($pw_obj)) {
return false;
}
$res = $pw_obj->delUser($user);
if(PEAR::isError($res)){
return false;
}
$res = $pw_obj->save();
if (PEAR::isError($res)) {
return false;
}
return true;
}
 
// }}}
// {{{ _load()
/**
* Load and initialize the File_Passwd object
*
* @return object File_Passwd_Cvs|PEAR_Error
*/
function &_load()
{
static $pw_obj;
if (!isset($pw_obj)) {
$pw_obj = File_Passwd::factory('Cvs');
if (PEAR::isError($pw_obj)) {
return $pw_obj;
}
$pw_obj->setFile($this->pwfile);
$res = $pw_obj->load();
if (PEAR::isError($res)) {
return $res;
}
}
return $pw_obj;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/LDAP.php
New file
0,0 → 1,472
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Jan Wagner <wagner@netsols.de> |
// +----------------------------------------------------------------------+
//
// $Id: LDAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "Auth/Container.php";
require_once "PEAR.php";
 
/**
* Storage driver for fetching login data from LDAP
*
* This class is heavily based on the DB and File containers. By default it
* connects to localhost:389 and searches for uid=$username with the scope
* "sub". If no search base is specified, it will try to determine it via
* the namingContexts attribute. It takes its parameters in a hash, connects
* to the ldap server, binds anonymously, searches for the user, and tries
* to bind as the user with the supplied password. When a group was set, it
* will look for group membership of the authenticated user. If all goes
* well the authentication was successful.
*
* Parameters:
*
* host: localhost (default), ldap.netsols.de or 127.0.0.1
* port: 389 (default) or 636 or whereever your server runs
* url: ldap://localhost:389/
* useful for ldaps://, works only with openldap2 ?
* it will be preferred over host and port
* binddn: If set, searching for user will be done after binding
* as this user, if not set the bind will be anonymous.
* This is reported to make the container work with MS
* Active Directory, but should work with any server that
* is configured this way.
* This has to be a complete dn for now (basedn and
* userdn will not be appended).
* bindpw: The password to use for binding with binddn
* scope: one, sub (default), or base
* basedn: the base dn of your server
* userdn: gets prepended to basedn when searching for user
* userattr: the user attribute to search for (default: uid)
* useroc: objectclass of user (for the search filter)
* (default: posixAccount)
* groupdn: gets prepended to basedn when searching for group
* groupattr : the group attribute to search for (default: cn)
* groupoc : objectclass of group (for the search filter)
* (default: groupOfUniqueNames)
* memberattr : the attribute of the group object where the user dn
* may be found (default: uniqueMember)
* memberisdn: whether the memberattr is the dn of the user (default)
* or the value of userattr (usually uid)
* group: the name of group to search for
* debug: Enable/Disable debugging output (default: false)
*
* To use this storage container, you have to use the following syntax:
*
* <?php
* ...
*
* $a = new Auth("LDAP", array(
* 'host' => 'localhost',
* 'port' => '389',
* 'basedn' => 'o=netsols,c=de',
* 'userattr' => 'uid'
* 'binddn' => 'cn=admin,o=netsols,c=de',
* 'bindpw' => 'password'));
*
* $a2 = new Auth('LDAP', array(
* 'url' => 'ldaps://ldap.netsols.de',
* 'basedn' => 'o=netsols,c=de',
* 'scope' => 'one',
* 'userdn' => 'ou=People',
* 'groupdn' => 'ou=Groups',
* 'groupoc' => 'posixGroup',
* 'memberattr' => 'memberUid',
* 'memberisdn' => false,
* 'group' => 'admin'
* ));
*
* $a3 = new Auth('LDAP', array(
* 'host' => 'ad.netsols.de',
* 'basedn' => 'dc=netsols,dc=de',
* 'userdn' => 'ou=Users',
* 'binddn' => 'cn=Jan Wagner,ou=Users,dc=netsols,dc=de',
* 'bindpw' => '*******',
* 'userattr' => 'samAccountName',
* 'useroc' => 'user',
* 'debug' => true
* ));
*
* The parameter values have to correspond
* to the ones for your LDAP server of course.
*
* When talking to a Microsoft ActiveDirectory server you have to
* use 'samaccountname' as the 'userattr' and follow special rules
* to translate the ActiveDirectory directory names into 'basedn'.
* The 'basedn' for the default 'Users' folder on an ActiveDirectory
* server for the ActiveDirectory Domain (which is not related to
* its DNS name) "win2000.example.org" would be:
* "CN=Users, DC=win2000, DC=example, DC=org'
* where every component of the domain name becomes a DC attribute
* of its own. If you want to use a custom users folder you have to
* replace "CN=Users" with a sequence of "OU" attributes that specify
* the path to your custom folder in reverse order.
* So the ActiveDirectory folder
* "win2000.example.org\Custom\Accounts"
* would become
* "OU=Accounts, OU=Custom, DC=win2000, DC=example, DC=org'
*
* It seems that binding anonymously to an Active Directory
* is not allowed, so you have to set binddn and bindpw for
* user searching,
*
* Example a3 shows a tested example for connenction to Windows 2000
* Active Directory
*
* @author Jan Wagner <wagner@netsols.de>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_LDAP extends Auth_Container
{
/**
* Options for the class
* @var array
*/
var $options = array();
 
/**
* Connection ID of LDAP Link
* @var string
*/
var $conn_id = false;
 
/**
* LDAP search function to use
* @var string
*/
var $ldap_search_func;
 
/**
* Constructor of the container class
*
* @param $params, associative hash with host,port,basedn and userattr key
* @return object Returns an error object if something went wrong
*/
function Auth_Container_LDAP($params)
{
$this->_setDefaults();
 
if (is_array($params)) {
$this->_parseOptions($params);
}
}
 
// }}}
// {{{ _connect()
 
/**
* Connect to the LDAP server using the global options
*
* @access private
* @return object Returns a PEAR error object if an error occurs.
*/
function _connect()
{
// connect
if (isset($this->options['url']) && $this->options['url'] != '') {
$this->_debug('Connecting with URL', __LINE__);
$conn_params = array($this->options['url']);
} else {
$this->_debug('Connecting with host:port', __LINE__);
$conn_params = array($this->options['host'], $this->options['port']);
}
 
if(($this->conn_id = @call_user_func_array('ldap_connect', $conn_params)) === false) {
return PEAR::raiseError('Auth_Container_LDAP: Could not connect to server.', 41, PEAR_ERROR_DIE);
}
$this->_debug('Successfully connected to server', __LINE__);
 
// try switchig to LDAPv3
$ver = 0;
if(@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver >= 2) {
$this->_debug('Switching to LDAPv3', __LINE__);
@ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, 3);
}
 
// bind with credentials or anonymously
if($this->options['binddn'] && $this->options['bindpw']) {
$this->_debug('Binding with credentials', __LINE__);
$bind_params = array($this->conn_id, $this->options['binddn'], $this->options['bindpw']);
} else {
$this->_debug('Binding anonymously', __LINE__);
$bind_params = array($this->conn_id);
}
// bind for searching
if ((@call_user_func_array('ldap_bind', $bind_params)) == false) {
$this->_debug();
$this->_disconnect();
return PEAR::raiseError("Auth_Container_LDAP: Could not bind to LDAP server.", 41, PEAR_ERROR_DIE);
}
$this->_debug('Binding was successful', __LINE__);
}
 
/**
* Disconnects (unbinds) from ldap server
*
* @access private
*/
function _disconnect()
{
if($this->_isValidLink()) {
$this->_debug('disconnecting from server');
@ldap_unbind($this->conn_id);
}
}
 
/**
* Tries to find Basedn via namingContext Attribute
*
* @access private
*/
function _getBaseDN()
{
if ($this->options['basedn'] == "" && $this->_isValidLink()) {
$this->_debug("basedn not set, searching via namingContexts.", __LINE__);
 
$result_id = @ldap_read($this->conn_id, "", "(objectclass=*)", array("namingContexts"));
if (ldap_count_entries($this->conn_id, $result_id) == 1) {
$this->_debug("got result for namingContexts", __LINE__);
$entry_id = ldap_first_entry($this->conn_id, $result_id);
$attrs = ldap_get_attributes($this->conn_id, $entry_id);
$basedn = $attrs['namingContexts'][0];
 
if ($basedn != "") {
$this->_debug("result for namingContexts was $basedn", __LINE__);
$this->options['basedn'] = $basedn;
}
}
ldap_free_result($result_id);
}
 
// if base ist still not set, raise error
if ($this->options['basedn'] == "") {
return PEAR::raiseError("Auth_Container_LDAP: LDAP search base not specified!", 41, PEAR_ERROR_DIE);
}
return true;
}
 
/**
* determines whether there is a valid ldap conenction or not
*
* @accessd private
* @return boolean
*/
function _isValidLink()
{
if(is_resource($this->conn_id)) {
if(get_resource_type($this->conn_id) == 'ldap link') {
return true;
}
}
return false;
}
 
/**
* Set some default options
*
* @access private
*/
function _setDefaults()
{
$this->options['host'] = 'localhost';
$this->options['port'] = '389';
$this->options['binddn'] = '';
$this->options['bindpw'] = '';
$this->options['scope'] = 'sub';
$this->options['basedn'] = '';
$this->options['userdn'] = '';
$this->options['userattr'] = "uid";
$this->options['useroc'] = 'posixAccount';
$this->options['groupdn'] = '';
$this->options['groupattr'] = 'cn';
$this->options['groupoc'] = 'groupOfUniqueNames';
$this->options['memberattr'] = 'uniqueMember';
$this->options['memberisdn'] = true;
$this->options['debug'] = false;
}
 
/**
* Parse options passed to the container class
*
* @access private
* @param array
*/
function _parseOptions($array)
{
foreach ($array as $key => $value) {
$this->options[$key] = $value;
}
 
// get the according search function for selected scope
switch($this->options['scope']) {
case 'one':
$this->ldap_search_func = 'ldap_list';
break;
case 'base':
$this->ldap_search_func = 'ldap_read';
break;
default:
$this->ldap_search_func = 'ldap_search';
break;
}
$this->_debug("LDAP search function will be: {$this->ldap_search_func}", __LINE__);
}
 
/**
* Fetch data from LDAP server
*
* Searches the LDAP server for the given username/password
* combination.
*
* @param string Username
* @param string Password
* @return boolean
*/
function fetchData($username, $password)
{
 
$this->_connect();
$this->_getBaseDN();
// make search filter
$filter = sprintf('(&(objectClass=%s)(%s=%s))', $this->options['useroc'], $this->options['userattr'], $username);
 
// make search base dn
$search_basedn = $this->options['userdn'];
if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
$search_basedn .= ',';
}
$search_basedn .= $this->options['basedn'];
// make functions params array
$func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['userattr']));
 
$this->_debug("Searching with $filter in $search_basedn", __LINE__);
 
// search
if (($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) == false) {
$this->_debug('User not found', __LINE__);
} elseif (ldap_count_entries($this->conn_id, $result_id) == 1) { // did we get just one entry?
 
$this->_debug('User was found', __LINE__);
// then get the user dn
$entry_id = ldap_first_entry($this->conn_id, $result_id);
$user_dn = ldap_get_dn($this->conn_id, $entry_id);
 
ldap_free_result($result_id);
 
// need to catch an empty password as openldap seems to return TRUE
// if anonymous binding is allowed
if ($password != "") {
$this->_debug("Bind as $user_dn", __LINE__);
 
// try binding as this user with the supplied password
if (@ldap_bind($this->conn_id, $user_dn, $password)) {
$this->_debug('Bind successful', __LINE__);
 
// check group if appropiate
if(isset($this->options['group'])) {
// decide whether memberattr value is a dn or the username
$this->_debug('Checking group membership', __LINE__);
return $this->checkGroup(($this->options['memberisdn']) ? $user_dn : $username);
} else {
$this->_debug('Authenticated', __LINE__);
$this->_disconnect();
return true; // user authenticated
} // checkGroup
} // bind
} // non-empty password
} // one entry
// default
$this->_debug('NOT authenticated!', __LINE__);
$this->_disconnect();
return false;
}
 
/**
* Validate group membership
*
* Searches the LDAP server for group membership of the
* authenticated user
*
* @param string Distinguished Name of the authenticated User
* @return boolean
*/
function checkGroup($user)
{
// make filter
$filter = sprintf('(&(%s=%s)(objectClass=%s)(%s=%s))',
$this->options['groupattr'],
$this->options['group'],
$this->options['groupoc'],
$this->options['memberattr'],
$user
);
 
// make search base dn
$search_basedn = $this->options['groupdn'];
if($search_basedn != '' && substr($search_basedn, -1) != ',') {
$search_basedn .= ',';
}
$search_basedn .= $this->options['basedn'];
$func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['memberattr']));
 
$this->_debug("Searching with $filter in $search_basedn", __LINE__);
// search
if(($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) != false) {
if(ldap_count_entries($this->conn_id, $result_id) == 1) {
ldap_free_result($result_id);
$this->_debug('User is member of group', __LINE__);
$this->_disconnect();
return true;
}
}
 
// default
$this->_debug('User is NOT member of group', __LINE__);
$this->_disconnect();
return false;
}
 
/**
* Outputs debugging messages
*
* @access private
* @param string Debugging Message
* @param integer Line number
*/
function _debug($msg = '', $line = 0)
{
if($this->options['debug'] === true) {
if($msg == '' && $this->_isValidLink()) {
$msg = 'LDAP_Error: ' . @ldap_err2str(@ldap_errno($this->_conn_id));
}
print("$line: $msg <br />");
}
}
}
 
?>
/branches/v1.0-menes/api/pear/Auth/Container/POP3.php
New file
0,0 → 1,107
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Stefan Ekman <stekman@sedata.org> |
// | Martin Jansen <mj@php.net> |
// | Mika Tuupola <tuupola@appelsiini.net> |
// +----------------------------------------------------------------------+
//
// $Id: POP3.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
 
require_once('Auth/Container.php');
require_once('PEAR.php');
require_once('Net/POP3.php');
 
/**
* Storage driver for Authentication on a POP3 server.
*
* @author Yavor Shahpasov <yavo@netsmart.com.cy>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_POP3 extends Auth_Container
{
/**
* POP3 Server
* @var string
*/
var $server='localhost';
 
/**
* POP3 Server port
* @var string
*/
var $port='110';
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* @param $server string server or server:port combination
* @return object Returns an error object if something went wrong
*/
function Auth_Container_POP3($server=null)
{
if(isset($server)){
if(is_array($server)){
if(isset($server['host'])){
$this->server = $server['host'];
}
if(isset($server['port'])){
$this->port = $server['port'];
}
}
else{
if(strstr($server, ':')){
$serverparts = explode(':', trim($server));
$this->server = $serverparts[0];
$this->port = $serverparts[1];
}
else
{
$this->server = $server;
}
}
}
}
 
// }}}
// {{{ fetchData()
 
/**
* Try to login to the POP3 server
*
* @param string Username
* @param string Password
* @return boolean
*/
function fetchData($username, $password)
{
$pop3 =& new Net_POP3();
$res = $pop3->connect($this->server, $this->port);
if(!$res){
return($res);
}
$result = $pop3->login($username, $password);
$pop3->disconnect();
return $result;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/MDB.php
New file
0,0 → 1,392
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Lorenzo Alberton <l.alberton@quipo.it> |
// +----------------------------------------------------------------------+
//
// $Id: MDB.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once 'Auth/Container.php';
require_once 'MDB.php';
 
/**
* Storage driver for fetching login data from a database
*
* This storage driver can use all databases which are supported
* by the PEAR MDB abstraction layer to fetch login data.
*
* @author Lorenzo Alberton <l.alberton@quipo.it>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_MDB extends Auth_Container
{
 
/**
* Additional options for the storage container
* @var array
*/
var $options = array();
 
/**
* DB object
* @var object
*/
var $db = null;
var $dsn = '';
 
/**
* User that is currently selected from the DB.
* @var string
*/
var $activeUser = '';
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* Initate connection to the database via PEAR::DB
*
* @param string Connection data or DB object
* @return object Returns an error object if something went wrong
*/
function Auth_Container_MDB($dsn)
{
$this->_setDefaults();
 
if (is_array($dsn)) {
$this->_parseOptions($dsn);
if (empty($this->options['dsn'])) {
PEAR::raiseError('No connection parameters specified!');
}
} else {
$this->options['dsn'] = $dsn;
}
}
 
// }}}
// {{{ _connect()
 
/**
* Connect to database by using the given DSN string
*
* @access private
* @param string DSN string
* @return mixed Object on error, otherwise bool
*/
function _connect($dsn)
{
if (is_string($dsn) || is_array($dsn)) {
$this->db =& MDB::Connect($dsn);
} elseif (get_parent_class($dsn) == "mdb_common") {
$this->db = $dsn;
} elseif (is_object($dsn) && MDB::isError($dsn)) {
return PEAR::raiseError($dsn->getMessage(), $dsn->code);
} else {
return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__,
41,
PEAR_ERROR_RETURN,
null,
null
);
 
}
 
if (MDB::isError($this->db) || PEAR::isError($this->db)) {
return PEAR::raiseError($this->db->getMessage(), $this->db->code);
} else {
return true;
}
}
 
// }}}
// {{{ _prepare()
 
/**
* Prepare database connection
*
* This function checks if we have already opened a connection to
* the database. If that's not the case, a new connection is opened.
*
* @access private
* @return mixed True or a DB error object.
*/
function _prepare()
{
return $this->_connect($this->options['dsn']);
}
 
// }}}
// {{{ query()
 
/**
* Prepare query to the database
*
* This function checks if we have already opened a connection to
* the database. If that's not the case, a new connection is opened.
* After that the query is passed to the database.
*
* @access public
* @param string Query string
* @return mixed a MDB_result object or MDB_OK on success, a MDB
* or PEAR error on failure
*/
function query($query)
{
$err = $this->_prepare();
if ($err !== true) {
return $err;
}
return $this->db->query($query);
}
 
// }}}
// {{{ _setDefaults()
 
/**
* Set some default options
*
* @access private
* @return void
*/
function _setDefaults()
{
$this->options['table'] = 'auth';
$this->options['usernamecol'] = 'username';
$this->options['passwordcol'] = 'password';
$this->options['dsn'] = '';
$this->options['db_fields'] = '';
$this->options['cryptType'] = 'md5';
}
 
// }}}
// {{{ _parseOptions()
 
/**
* Parse options passed to the container class
*
* @access private
* @param array
*/
function _parseOptions($array)
{
foreach ($array as $key => $value) {
if (isset($this->options[$key])) {
$this->options[$key] = $value;
}
}
 
// Include additional fields if they exist
if (!empty($this->options['db_fields'])) {
if (is_array($this->options['db_fields'])) {
$this->options['db_fields'] = join($this->options['db_fields'], ', ');
}
$this->options['db_fields'] = ', ' . $this->options['db_fields'];
}
 
}
 
// }}}
// {{{ fetchData()
 
/**
* Get user information from database
*
* This function uses the given username to fetch
* the corresponding login data from the database
* table. If an account that matches the passed username
* and password is found, the function returns true.
* Otherwise it returns false.
*
* @param string Username
* @param string Password
* @return mixed Error object or boolean
*/
function fetchData($username, $password)
{
// Prepare for a database query
$err = $this->_prepare();
if ($err !== true) {
return PEAR::raiseError($err->getMessage(), $err->getCode());
}
 
// Find if db_fileds contains a *, i so assume all col are selected
if (strstr($this->options['db_fields'], '*')) {
$sql_from = '*';
} else{
$sql_from = $this->options['usernamecol'] . ', '. $this->options['passwordcol'] . $this->options['db_fields'];
}
 
$query = sprintf("SELECT %s FROM %s WHERE %s = %s",
$sql_from,
$this->options['table'],
$this->options['usernamecol'],
$this->db->getTextValue($username)
);
 
$res = $this->db->getRow($query, null, null, null, MDB_FETCHMODE_ASSOC);
 
if (MDB::isError($res) || PEAR::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
}
if (!is_array($res)) {
$this->activeUser = '';
return false;
}
if ($this->verifyPassword(trim($password, "\r\n"),
trim($res[$this->options['passwordcol']], "\r\n"),
$this->options['cryptType'])) {
// Store additional field values in the session
foreach ($res as $key => $value) {
if ($key == $this->options['passwordcol'] ||
$key == $this->options['usernamecol']) {
continue;
}
// Use reference to the auth object if exists
// This is because the auth session variable can change so a static call to setAuthData does not make sence
if(is_object($this->_auth_obj)){
$this->_auth_obj->setAuthData($key, $value);
} else {
Auth::setAuthData($key, $value);
}
}
 
return true;
}
 
$this->activeUser = $res[$this->options['usernamecol']];
return false;
}
 
// }}}
// {{{ listUsers()
 
function listUsers()
{
$err = $this->_prepare();
if ($err !== true) {
return PEAR::raiseError($err->getMessage(), $err->getCode());
}
 
$retVal = array();
 
// Find if db_fileds contains a *, i so assume all col are selected
if (strstr($this->options['db_fields'], '*')) {
$sql_from = '*';
} else{
$sql_from = $this->options['db_fields'];
}
 
$query = sprintf('SELECT %s FROM %s',
$sql_from,
$this->options['table']
);
 
$res = $this->db->getAll($query, null, null, null, MDB_FETCHMODE_ASSOC);
 
if (MDB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
} else {
foreach ($res as $user) {
$user['username'] = $user[$this->options['usernamecol']];
$retVal[] = $user;
}
}
return $retVal;
}
 
// }}}
// {{{ addUser()
 
/**
* Add user to the storage container
*
* @access public
* @param string Username
* @param string Password
* @param mixed Additional information that are stored in the DB
*
* @return mixed True on success, otherwise error object
*/
function addUser($username, $password, $additional = "")
{
if (function_exists($this->options['cryptType'])) {
$cryptFunction = $this->options['cryptType'];
} else {
$cryptFunction = 'md5';
}
 
$additional_key = '';
$additional_value = '';
 
if (is_array($additional)) {
foreach ($additional as $key => $value) {
$additional_key .= ', ' . $key;
$additional_value .= ', ' . $this->db->getTextValue($value);
}
}
 
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)",
$this->options['table'],
$this->options['usernamecol'],
$this->options['passwordcol'],
$additional_key,
$this->db->getTextValue($username),
$this->db->getTextValue($cryptFunction($password)),
$additional_value
);
 
$res = $this->query($query);
 
if (MDB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->code);
} else {
return true;
}
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @access public
* @param string Username
*
* @return mixed True on success, otherwise error object
*/
function removeUser($username)
{
$query = sprintf("DELETE FROM %s WHERE %s = %s",
$this->options['table'],
$this->options['usernamecol'],
$this->db->getTextValue($username)
);
 
$res = $this->query($query);
 
if (MDB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->code);
} else {
return true;
}
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/SOAP.php
New file
0,0 → 1,170
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Bruno Pedro <bpedro@co.sapo.pt> |
// +----------------------------------------------------------------------+
//
// $Id: SOAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "Auth/Container.php";
require_once "PEAR.php";
require_once 'SOAP/Client.php';
 
/**
* Storage driver for fetching login data from SOAP
*
* This class takes one parameter (options), where
* you specify the following fields: endpoint, namespace,
* method, encoding, usernamefield and passwordfield.
*
* You can use specify features of your SOAP service
* by providing its parameters in an associative manner by
* using the '_features' array through the options parameter.
*
* The 'matchpassword' option should be set to false if your
* webservice doesn't return (username,password) pairs, but
* instead returns error when the login is invalid.
*
* Example usage:
*
* <?php
*
* ...
*
* $options = array (
* 'endpoint' => 'http://your.soap.service/endpoint',
* 'namespace' => 'urn:/Your/Namespace',
* 'method' => 'get',
* 'encoding' => 'UTF-8',
* 'usernamefield' => 'login',
* 'passwordfield' => 'password',
* 'matchpasswords' => false,
* '_features' => array (
* 'example_feature' => 'example_value',
* 'another_example' => ''
* )
* );
* $auth = new Auth('SOAP', $options, 'loginFunction');
* $auth->start();
*
* ...
*
* ?>
*
* @author Bruno Pedro <bpedro@co.sapo.pt>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_SOAP extends Auth_Container
{
 
/**
* Required options for the class
* @var array
* @access private
*/
var $_requiredOptions = array('endpoint', 'namespace', 'method', 'encoding', 'usernamefield', 'passwordfield');
 
/**
* Options for the class
* @var array
* @access private
*/
var $_options = array();
 
/**
* Optional SOAP features
* @var array
* @access private
*/
var $_features = array();
 
/**
* The SOAP response
* @var array
* @access public
*/
var $soapResponse = array();
 
/**
* Constructor of the container class
*
* @param $options, associative array with endpoint, namespace, method,
* usernamefield, passwordfield and optional features
*/
function Auth_Container_SOAP($options)
{
$this->_options = $options;
if (!isset($this->_options['matchpasswords'])) {
$this->_options['matchpasswords'] = true;
}
if (!empty($this->_options['_features'])) {
$this->_features = $this->_options['_features'];
unset($this->_options['_features']);
}
}
 
/**
* Fetch data from SOAP service
*
* Requests the SOAP service for the given username/password
* combination.
*
* @param string Username
* @param string Password
* @return mixed Returns the SOAP response or false if something went wrong
*/
function fetchData($username, $password)
{
// check if all required options are set
if (array_intersect($this->_requiredOptions, array_keys($this->_options)) != $this->_requiredOptions) {
return false;
} else {
// create a SOAP client and set encoding
$soapClient = new SOAP_Client($this->_options['endpoint']);
$soapClient->setEncoding($this->_options['encoding']);
}
// assign username and password fields
$usernameField = new SOAP_Value($this->_options['usernamefield'],'string', $username);
$passwordField = new SOAP_Value($this->_options['passwordfield'],'string', $password);
$SOAPParams = array($usernameField, $passwordField);
// assign optional features
foreach ($this->_features as $fieldName => $fieldValue) {
$SOAPParams[] = new SOAP_Value($fieldName, 'string', $fieldValue);
}
// make SOAP call
$this->soapResponse = $soapClient->call(
$this->_options['method'],
$SOAPParams,
array('namespace' => $this->_options['namespace'])
);
if (!PEAR::isError($this->soapResponse)) {
if ($this->_options['matchpasswords']) {
// check if passwords match
if ($password == $this->soapResponse->{$this->_options['passwordfield']}) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/SMBPasswd.php
New file
0,0 → 1,134
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Michael Bretterklieber <michael@bretterklieber.com> |
// +----------------------------------------------------------------------+
//
// $Id: SMBPasswd.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "File/SMBPasswd.php";
require_once "Auth/Container.php";
require_once "PEAR.php";
 
/**
* Storage driver for fetching login data from an SAMBA smbpasswd file.
*
* This storage container can handle SAMBA smbpasswd files.
*
* Example:
* $a = new Auth("SMBPasswd", '/usr/local/private/smbpasswd');
* $a->start();
* if ($a->getAuth()) {
* printf ("AUTH OK<br>\n");
* $a->logout();
* }
*
* @author Michael Bretterklieber <michael@bretterklieber.com>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_SMBPasswd extends Auth_Container
{
/**
* File_SMBPasswd object
* @var object
*/
var $pwfile;
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* @param $filename string filename for a passwd type file
* @return object Returns an error object if something went wrong
*/
function Auth_Container_SMBPasswd($filename)
{
$this->pwfile = new File_SMBPasswd($filename,0);
 
if (!$this->pwfile->load()) {
PEAR::raiseError("Error while reading file contents.", 41, PEAR_ERROR_DIE);
return;
}
 
}
 
// }}}
// {{{ fetchData()
 
/**
* Get user information from pwfile
*
* @param string Username
* @param string Password
* @return boolean
*/
function fetchData($username, $password)
{
return $this->pwfile->verifyAccount($username, $password);
}
 
// }}}
// {{{ listUsers()
function listUsers()
{
return $this->pwfile->getAccounts();
}
 
// }}}
// {{{ addUser()
 
/**
* Add a new user to the storage container
*
* @param string Username
* @param string Password
* @param array Additional information
*
* @return boolean
*/
function addUser($username, $password, $additional = '')
{
$res = $this->pwfile->addUser($user, $additional['userid'], $pass);
if ($res === true) {
return $this->pwfile->save();
}
return $res;
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @param string Username
*/
function removeUser($username)
{
$res = $this->pwfile->delUser($username);
if ($res === true) {
return $this->pwfile->save();
}
return $res;
}
 
// }}}
 
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/DB.php
New file
0,0 → 1,409
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Martin Jansen <mj@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: DB.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once 'Auth/Container.php';
require_once 'DB.php';
 
/**
* Storage driver for fetching login data from a database
*
* This storage driver can use all databases which are supported
* by the PEAR DB abstraction layer to fetch login data.
*
* @author Martin Jansen <mj@php.net>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_DB extends Auth_Container
{
 
/**
* Additional options for the storage container
* @var array
*/
var $options = array();
 
/**
* DB object
* @var object
*/
var $db = null;
var $dsn = '';
 
/**
* User that is currently selected from the DB.
* @var string
*/
var $activeUser = '';
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* Initate connection to the database via PEAR::DB
*
* @param string Connection data or DB object
* @return object Returns an error object if something went wrong
*/
function Auth_Container_DB($dsn)
{
$this->_setDefaults();
 
if (is_array($dsn)) {
$this->_parseOptions($dsn);
 
if (empty($this->options['dsn'])) {
PEAR::raiseError('No connection parameters specified!');
}
} else {
$this->options['dsn'] = $dsn;
}
}
 
// }}}
// {{{ _connect()
 
/**
* Connect to database by using the given DSN string
*
* @access private
* @param string DSN string
* @return mixed Object on error, otherwise bool
*/
function _connect($dsn)
{
if (is_string($dsn) || is_array($dsn)) {
$this->db = DB::Connect($dsn);
} elseif (get_parent_class($dsn) == "db_common") {
$this->db = $dsn;
} elseif (DB::isError($dsn)) {
return PEAR::raiseError($dsn->getMessage(), $dsn->getCode());
} else {
return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__,
41,
PEAR_ERROR_RETURN,
null,
null
);
}
 
if (DB::isError($this->db) || PEAR::isError($this->db)) {
return PEAR::raiseError($this->db->getMessage(), $this->db->getCode());
} else {
return true;
}
}
 
// }}}
// {{{ _prepare()
 
/**
* Prepare database connection
*
* This function checks if we have already opened a connection to
* the database. If that's not the case, a new connection is opened.
*
* @access private
* @return mixed True or a DB error object.
*/
function _prepare()
{
if (!DB::isConnection($this->db)) {
$res = $this->_connect($this->options['dsn']);
if(DB::isError($res) || PEAR::isError($res)){
return $res;
}
}
return true;
}
 
// }}}
// {{{ query()
 
/**
* Prepare query to the database
*
* This function checks if we have already opened a connection to
* the database. If that's not the case, a new connection is opened.
* After that the query is passed to the database.
*
* @access public
* @param string Query string
* @return mixed a DB_result object or DB_OK on success, a DB
* or PEAR error on failure
*/
function query($query)
{
$err = $this->_prepare();
if ($err !== true) {
return $err;
}
return $this->db->query($query);
}
 
// }}}
// {{{ _setDefaults()
 
/**
* Set some default options
*
* @access private
* @return void
*/
function _setDefaults()
{
$this->options['table'] = 'auth';
$this->options['usernamecol'] = 'username';
$this->options['passwordcol'] = 'password';
$this->options['dsn'] = '';
$this->options['db_fields'] = '';
$this->options['cryptType'] = 'md5';
}
 
// }}}
// {{{ _parseOptions()
 
/**
* Parse options passed to the container class
*
* @access private
* @param array
*/
function _parseOptions($array)
{
foreach ($array as $key => $value) {
if (isset($this->options[$key])) {
$this->options[$key] = $value;
}
}
 
/* Include additional fields if they exist */
if(!empty($this->options['db_fields'])){
if(is_array($this->options['db_fields'])){
$this->options['db_fields'] = join($this->options['db_fields'], ', ');
}
$this->options['db_fields'] = ', '.$this->options['db_fields'];
}
}
 
// }}}
// {{{ fetchData()
 
/**
* Get user information from database
*
* This function uses the given username to fetch
* the corresponding login data from the database
* table. If an account that matches the passed username
* and password is found, the function returns true.
* Otherwise it returns false.
*
* @param string Username
* @param string Password
* @return mixed Error object or boolean
*/
function fetchData($username, $password)
{
// Prepare for a database query
$err = $this->_prepare();
if ($err !== true) {
return PEAR::raiseError($err->getMessage(), $err->getCode());
}
 
// Find if db_fileds contains a *, i so assume all col are selected
if(strstr($this->options['db_fields'], '*')){
$sql_from = "*";
}
else{
$sql_from = $this->options['usernamecol'] . ", ".$this->options['passwordcol'].$this->options['db_fields'];
}
/**
Old Style, removed to go around the oci8
problem
See bug 206
http://pear.php.net/bugs/bug.php?id=206
$query = "SELECT ! FROM ! WHERE ! = ?";
$query_params = array(
$sql_from,
$this->options['table'],
$this->options['usernamecol'],
$username
);
*/
$query = "SELECT ".$sql_from.
" FROM ".$this->options['table'].
" WHERE ".$this->options['usernamecol']." = '".$this->db->quoteString($username)."'";
$res = $this->db->getRow($query, null, DB_FETCHMODE_ASSOC);
 
if (DB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
}
if (!is_array($res)) {
$this->activeUser = '';
return false;
}
if ($this->verifyPassword(trim($password, "\r\n"),
trim($res[$this->options['passwordcol']], "\r\n"),
$this->options['cryptType'])) {
// Store additional field values in the session
foreach ($res as $key => $value) {
if ($key == $this->options['passwordcol'] ||
$key == $this->options['usernamecol']) {
continue;
}
// Use reference to the auth object if exists
// This is because the auth session variable can change so a static call to setAuthData does not make sence
if(is_object($this->_auth_obj)){
$this->_auth_obj->setAuthData($key, $value);
} else {
Auth::setAuthData($key, $value);
}
}
 
return true;
}
 
$this->activeUser = $res[$this->options['usernamecol']];
return false;
}
 
// }}}
// {{{ listUsers()
 
function listUsers()
{
$err = $this->_prepare();
if ($err !== true) {
return PEAR::raiseError($err->getMessage(), $err->getCode());
}
 
$retVal = array();
 
// Find if db_fileds contains a *, i so assume all col are selected
if(strstr($this->options['db_fields'], '*')){
$sql_from = "*";
}
else{
$sql_from = $this->options['usernamecol'] . ", ".$this->options['passwordcol'].$this->options['db_fields'];
}
 
$query = sprintf("SELECT %s FROM %s",
$sql_from,
$this->options['table']
);
$res = $this->db->getAll($query, null, DB_FETCHMODE_ASSOC);
 
if (DB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
} else {
foreach ($res as $user) {
$user['username'] = $user[$this->options['usernamecol']];
$retVal[] = $user;
}
}
return $retVal;
}
 
// }}}
// {{{ addUser()
 
/**
* Add user to the storage container
*
* @access public
* @param string Username
* @param string Password
* @param mixed Additional information that are stored in the DB
*
* @return mixed True on success, otherwise error object
*/
function addUser($username, $password, $additional = "")
{
if (function_exists($this->options['cryptType'])) {
$cryptFunction = $this->options['cryptType'];
} else {
$cryptFunction = 'md5';
}
 
$additional_key = '';
$additional_value = '';
 
if (is_array($additional)) {
foreach ($additional as $key => $value) {
$additional_key .= ', ' . $key;
$additional_value .= ", '" . $value . "'";
}
}
 
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES ('%s', '%s'%s)",
$this->options['table'],
$this->options['usernamecol'],
$this->options['passwordcol'],
$additional_key,
$username,
$cryptFunction($password),
$additional_value
);
 
$res = $this->query($query);
 
if (DB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
} else {
return true;
}
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @access public
* @param string Username
*
* @return mixed True on success, otherwise error object
*/
function removeUser($username)
{
$query = sprintf("DELETE FROM %s WHERE %s = '%s'",
$this->options['table'],
$this->options['usernamecol'],
$username
);
 
$res = $this->query($query);
 
if (DB::isError($res)) {
return PEAR::raiseError($res->getMessage(), $res->getCode());
} else {
return true;
}
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/IMAP.php
New file
0,0 → 1,170
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Jeroen Houben <jeroen@terena.nl> |
// +----------------------------------------------------------------------+
//
// $Id: IMAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "Auth/Container.php";
require_once "PEAR.php";
 
/**
* Storage driver for fetching login data from an IMAP server
*
* This class is based on LDAP containers, but it very simple.
* By default it connects to localhost:143
* The constructor will first check if the host:port combination is
* actually reachable. This behaviour can be disabled.
* It then tries to create an IMAP stream (without opening a mailbox)
* If you wish to pass extended options to the connections, you may
* do so by specifying protocol options.
*
* To use this storage containers, you have to use the
* following syntax:
*
* <?php
* ...
* $params = array(
* 'host' => 'mail.example.com',
* 'port' => 143,
* );
* $myAuth = new Auth('IMAP', $params);
* ....
*
* By default we connect without any protocol options set. However, some
* servers require you to connect with the notls or norsh options set.
* To do this you need to add the following value to the params array:
* 'baseDSN' => '/imap/notls/norsh'
*
* To connect to an SSL IMAP server:
* 'baseDSN' => '/imap/ssl'
*
* To connect to an SSL IMAP server with a self-signed certificate:
* 'baseDSN' => '/imap/ssl/novalidate-cert'
*
* Further options may be available and can be found on the php site at
* http://www.php.net/manual/function.imap-open.php
*
*/
 
/*
*
* @author Jeroen Houben <jeroen@terena.nl>, Cipriano Groenendal <cipri@campai.nl>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_IMAP extends Auth_Container
{
/**
* Options for the class
* @var array
*/
var $options = array();
 
/**
* Constructor of the container class
*
* @param $params, associative hash with host,port,basedn and userattr key
* @param $params, associative array with host, port, baseDSN, checkServer key.
* @return object Returns an error object if something went wrong
*/
function Auth_Container_IMAP($params)
{
if (!extension_loaded('imap')) {
return PEAR::raiseError("Cannot use IMAP authentication, IMAP extension not loaded!",
41, PEAR_ERROR_DIE);
}
$this->_setDefaults();
// set parameters (if any)
if (is_array($params)) {
$this->_parseOptions($params);
}
if ($this->options['checkServer']) {
$this->_checkServer($this->options['timeout']);
}
return true;
}
 
/**
* Set some default options
*
* @access private
*/
function _setDefaults()
{
$this->options['host'] = 'localhost';
$this->options['port'] = 143;
$this->options['baseDSN'] = '';
$this->options['checkServer'] = true;
$this->options['timeout'] = 20;
}
 
 
/**
* Check if the given server and port are reachable
*
* @access private
*/
function _checkServer() {
$fp = @fsockopen ($this->options['host'], $this->options['port'],
$errno, $errstr, $timeout);
if (is_resource($fp)) {
@fclose($fp);
} else {
$message = "Error connecting to IMAP server "
. $this->options['host']
. ":" . $this->options['port'];
return PEAR::raiseError($message, 41, PEAR_ERROR_DIE);
}
}
 
/**
* Parse options passed to the container class
*
* @access private
* @param array
*/
function _parseOptions($array)
{
foreach ($array as $key => $value) {
$this->options[$key] = $value;
}
}
 
/**
* Try to open a IMAP stream using $username / $password
*
* @param string Username
* @param string Password
* @return boolean
*/
function fetchData($username, $password)
{
$dsn = '{'.$this->options['host'].':'.$this->options['port'].$this->options['baseDSN'].'}';
$conn = @imap_open ($dsn, $username, $password, OP_HALFOPEN);
if (is_resource($conn)){
$this->activeUser = $username;
@imap_close($conn);
return true;
} else {
$this->activeUser = '';
return false;
}
}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/RADIUS.php
New file
0,0 → 1,154
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Michael Bretterklieber <michael@bretterklieber.com> |
// +----------------------------------------------------------------------+
//
// $Id: RADIUS.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "Auth/Container.php";
require_once "Auth/RADIUS.php";
 
/**
* Storage driver for authenticating users against RADIUS servers.
*
* @author Michael Bretterklieber <michael@bretterklieber.com>
* @access public
* @version $Revision: 1.1 $
*/
class Auth_Container_RADIUS extends Auth_Container
{
 
/**
* Contains a RADIUS object
* @var object
*/
var $radius;
/**
* Contains the authentication type
* @var string
*/
var $authtype;
 
/**
* Constructor of the container class.
*
* $options can have these keys:
* 'servers' an array containing an array: servername, port,
* sharedsecret, timeout, maxtries
* 'configfile' The filename of the configuration file
* 'authtype' The type of authentication, one of: PAP, CHAP_MD5,
* MSCHAPv1, MSCHAPv2, default is PAP
*
* @param $options associative array
* @return object Returns an error object if something went wrong
*/
function Auth_Container_RADIUS($options)
{
$this->authtype = 'PAP';
if (isset($options['authtype'])) {
$this->authtype = $options['authtype'];
}
$classname = 'Auth_RADIUS_' . $this->authtype;
if (!class_exists($classname)) {
PEAR::raiseError("Unknown Authtype, please use on of: PAP, CHAP_MD5, MSCHAPv1, MSCHAPv2!",
41, PEAR_ERROR_DIE);
}
$this->radius = new $classname;
 
if (isset($options['configfile'])) {
$this->radius->setConfigfile($options['configfile']);
}
 
$servers = $options['servers'];
if (is_array($servers)) {
foreach ($servers as $server) {
$servername = $server[0];
$port = isset($server[1]) ? $server[1] : 0;
$sharedsecret = isset($server[2]) ? $server[2] : 'testing123';
$timeout = isset($server[3]) ? $server[3] : 3;
$maxtries = isset($server[4]) ? $server[4] : 3;
$this->radius->addServer($servername, $port, $sharedsecret, $timeout, $maxtries);
}
}
if (!$this->radius->start()) {
PEAR::raiseError($this->radius->getError(), 41, PEAR_ERROR_DIE);
}
}
 
/**
* Authenticate
*
* @param string Username
* @param string Password
* @return bool true on success, false on reject
*/
function fetchData($username, $password, $challenge = null)
{
switch($this->authtype) {
case 'CHAP_MD5':
case 'MSCHAPv1':
if (isset($challenge)) {
echo $password;
$this->radius->challenge = $challenge;
$this->radius->chapid = 1;
$this->radius->response = pack('H*', $password);
} else {
require_once 'Crypt_CHAP/CHAP.php';
$classname = 'Crypt_' . $this->authtype;
$crpt = new $classname;
$crpt->password = $password;
$this->radius->challenge = $crpt->challenge;
$this->radius->chapid = $crpt->chapid;
$this->radius->response = $crpt->challengeResponse();
break;
}
 
case 'MSCHAPv2':
require_once 'Crypt_CHAP/CHAP.php';
$crpt = new Crypt_MSCHAPv2;
$crpt->username = $username;
$crpt->password = $password;
$this->radius->challenge = $crpt->authChallenge;
$this->radius->peerChallenge = $crpt->peerChallenge;
$this->radius->chapid = $crpt->chapid;
$this->radius->response = $crpt->challengeResponse();
break;
 
default:
$this->radius->password = $password;
break;
}
 
$this->radius->username = $username;
 
$this->radius->putAuthAttributes();
$result = $this->radius->send();
if (PEAR::isError($result)) {
return false;
}
 
$this->radius->getAttributes();
// just for debugging
// $this->radius->dumpAttributes();
 
return $result;
}
}
?>
/branches/v1.0-menes/api/pear/Auth/Container/vpopmail.php
New file
0,0 → 1,66
<?PHP
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stanislav Grozev <tacho@orbitel.bg> |
// +----------------------------------------------------------------------+
//
// $Id: vpopmail.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
require_once "Auth/Container.php";
 
/**
* Storage driver for fetching login data from vpopmail
*
* @author Stanislav Grozev <tacho@orbitel.bg>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth_Container_vpopmail extends Auth_Container {
 
// {{{ Constructor
 
/**
* Constructor of the container class
*
* @return integer Always returns 1.
*/
function Auth_Container_vpopmail()
{
return 1;
}
 
// }}}
// {{{ fetchData()
 
/**
* Get user information from vpopmail
*
* @param string Username - has to be valid email address
* @param string Password
* @return boolean
*/
function fetchData($username, $password)
{
$userdata = array();
$userdata = preg_split("/@/", $username, 2);
$result = @vpopmail_auth_user($userdata[0], $userdata[1], $password);
 
return $result;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Auth/Auth.php
New file
0,0 → 1,5
<?php
 
include_once('Auth.php');
 
?>
/branches/v1.0-menes/api/pear/Auth/Container.php
New file
0,0 → 1,177
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Martin Jansen <mj@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: Container.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
//
 
define("AUTH_METHOD_NOT_SUPPORTED", -4);
 
/**
* Storage class for fetching login data
*
* @author Martin Jansen <mj@php.net>
* @package Auth
*/
class Auth_Container
{
 
/**
* User that is currently selected from the storage container.
*
* @access public
*/
var $activeUser = "";
 
// {{{ Constructor
 
/**
* Constructor
*
* Has to be overwritten by each storage class
*
* @access public
*/
function Auth_Container()
{
}
 
// }}}
// {{{ fetchData()
 
/**
* Fetch data from storage container
*
* Has to be overwritten by each storage class
*
* @access public
*/
function fetchData()
{
}
 
// }}}
// {{{ verifyPassword()
 
/**
* Crypt and verfiy the entered password
*
* @param string Entered password
* @param string Password from the data container (usually this password
* is already encrypted.
* @param string Type of algorithm with which the password from
* the container has been crypted. (md5, crypt etc.)
* Defaults to "md5".
* @return bool True, if the passwords match
*/
function verifyPassword($password1, $password2, $cryptType = "md5")
{
switch ($cryptType) {
case "crypt" :
return (($password2 == "**" . $password1) ||
(crypt($password1, $password2) == $password2)
);
break;
 
case "none" :
return ($password1 == $password2);
break;
 
case "md5" :
return (md5($password1) == $password2);
break;
 
default :
if (function_exists($cryptType)) {
return ($cryptType($password1) == $password2);
}
else if (method_exists($this,$cryptType)) {
return ($this->$cryptType($password1) == $password2);
} else {
return false;
}
break;
}
}
 
// }}}
// {{{ listUsers()
 
/**
* List all users that are available from the storage container
*/
function listUsers()
{
return AUTH_METHOD_NOT_SUPPORTED;
}
 
/**
* Returns a user assoc array
*
* Containers which want should overide this
*
* @param string The username
*/
function getUser($username)
{
$users = $this->listUsers();
if($users === AUTH_METHOD_NOT_SUPPORTED){
return(AUTH_METHOD_NOT_SUPPORTED);
}
for($i=0;$c = count($users),$i<$c;$i++){
if($users[$i]['username'] == $username){
return($users[$i]);
}
}
return(false);
}
 
// }}}
// {{{ addUser()
 
/**
* Add a new user to the storage container
*
* @param string Username
* @param string Password
* @param array Additional information
*
* @return boolean
*/
function addUser($username, $password, $additional=null)
{
return AUTH_METHOD_NOT_SUPPORTED;
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @param string Username
*/
function removeUser($username)
{
return AUTH_METHOD_NOT_SUPPORTED;
}
 
// }}}
 
}
?>
/branches/v1.0-menes/api/pear/Mail/mimePart.php
New file
0,0 → 1,351
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// +-----------------------------------------------------------------------+
 
/**
*
* Raw mime encoding class
*
* What is it?
* This class enables you to manipulate and build
* a mime email from the ground up.
*
* Why use this instead of mime.php?
* mime.php 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.
*
* Eg.
*
* // Since multipart/mixed has no real body, (the body is
* // the subpart), we set the body argument to blank.
*
* $params['content_type'] = 'multipart/mixed';
* $email = new Mail_mimePart('', $params);
*
* // Here we add a text part to the multipart we have
* // already. Assume $body contains plain text.
*
* $params['content_type'] = 'text/plain';
* $params['encoding'] = '7bit';
* $text = $email->addSubPart($body, $params);
*
* // Now add an attachment. Assume $attach is
* the contents of the attachment
*
* $params['content_type'] = 'application/zip';
* $params['encoding'] = 'base64';
* $params['disposition'] = 'attachment';
* $params['dfilename'] = 'example.zip';
* $attach =& $email->addSubPart($body, $params);
*
* // Now build the email. Note that the encode
* // function returns an associative array containing two
* // elements, body and headers. You will need to add extra
* // headers, (eg. Mime-Version) before sending.
*
* $email = $message->encode();
* $email['headers'][] = 'Mime-Version: 1.0';
*
*
* Further examples are available at http://www.phpguru.org
*
* TODO:
* - Set encode() to return the $obj->encoded if encode()
* has already been run. Unless a flag is passed to specifically
* re-build the message.
*
* @author Richard Heyes <richard@phpguru.org>
* @version $Revision: 1.1 $
* @package Mail
*/
 
class Mail_mimePart {
 
/**
* The encoding type of this part
* @var string
*/
var $_encoding;
 
/**
* An array of subparts
* @var array
*/
var $_subparts;
 
/**
* The output of this part after being built
* @var string
*/
var $_encoded;
 
/**
* Headers for this part
* @var array
*/
var $_headers;
 
/**
* The body of this part (not encoded)
* @var string
*/
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;
 
} 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;
}
}
 
/**
* quoteadPrintableEncode()
*
* 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)){
 
$linlen = strlen($line);
$newline = '';
 
for ($i = 0; $i < $linlen; $i++) {
$char = substr($line, $i, 1);
$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
?>
/branches/v1.0-menes/api/pear/Mail/mail.php
New file
0,0 → 1,130
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: mail.php,v 1.1 2005-11-24 16:15:46 florian Exp $
 
/**
* internal PHP-mail() implementation of the PEAR Mail:: interface.
* @package Mail
* @version $Revision: 1.1 $
*/
class Mail_mail extends Mail {
 
/**
* Any arguments to pass to the mail() function.
* @var string
*/
var $_params = '';
 
/**
* Constructor.
*
* Instantiates a new Mail_mail:: object based on the parameters
* passed in.
*
* @param array $params Extra arguments for the mail() function.
*/
function Mail_mail($params = null)
{
/* The other mail implementations accept parameters as arrays.
* In the interest of being consistent, explode an array into
* a string of parameter arguments. */
if (is_array($params)) {
$this->_params = join(' ', $params);
} else {
$this->_params = $params;
}
 
/* Because the mail() function may pass headers as command
* line arguments, we can't guarantee the use of the standard
* "\r\n" separator. Instead, we use the system's native line
* separator. */
$this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
}
 
/**
* Implements Mail_mail::send() function using php's built-in mail()
* command.
*
* @param mixed $recipients Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid. This may contain recipients not
* specified in the headers, for Bcc:, resending
* messages, etc.
*
* @param array $headers The array of headers to send with the mail, in an
* associative array, where the array key is the
* header name (ie, 'Subject'), and the array value
* is the header value (ie, 'test'). The header
* produced from those values would be 'Subject:
* test'.
*
* @param string $body The full text of the message body, including any
* Mime parts, etc.
*
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
*
* @access public
*/
function send($recipients, $headers, $body)
{
// If we're passed an array of recipients, implode it.
if (is_array($recipients)) {
$recipients = implode(', ', $recipients);
}
 
// Get the Subject out of the headers array so that we can
// pass it as a seperate argument to mail().
$subject = '';
if (isset($headers['Subject'])) {
$subject = $headers['Subject'];
unset($headers['Subject']);
}
 
// Flatten the headers out.
$headerElements = $this->prepareHeaders($headers);
if (PEAR::isError($headerElements)) {
return $headerElements;
}
list(, $text_headers) = $headerElements;
 
/*
* We only use mail()'s optional fifth parameter if the additional
* parameters have been provided and we're not running in safe mode.
*/
if (empty($this->_params) || ini_get('safe_mode')) {
$result = mail($recipients, $subject, $body, $text_headers);
} else {
$result = mail($recipients, $subject, $body, $text_headers,
$this->_params);
}
 
/*
* If the mail() function returned failure, we need to create a
* PEAR_Error object and return it instead of the boolean result.
*/
if ($result === false) {
$result = PEAR::raiseError('mail() returned failure');
}
 
return $result;
}
 
}
/branches/v1.0-menes/api/pear/Mail/smtp.php
New file
0,0 → 1,323
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Chuck Hagenbuch <chuck@horde.org> |
// | Jon Parise <jon@php.net> |
// +----------------------------------------------------------------------+
 
/**
* SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class.
* @access public
* @package Mail
* @version $Revision: 1.1 $
*/
class Mail_smtp extends Mail {
 
/**
* SMTP connection object.
*
* @var object
* @access private
*/
var $_smtp = null;
 
/**
* The SMTP host to connect to.
* @var string
*/
var $host = 'localhost';
 
/**
* The port the SMTP server is on.
* @var integer
*/
var $port = 25;
 
/**
* Should SMTP authentication be used?
*
* This value may be set to true, false or the name of a specific
* authentication method.
*
* If the value is set to true, the Net_SMTP package will attempt to use
* the best authentication method advertised by the remote SMTP server.
*
* @var mixed
*/
var $auth = false;
 
/**
* The username to use if the SMTP server requires authentication.
* @var string
*/
var $username = '';
 
/**
* The password to use if the SMTP server requires authentication.
* @var string
*/
var $password = '';
 
/**
* Hostname or domain that will be sent to the remote SMTP server in the
* HELO / EHLO message.
*
* @var string
*/
var $localhost = 'localhost';
 
/**
* SMTP connection timeout value. NULL indicates no timeout.
*
* @var integer
*/
var $timeout = null;
 
/**
* Whether to use VERP or not. If not a boolean, the string value
* will be used as the VERP separators.
*
* @var mixed boolean or string
*/
var $verp = false;
 
/**
* Turn on Net_SMTP debugging?
*
* @var boolean $debug
*/
var $debug = false;
 
/**
* Indicates whether or not the SMTP connection should persist over
* multiple calls to the send() method.
*
* @var boolean
*/
var $persist = false;
 
/**
* Constructor.
*
* Instantiates a new Mail_smtp:: object based on the parameters
* passed in. It looks for the following parameters:
* host The server to connect to. Defaults to localhost.
* port The port to connect to. Defaults to 25.
* auth SMTP authentication. Defaults to none.
* username The username to use for SMTP auth. No default.
* password The password to use for SMTP auth. No default.
* localhost The local hostname / domain. Defaults to localhost.
* timeout The SMTP connection timeout. Defaults to none.
* verp Whether to use VERP or not. Defaults to false.
* debug Activate SMTP debug mode? Defaults to false.
* persist Should the SMTP connection persist?
*
* If a parameter is present in the $params array, it replaces the
* default.
*
* @param array Hash containing any parameters different from the
* defaults.
* @access public
*/
function Mail_smtp($params)
{
if (isset($params['host'])) $this->host = $params['host'];
if (isset($params['port'])) $this->port = $params['port'];
if (isset($params['auth'])) $this->auth = $params['auth'];
if (isset($params['username'])) $this->username = $params['username'];
if (isset($params['password'])) $this->password = $params['password'];
if (isset($params['localhost'])) $this->localhost = $params['localhost'];
if (isset($params['timeout'])) $this->timeout = $params['timeout'];
if (isset($params['verp'])) $this->verp = $params['verp'];
if (isset($params['debug'])) $this->debug = (boolean)$params['debug'];
if (isset($params['persist'])) $this->persist = (boolean)$params['persist'];
 
register_shutdown_function(array(&$this, '_Mail_smtp'));
}
 
/**
* Destructor implementation to ensure that we disconnect from any
* potentially-alive persistent SMTP connections.
*/
function _Mail_smtp()
{
$this->disconnect();
}
 
/**
* Implements Mail::send() function using SMTP.
*
* @param mixed $recipients Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid. This may contain recipients not
* specified in the headers, for Bcc:, resending
* messages, etc.
*
* @param array $headers The array of headers to send with the mail, in an
* associative array, where the array key is the
* header name (e.g., 'Subject'), and the array value
* is the header value (e.g., 'test'). The header
* produced from those values would be 'Subject:
* test'.
*
* @param string $body The full text of the message body, including any
* Mime parts, etc.
*
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
* @access public
*/
function send($recipients, $headers, $body)
{
include_once 'Net/SMTP.php';
 
/* If we don't already have an SMTP object, create one. */
if (is_object($this->_smtp) === false) {
$this->_smtp =& new Net_SMTP($this->host, $this->port,
$this->localhost);
 
/* If we still don't have an SMTP object at this point, fail. */
if (is_object($this->_smtp) === false) {
return PEAR::raiseError('Failed to create a Net_SMTP object');
}
 
/* Configure the SMTP connection. */
if ($this->debug) {
$this->_smtp->setDebug(true);
}
 
/* Attempt to connect to the configured SMTP server. */
if (PEAR::isError($res = $this->_smtp->connect($this->timeout))) {
$error = $this->_error('Failed to connect to ' .
$this->host . ':' . $this->port,
$res);
return PEAR::raiseError($error);
}
 
/* Attempt to authenticate if authentication has been enabled. */
if ($this->auth) {
$method = is_string($this->auth) ? $this->auth : '';
 
if (PEAR::isError($res = $this->_smtp->auth($this->username,
$this->password,
$method))) {
$error = $this->_error("$method authentication failure",
$res);
$this->_smtp->rset();
return PEAR::raiseError($error);
}
}
}
 
$headerElements = $this->prepareHeaders($headers);
if (PEAR::isError($headerElements)) {
$this->_smtp->rset();
return $headerElements;
}
list($from, $textHeaders) = $headerElements;
 
/* Since few MTAs are going to allow this header to be forged
* unless it's in the MAIL FROM: exchange, we'll use
* Return-Path instead of From: if it's set. */
if (!empty($headers['Return-Path'])) {
$from = $headers['Return-Path'];
}
 
if (!isset($from)) {
$this->_smtp->rset();
return PEAR::raiseError('No From: address has been provided');
}
 
$args['verp'] = $this->verp;
if (PEAR::isError($res = $this->_smtp->mailFrom($from, $args))) {
$error = $this->_error("Failed to set sender: $from", $res);
$this->_smtp->rset();
return PEAR::raiseError($error);
}
 
$recipients = $this->parseRecipients($recipients);
if (PEAR::isError($recipients)) {
$this->_smtp->rset();
return $recipients;
}
 
foreach ($recipients as $recipient) {
if (PEAR::isError($res = $this->_smtp->rcptTo($recipient))) {
$error = $this->_error("Failed to add recipient: $recipient",
$res);
$this->_smtp->rset();
return PEAR::raiseError($error);
}
}
 
/* Send the message's headers and the body as SMTP data. */
if (PEAR::isError($res = $this->_smtp->data("$textHeaders\r\n$body"))) {
$error = $this->_error('Failed to send data', $res);
$this->_smtp->rset();
return PEAR::raiseError($error);
}
 
/* If persistent connections are disabled, destroy our SMTP object. */
if ($this->persist === false) {
$this->disconnect();
}
 
return true;
}
 
/**
* Disconnect and destroy the current SMTP connection.
*
* @return boolean True if the SMTP connection no longer exists.
*
* @since 1.1.9
* @access public
*/
function disconnect()
{
/* If we have an SMTP object, disconnect and destroy it. */
if (is_object($this->_smtp) && $this->_smtp->disconnect()) {
$this->_smtp = null;
}
 
/* We are disconnected if we no longer have an SMTP object. */
return ($this->_smtp === null);
}
 
/**
* Build a standardized string describing the current SMTP error.
*
* @param string $text Custom string describing the error context.
* @param object $error Reference to the current PEAR_Error object.
*
* @return string A string describing the current SMTP error.
*
* @since 1.1.7
* @access private
*/
function _error($text, &$error)
{
/* Split the SMTP response into a code and a response string. */
list($code, $response) = $this->_smtp->getResponse();
 
/* Build our standardized error string. */
$msg = $text;
$msg .= ' [SMTP: ' . $error->getMessage();
$msg .= " (code: $code, response: $response)]";
 
return $msg;
}
}
/branches/v1.0-menes/api/pear/Mail/RFC822.php
New file
0,0 → 1,923
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2001-2002, Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Authors: Richard Heyes <richard@phpguru.org> |
// | Chuck Hagenbuch <chuck@horde.org> |
// +-----------------------------------------------------------------------+
 
/**
* RFC 822 Email address list validation Utility
*
* What is it?
*
* This class will take an address string, and parse it into it's consituent
* parts, be that either addresses, groups, or combinations. Nested groups
* are not supported. The structure it returns is pretty straight forward,
* and is similar to that provided by the imap_rfc822_parse_adrlist(). Use
* print_r() to view the structure.
*
* How do I use it?
*
* $address_string = 'My Group: "Richard" <richard@localhost> (A comment), ted@example.com (Ted Bloggs), Barney;';
* $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', true)
* print_r($structure);
*
* @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org>
* @version $Revision: 1.1 $
* @license BSD
* @package Mail
*/
class Mail_RFC822 {
 
/**
* The address being parsed by the RFC822 object.
* @var string $address
*/
var $address = '';
 
/**
* The default domain to use for unqualified addresses.
* @var string $default_domain
*/
var $default_domain = 'localhost';
 
/**
* Should we return a nested array showing groups, or flatten everything?
* @var boolean $nestGroups
*/
var $nestGroups = true;
 
/**
* Whether or not to validate atoms for non-ascii characters.
* @var boolean $validate
*/
var $validate = true;
 
/**
* The array of raw addresses built up as we parse.
* @var array $addresses
*/
var $addresses = array();
 
/**
* The final array of parsed address information that we build up.
* @var array $structure
*/
var $structure = array();
 
/**
* The current error message, if any.
* @var string $error
*/
var $error = null;
 
/**
* An internal counter/pointer.
* @var integer $index
*/
var $index = null;
 
/**
* The number of groups that have been found in the address list.
* @var integer $num_groups
* @access public
*/
var $num_groups = 0;
 
/**
* A variable so that we can tell whether or not we're inside a
* Mail_RFC822 object.
* @var boolean $mailRFC822
*/
var $mailRFC822 = true;
 
/**
* A limit after which processing stops
* @var int $limit
*/
var $limit = null;
 
/**
* Sets up the object. The address must either be set here or when
* calling parseAddressList(). One or the other.
*
* @access public
* @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
* @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
*
* @return object Mail_RFC822 A new Mail_RFC822 object.
*/
function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{
if (isset($address)) $this->address = $address;
if (isset($default_domain)) $this->default_domain = $default_domain;
if (isset($nest_groups)) $this->nestGroups = $nest_groups;
if (isset($validate)) $this->validate = $validate;
if (isset($limit)) $this->limit = $limit;
}
 
/**
* Starts the whole process. The address must either be set here
* or when creating the object. One or the other.
*
* @access public
* @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
* @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
*
* @return array A structured array of addresses.
*/
function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{
if (!isset($this) || !isset($this->mailRFC822)) {
$obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
return $obj->parseAddressList();
}
 
if (isset($address)) $this->address = $address;
if (isset($default_domain)) $this->default_domain = $default_domain;
if (isset($nest_groups)) $this->nestGroups = $nest_groups;
if (isset($validate)) $this->validate = $validate;
if (isset($limit)) $this->limit = $limit;
 
$this->structure = array();
$this->addresses = array();
$this->error = null;
$this->index = null;
 
// Unfold any long lines in $this->address.
$this->address = preg_replace('/\r?\n/', "\r\n", $this->address);
$this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address);
 
while ($this->address = $this->_splitAddresses($this->address));
 
if ($this->address === false || isset($this->error)) {
require_once 'PEAR.php';
return PEAR::raiseError($this->error);
}
 
// Validate each address individually. If we encounter an invalid
// address, stop iterating and return an error immediately.
foreach ($this->addresses as $address) {
$valid = $this->_validateAddress($address);
 
if ($valid === false || isset($this->error)) {
require_once 'PEAR.php';
return PEAR::raiseError($this->error);
}
 
if (!$this->nestGroups) {
$this->structure = array_merge($this->structure, $valid);
} else {
$this->structure[] = $valid;
}
}
 
return $this->structure;
}
 
/**
* Splits an address into separate addresses.
*
* @access private
* @param string $address The addresses to split.
* @return boolean Success or failure.
*/
function _splitAddresses($address)
{
if (!empty($this->limit) && count($this->addresses) == $this->limit) {
return '';
}
 
if ($this->_isGroup($address) && !isset($this->error)) {
$split_char = ';';
$is_group = true;
} elseif (!isset($this->error)) {
$split_char = ',';
$is_group = false;
} elseif (isset($this->error)) {
return false;
}
 
// Split the string based on the above ten or so lines.
$parts = explode($split_char, $address);
$string = $this->_splitCheck($parts, $split_char);
 
// If a group...
if ($is_group) {
// If $string does not contain a colon outside of
// brackets/quotes etc then something's fubar.
 
// First check there's a colon at all:
if (strpos($string, ':') === false) {
$this->error = 'Invalid address: ' . $string;
return false;
}
 
// Now check it's outside of brackets/quotes:
if (!$this->_splitCheck(explode(':', $string), ':')) {
return false;
}
 
// We must have a group at this point, so increase the counter:
$this->num_groups++;
}
 
// $string now contains the first full address/group.
// Add to the addresses array.
$this->addresses[] = array(
'address' => trim($string),
'group' => $is_group
);
 
// Remove the now stored address from the initial line, the +1
// is to account for the explode character.
$address = trim(substr($address, strlen($string) + 1));
 
// If the next char is a comma and this was a group, then
// there are more addresses, otherwise, if there are any more
// chars, then there is another address.
if ($is_group && substr($address, 0, 1) == ','){
$address = trim(substr($address, 1));
return $address;
 
} elseif (strlen($address) > 0) {
return $address;
 
} else {
return '';
}
 
// If you got here then something's off
return false;
}
 
/**
* Checks for a group at the start of the string.
*
* @access private
* @param string $address The address to check.
* @return boolean Whether or not there is a group at the start of the string.
*/
function _isGroup($address)
{
// First comma not in quotes, angles or escaped:
$parts = explode(',', $address);
$string = $this->_splitCheck($parts, ',');
 
// Now we have the first address, we can reliably check for a
// group by searching for a colon that's not escaped or in
// quotes or angle brackets.
if (count($parts = explode(':', $string)) > 1) {
$string2 = $this->_splitCheck($parts, ':');
return ($string2 !== $string);
} else {
return false;
}
}
 
/**
* A common function that will check an exploded string.
*
* @access private
* @param array $parts The exloded string.
* @param string $char The char that was exploded on.
* @return mixed False if the string contains unclosed quotes/brackets, or the string on success.
*/
function _splitCheck($parts, $char)
{
$string = $parts[0];
 
for ($i = 0; $i < count($parts); $i++) {
if ($this->_hasUnclosedQuotes($string)
|| $this->_hasUnclosedBrackets($string, '<>')
|| $this->_hasUnclosedBrackets($string, '[]')
|| $this->_hasUnclosedBrackets($string, '()')
|| substr($string, -1) == '\\') {
if (isset($parts[$i + 1])) {
$string = $string . $char . $parts[$i + 1];
} else {
$this->error = 'Invalid address spec. Unclosed bracket or quotes';
return false;
}
} else {
$this->index = $i;
break;
}
}
 
return $string;
}
 
/**
* Checks if a string has an unclosed quotes or not.
*
* @access private
* @param string $string The string to check.
* @return boolean True if there are unclosed quotes inside the string, false otherwise.
*/
function _hasUnclosedQuotes($string)
{
$string = explode('"', $string);
$string_cnt = count($string);
 
for ($i = 0; $i < (count($string) - 1); $i++)
if (substr($string[$i], -1) == '\\')
$string_cnt--;
 
return ($string_cnt % 2 === 0);
}
 
/**
* Checks if a string has an unclosed brackets or not. IMPORTANT:
* This function handles both angle brackets and square brackets;
*
* @access private
* @param string $string The string to check.
* @param string $chars The characters to check for.
* @return boolean True if there are unclosed brackets inside the string, false otherwise.
*/
function _hasUnclosedBrackets($string, $chars)
{
$num_angle_start = substr_count($string, $chars[0]);
$num_angle_end = substr_count($string, $chars[1]);
 
$this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]);
$this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]);
 
if ($num_angle_start < $num_angle_end) {
$this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')';
return false;
} else {
return ($num_angle_start > $num_angle_end);
}
}
 
/**
* Sub function that is used only by hasUnclosedBrackets().
*
* @access private
* @param string $string The string to check.
* @param integer &$num The number of occurences.
* @param string $char The character to count.
* @return integer The number of occurences of $char in $string, adjusted for backslashes.
*/
function _hasUnclosedBracketsSub($string, &$num, $char)
{
$parts = explode($char, $string);
for ($i = 0; $i < count($parts); $i++){
if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i]))
$num--;
if (isset($parts[$i + 1]))
$parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1];
}
 
return $num;
}
 
/**
* Function to begin checking the address.
*
* @access private
* @param string $address The address to validate.
* @return mixed False on failure, or a structured array of address information on success.
*/
function _validateAddress($address)
{
$is_group = false;
$addresses = array();
 
if ($address['group']) {
$is_group = true;
 
// Get the group part of the name
$parts = explode(':', $address['address']);
$groupname = $this->_splitCheck($parts, ':');
$structure = array();
 
// And validate the group part of the name.
if (!$this->_validatePhrase($groupname)){
$this->error = 'Group name did not validate.';
return false;
} else {
// Don't include groups if we are not nesting
// them. This avoids returning invalid addresses.
if ($this->nestGroups) {
$structure = new stdClass;
$structure->groupname = $groupname;
}
}
 
$address['address'] = ltrim(substr($address['address'], strlen($groupname . ':')));
}
 
// If a group then split on comma and put into an array.
// Otherwise, Just put the whole address in an array.
if ($is_group) {
while (strlen($address['address']) > 0) {
$parts = explode(',', $address['address']);
$addresses[] = $this->_splitCheck($parts, ',');
$address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
}
} else {
$addresses[] = $address['address'];
}
 
// Check that $addresses is set, if address like this:
// Groupname:;
// Then errors were appearing.
if (!count($addresses)){
$this->error = 'Empty group.';
return false;
}
 
// Trim the whitespace from all of the address strings.
array_map('trim', $addresses);
 
// Validate each mailbox.
// Format could be one of: name <geezer@domain.com>
// geezer@domain.com
// geezer
// ... or any other format valid by RFC 822.
for ($i = 0; $i < count($addresses); $i++) {
if (!$this->validateMailbox($addresses[$i])) {
if (empty($this->error)) {
$this->error = 'Validation failed for: ' . $addresses[$i];
}
return false;
}
}
 
// Nested format
if ($this->nestGroups) {
if ($is_group) {
$structure->addresses = $addresses;
} else {
$structure = $addresses[0];
}
 
// Flat format
} else {
if ($is_group) {
$structure = array_merge($structure, $addresses);
} else {
$structure = $addresses;
}
}
 
return $structure;
}
 
/**
* Function to validate a phrase.
*
* @access private
* @param string $phrase The phrase to check.
* @return boolean Success or failure.
*/
function _validatePhrase($phrase)
{
// Splits on one or more Tab or space.
$parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
 
$phrase_parts = array();
while (count($parts) > 0){
$phrase_parts[] = $this->_splitCheck($parts, ' ');
for ($i = 0; $i < $this->index + 1; $i++)
array_shift($parts);
}
 
foreach ($phrase_parts as $part) {
// If quoted string:
if (substr($part, 0, 1) == '"') {
if (!$this->_validateQuotedString($part)) {
return false;
}
continue;
}
 
// Otherwise it's an atom:
if (!$this->_validateAtom($part)) return false;
}
 
return true;
}
 
/**
* Function to validate an atom which from rfc822 is:
* atom = 1*<any CHAR except specials, SPACE and CTLs>
*
* If validation ($this->validate) has been turned off, then
* validateAtom() doesn't actually check anything. This is so that you
* can split a list of addresses up before encoding personal names
* (umlauts, etc.), for example.
*
* @access private
* @param string $atom The string to check.
* @return boolean Success or failure.
*/
function _validateAtom($atom)
{
if (!$this->validate) {
// Validation has been turned off; assume the atom is okay.
return true;
}
 
// Check for any char from ASCII 0 - ASCII 127
if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) {
return false;
}
 
// Check for specials:
if (preg_match('/[][()<>@,;\\:". ]/', $atom)) {
return false;
}
 
// Check for control characters (ASCII 0-31):
if (preg_match('/[\\x00-\\x1F]+/', $atom)) {
return false;
}
 
return true;
}
 
/**
* Function to validate quoted string, which is:
* quoted-string = <"> *(qtext/quoted-pair) <">
*
* @access private
* @param string $qstring The string to check
* @return boolean Success or failure.
*/
function _validateQuotedString($qstring)
{
// Leading and trailing "
$qstring = substr($qstring, 1, -1);
 
// Perform check, removing quoted characters first.
return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring));
}
 
/**
* Function to validate a mailbox, which is:
* mailbox = addr-spec ; simple address
* / phrase route-addr ; name and route-addr
*
* @access public
* @param string &$mailbox The string to check.
* @return boolean Success or failure.
*/
function validateMailbox(&$mailbox)
{
// A couple of defaults.
$phrase = '';
$comment = '';
$comments = array();
 
// Catch any RFC822 comments and store them separately.
$_mailbox = $mailbox;
while (strlen(trim($_mailbox)) > 0) {
$parts = explode('(', $_mailbox);
$before_comment = $this->_splitCheck($parts, '(');
if ($before_comment != $_mailbox) {
// First char should be a (.
$comment = substr(str_replace($before_comment, '', $_mailbox), 1);
$parts = explode(')', $comment);
$comment = $this->_splitCheck($parts, ')');
$comments[] = $comment;
 
// +1 is for the trailing )
$_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1);
} else {
break;
}
}
 
foreach ($comments as $comment) {
$mailbox = str_replace("($comment)", '', $mailbox);
}
 
$mailbox = trim($mailbox);
 
// Check for name + route-addr
if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') {
$parts = explode('<', $mailbox);
$name = $this->_splitCheck($parts, '<');
 
$phrase = trim($name);
$route_addr = trim(substr($mailbox, strlen($name.'<'), -1));
 
if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) {
return false;
}
 
// Only got addr-spec
} else {
// First snip angle brackets if present.
if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') {
$addr_spec = substr($mailbox, 1, -1);
} else {
$addr_spec = $mailbox;
}
 
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
return false;
}
}
 
// Construct the object that will be returned.
$mbox = new stdClass();
 
// Add the phrase (even if empty) and comments
$mbox->personal = $phrase;
$mbox->comment = isset($comments) ? $comments : array();
 
if (isset($route_addr)) {
$mbox->mailbox = $route_addr['local_part'];
$mbox->host = $route_addr['domain'];
$route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : '';
} else {
$mbox->mailbox = $addr_spec['local_part'];
$mbox->host = $addr_spec['domain'];
}
 
$mailbox = $mbox;
return true;
}
 
/**
* This function validates a route-addr which is:
* route-addr = "<" [route] addr-spec ">"
*
* Angle brackets have already been removed at the point of
* getting to this function.
*
* @access private
* @param string $route_addr The string to check.
* @return mixed False on failure, or an array containing validated address/route information on success.
*/
function _validateRouteAddr($route_addr)
{
// Check for colon.
if (strpos($route_addr, ':') !== false) {
$parts = explode(':', $route_addr);
$route = $this->_splitCheck($parts, ':');
} else {
$route = $route_addr;
}
 
// If $route is same as $route_addr then the colon was in
// quotes or brackets or, of course, non existent.
if ($route === $route_addr){
unset($route);
$addr_spec = $route_addr;
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
return false;
}
} else {
// Validate route part.
if (($route = $this->_validateRoute($route)) === false) {
return false;
}
 
$addr_spec = substr($route_addr, strlen($route . ':'));
 
// Validate addr-spec part.
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
return false;
}
}
 
if (isset($route)) {
$return['adl'] = $route;
} else {
$return['adl'] = '';
}
 
$return = array_merge($return, $addr_spec);
return $return;
}
 
/**
* Function to validate a route, which is:
* route = 1#("@" domain) ":"
*
* @access private
* @param string $route The string to check.
* @return mixed False on failure, or the validated $route on success.
*/
function _validateRoute($route)
{
// Split on comma.
$domains = explode(',', trim($route));
 
foreach ($domains as $domain) {
$domain = str_replace('@', '', trim($domain));
if (!$this->_validateDomain($domain)) return false;
}
 
return $route;
}
 
/**
* Function to validate a domain, though this is not quite what
* you expect of a strict internet domain.
*
* domain = sub-domain *("." sub-domain)
*
* @access private
* @param string $domain The string to check.
* @return mixed False on failure, or the validated domain on success.
*/
function _validateDomain($domain)
{
// Note the different use of $subdomains and $sub_domains
$subdomains = explode('.', $domain);
 
while (count($subdomains) > 0) {
$sub_domains[] = $this->_splitCheck($subdomains, '.');
for ($i = 0; $i < $this->index + 1; $i++)
array_shift($subdomains);
}
 
foreach ($sub_domains as $sub_domain) {
if (!$this->_validateSubdomain(trim($sub_domain)))
return false;
}
 
// Managed to get here, so return input.
return $domain;
}
 
/**
* Function to validate a subdomain:
* subdomain = domain-ref / domain-literal
*
* @access private
* @param string $subdomain The string to check.
* @return boolean Success or failure.
*/
function _validateSubdomain($subdomain)
{
if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){
if (!$this->_validateDliteral($arr[1])) return false;
} else {
if (!$this->_validateAtom($subdomain)) return false;
}
 
// Got here, so return successful.
return true;
}
 
/**
* Function to validate a domain literal:
* domain-literal = "[" *(dtext / quoted-pair) "]"
*
* @access private
* @param string $dliteral The string to check.
* @return boolean Success or failure.
*/
function _validateDliteral($dliteral)
{
return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\';
}
 
/**
* Function to validate an addr-spec.
*
* addr-spec = local-part "@" domain
*
* @access private
* @param string $addr_spec The string to check.
* @return mixed False on failure, or the validated addr-spec on success.
*/
function _validateAddrSpec($addr_spec)
{
$addr_spec = trim($addr_spec);
 
// Split on @ sign if there is one.
if (strpos($addr_spec, '@') !== false) {
$parts = explode('@', $addr_spec);
$local_part = $this->_splitCheck($parts, '@');
$domain = substr($addr_spec, strlen($local_part . '@'));
 
// No @ sign so assume the default domain.
} else {
$local_part = $addr_spec;
$domain = $this->default_domain;
}
 
if (($local_part = $this->_validateLocalPart($local_part)) === false) return false;
if (($domain = $this->_validateDomain($domain)) === false) return false;
 
// Got here so return successful.
return array('local_part' => $local_part, 'domain' => $domain);
}
 
/**
* Function to validate the local part of an address:
* local-part = word *("." word)
*
* @access private
* @param string $local_part
* @return mixed False on failure, or the validated local part on success.
*/
function _validateLocalPart($local_part)
{
$parts = explode('.', $local_part);
$words = array();
 
// Split the local_part into words.
while (count($parts) > 0){
$words[] = $this->_splitCheck($parts, '.');
for ($i = 0; $i < $this->index + 1; $i++) {
array_shift($parts);
}
}
 
// Validate each word.
foreach ($words as $word) {
// If this word contains an unquoted space, it is invalid. (6.2.4)
if (strpos($word, ' ') && $word[0] !== '"')
{
return false;
}
 
if ($this->_validatePhrase(trim($word)) === false) return false;
}
 
// Managed to get here, so return the input.
return $local_part;
}
 
/**
* Returns an approximate count of how many addresses are in the
* given string. This is APPROXIMATE as it only splits based on a
* comma which has no preceding backslash. Could be useful as
* large amounts of addresses will end up producing *large*
* structures when used with parseAddressList().
*
* @param string $data Addresses to count
* @return int Approximate count
*/
function approximateCount($data)
{
return count(preg_split('/(?<!\\\\),/', $data));
}
 
/**
* This is a email validating function separate to the rest of the
* class. It simply validates whether an email is of the common
* internet form: <user>@<domain>. This can be sufficient for most
* people. Optional stricter mode can be utilised which restricts
* mailbox characters allowed to alphanumeric, full stop, hyphen
* and underscore.
*
* @param string $data Address to check
* @param boolean $strict Optional stricter mode
* @return mixed False if it fails, an indexed array
* username/domain if it matches
*/
function isValidInetAddress($data, $strict = false)
{
$regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i';
if (preg_match($regex, trim($data), $matches)) {
return array($matches[1], $matches[2]);
} else {
return false;
}
}
 
}
/branches/v1.0-menes/api/pear/Mail/mime.php
New file
0,0 → 1,713
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | Copyright (c) 2003-2005 The PHP Group |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// | Tomas V.V.Cox <cox@idecnet.com> (port to PEAR) |
// +-----------------------------------------------------------------------+
//
// $Id: mime.php,v 1.1 2006-09-13 08:49:41 alexandre_tb Exp $
 
require_once('PEAR.php');
require_once('Mail/mimePart.php');
 
/**
* Mime mail composer class. Can handle: text and html bodies, embedded html
* images and attachments.
* Documentation and examples of this class are avaible here:
* http://pear.php.net/manual/
*
* @notes This class is based on HTML Mime Mail class from
* Richard Heyes <richard@phpguru.org> which was based also
* in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
* Sascha Schumann <sascha@schumann.cx>
*
* @author Richard Heyes <richard.heyes@heyes-computing.net>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @package Mail
* @access public
*/
class Mail_mime
{
/**
* Contains the plain text part of the email
* @var string
*/
var $_txtbody;
/**
* Contains the html part of the email
* @var string
*/
var $_htmlbody;
/**
* contains the mime encoded text
* @var string
*/
var $_mime;
/**
* contains the multipart content
* @var string
*/
var $_multipart;
/**
* list of the attached images
* @var array
*/
var $_html_images = array();
/**
* list of the attachements
* @var array
*/
var $_parts = array();
/**
* Build parameters
* @var array
*/
var $_build_params = array();
/**
* Headers for the mail
* @var array
*/
var $_headers = array();
/**
* End Of Line sequence (for serialize)
* @var string
*/
var $_eol;
 
 
/**
* Constructor function
*
* @access public
*/
function Mail_mime($crlf = "\r\n")
{
$this->_setEOL($crlf);
$this->_build_params = array(
'text_encoding' => '7bit',
'html_encoding' => 'quoted-printable',
'7bit_wrap' => 998,
'html_charset' => 'ISO-8859-1',
'text_charset' => 'ISO-8859-1',
'head_charset' => 'ISO-8859-1'
);
}
 
/**
* Wakeup (unserialize) - re-sets EOL constant
*
* @access private
*/
function __wakeup()
{
$this->_setEOL($this->_eol);
}
 
/**
* Accessor function to set the body text. Body text is used if
* it's not an html mail being sent or else is used to fill the
* text/plain part that emails clients who don't support
* html should show.
*
* @param string $data Either a string or
* the file name with the contents
* @param bool $isfile If true the first param should be treated
* as a file name, else as a string (default)
* @param bool $append If true the text or file is appended to
* the existing body, else the old body is
* overwritten
* @return mixed true on success or PEAR_Error object
* @access public
*/
function setTXTBody($data, $isfile = false, $append = false)
{
if (!$isfile) {
if (!$append) {
$this->_txtbody = $data;
} else {
$this->_txtbody .= $data;
}
} else {
$cont = $this->_file2str($data);
if (PEAR::isError($cont)) {
return $cont;
}
if (!$append) {
$this->_txtbody = $cont;
} else {
$this->_txtbody .= $cont;
}
}
return true;
}
 
/**
* Adds a html part to the mail
*
* @param string $data Either a string or the file name with the
* contents
* @param bool $isfile If true the first param should be treated
* as a file name, else as a string (default)
* @return mixed true on success or PEAR_Error object
* @access public
*/
function setHTMLBody($data, $isfile = false)
{
if (!$isfile) {
$this->_htmlbody = $data;
} else {
$cont = $this->_file2str($data);
if (PEAR::isError($cont)) {
return $cont;
}
$this->_htmlbody = $cont;
}
 
return true;
}
 
/**
* Adds an image to the list of embedded images.
*
* @param string $file The image file name OR image data itself
* @param string $c_type The content type
* @param string $name The filename of the image.
* Only use if $file is the image data
* @param bool $isfilename Whether $file is a filename or not
* Defaults to true
* @return mixed true on success or PEAR_Error object
* @access public
*/
function addHTMLImage($file, $c_type='application/octet-stream',
$name = '', $isfilename = true)
{
$filedata = ($isfilename === true) ? $this->_file2str($file)
: $file;
if ($isfilename === true) {
$filename = ($name == '' ? basename($file) : basename($name));
} else {
$filename = basename($name);
}
if (PEAR::isError($filedata)) {
return $filedata;
}
$this->_html_images[] = array(
'body' => $filedata,
'name' => $filename,
'c_type' => $c_type,
'cid' => md5(uniqid(time()))
);
return true;
}
 
/**
* Adds a file to the list of attachments.
*
* @param string $file The file name of the file to attach
* OR the file data itself
* @param string $c_type The content type
* @param string $name The filename of the attachment
* Only use if $file is the file data
* @param bool $isFilename Whether $file is a filename or not
* Defaults to true
* @return mixed true on success or PEAR_Error object
* @access public
*/
function addAttachment($file, $c_type = 'application/octet-stream',
$name = '', $isfilename = true,
$encoding = 'base64')
{
$filedata = ($isfilename === true) ? $this->_file2str($file)
: $file;
if ($isfilename === true) {
// Force the name the user supplied, otherwise use $file
$filename = (!empty($name)) ? $name : $file;
} else {
$filename = $name;
}
if (empty($filename)) {
return PEAR::raiseError(
'The supplied filename for the attachment can\'t be empty'
);
}
$filename = basename($filename);
if (PEAR::isError($filedata)) {
return $filedata;
}
 
$this->_parts[] = array(
'body' => $filedata,
'name' => $filename,
'c_type' => $c_type,
'encoding' => $encoding
);
return true;
}
 
/**
* Get the contents of the given file name as string
*
* @param string $file_name path of file to process
* @return string contents of $file_name
* @access private
*/
function &_file2str($file_name)
{
if (!is_readable($file_name)) {
return PEAR::raiseError('File is not readable ' . $file_name);
}
if (!$fd = fopen($file_name, 'rb')) {
return PEAR::raiseError('Could not open ' . $file_name);
}
$filesize = filesize($file_name);
if ($filesize == 0){
$cont = "";
}else{
$cont = fread($fd, $filesize);
}
fclose($fd);
return $cont;
}
 
/**
* Adds a text subpart to the mimePart object and
* returns it during the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @param string The text to add.
* @return object The text mimePart object
* @access private
*/
function &_addTextPart(&$obj, $text)
{
$params['content_type'] = 'text/plain';
$params['encoding'] = $this->_build_params['text_encoding'];
$params['charset'] = $this->_build_params['text_charset'];
if (is_object($obj)) {
return $obj->addSubpart($text, $params);
} else {
return new Mail_mimePart($text, $params);
}
}
 
/**
* Adds a html subpart to the mimePart object and
* returns it during the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @return object The html mimePart object
* @access private
*/
function &_addHtmlPart(&$obj)
{
$params['content_type'] = 'text/html';
$params['encoding'] = $this->_build_params['html_encoding'];
$params['charset'] = $this->_build_params['html_charset'];
if (is_object($obj)) {
return $obj->addSubpart($this->_htmlbody, $params);
} else {
return new Mail_mimePart($this->_htmlbody, $params);
}
}
 
/**
* Creates a new mimePart object, using multipart/mixed as
* the initial content-type and returns it during the
* build process.
*
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addMixedPart()
{
$params['content_type'] = 'multipart/mixed';
return new Mail_mimePart('', $params);
}
 
/**
* Adds a multipart/alternative part to a mimePart
* object (or creates one), and returns it during
* the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addAlternativePart(&$obj)
{
$params['content_type'] = 'multipart/alternative';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}
 
/**
* Adds a multipart/related part to a mimePart
* object (or creates one), and returns it during
* the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addRelatedPart(&$obj)
{
$params['content_type'] = 'multipart/related';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}
 
/**
* Adds an html image subpart to a mimePart object
* and returns it during the build process.
*
* @param object The mimePart to add the image to
* @param array The image information
* @return object The image mimePart object
* @access private
*/
function &_addHtmlImagePart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = 'base64';
$params['disposition'] = 'inline';
$params['dfilename'] = $value['name'];
$params['cid'] = $value['cid'];
$obj->addSubpart($value['body'], $params);
}
 
/**
* Adds an attachment subpart to a mimePart object
* and returns it during the build process.
*
* @param object The mimePart to add the image to
* @param array The attachment information
* @return object The image mimePart object
* @access private
*/
function &_addAttachmentPart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = $value['encoding'];
$params['disposition'] = 'attachment';
$params['dfilename'] = $value['name'];
$obj->addSubpart($value['body'], $params);
}
 
/**
* Builds the multipart message from the list ($this->_parts) and
* returns the mime content.
*
* @param array Build parameters that change the way the email
* is built. Should be associative. Can contain:
* text_encoding - What encoding to use for plain text
* Default is 7bit
* html_encoding - What encoding to use for html
* Default is quoted-printable
* 7bit_wrap - Number of characters before text is
* wrapped in 7bit encoding
* Default is 998
* html_charset - The character set to use for html.
* Default is iso-8859-1
* text_charset - The character set to use for text.
* Default is iso-8859-1
* head_charset - The character set to use for headers.
* Default is iso-8859-1
* @return string The mime content
* @access public
*/
function &get($build_params = null)
{
if (isset($build_params)) {
while (list($key, $value) = each($build_params)) {
$this->_build_params[$key] = $value;
}
}
 
if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
foreach ($this->_html_images as $value) {
$regex = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . preg_quote($value['name'], '#') .
'\3#';
$rep = '\1\2=\3cid:' . $value['cid'] .'\3';
$this->_htmlbody = preg_replace($regex, $rep,
$this->_htmlbody
);
}
}
 
$null = null;
$attachments = !empty($this->_parts) ? true : false;
$html_images = !empty($this->_html_images) ? true : false;
$html = !empty($this->_htmlbody) ? true : false;
$text = (!$html AND !empty($this->_txtbody)) ? true : false;
 
switch (true) {
case $text AND !$attachments:
$message =& $this->_addTextPart($null, $this->_txtbody);
break;
 
case !$text AND !$html AND $attachments:
$message =& $this->_addMixedPart();
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;
 
case $text AND $attachments:
$message =& $this->_addMixedPart();
$this->_addTextPart($message, $this->_txtbody);
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;
 
case $html AND !$attachments AND !$html_images:
if (isset($this->_txtbody)) {
$message =& $this->_addAlternativePart($null);
$this->_addTextPart($message, $this->_txtbody);
$this->_addHtmlPart($message);
} else {
$message =& $this->_addHtmlPart($null);
}
break;
 
case $html AND !$attachments AND $html_images:
if (isset($this->_txtbody)) {
$message =& $this->_addAlternativePart($null);
$this->_addTextPart($message, $this->_txtbody);
$related =& $this->_addRelatedPart($message);
} else {
$message =& $this->_addRelatedPart($null);
$related =& $message;
}
$this->_addHtmlPart($related);
for ($i = 0; $i < count($this->_html_images); $i++) {
$this->_addHtmlImagePart($related, $this->_html_images[$i]);
}
break;
 
case $html AND $attachments AND !$html_images:
$message =& $this->_addMixedPart();
if (isset($this->_txtbody)) {
$alt =& $this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->_txtbody);
$this->_addHtmlPart($alt);
} else {
$this->_addHtmlPart($message);
}
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;
 
case $html AND $attachments AND $html_images:
$message =& $this->_addMixedPart();
if (isset($this->_txtbody)) {
$alt =& $this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->_txtbody);
$rel =& $this->_addRelatedPart($alt);
} else {
$rel =& $this->_addRelatedPart($message);
}
$this->_addHtmlPart($rel);
for ($i = 0; $i < count($this->_html_images); $i++) {
$this->_addHtmlImagePart($rel, $this->_html_images[$i]);
}
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;
 
}
 
if (isset($message)) {
$output = $message->encode();
$this->_headers = array_merge($this->_headers,
$output['headers']);
return $output['body'];
 
} else {
return false;
}
}
 
/**
* Returns an array with the headers needed to prepend to the email
* (MIME-Version and Content-Type). Format of argument is:
* $array['header-name'] = 'header-value';
*
* @param array $xtra_headers Assoc array with any extra headers.
* Optional.
* @return array Assoc array with the mime headers
* @access public
*/
function &headers($xtra_headers = null)
{
// Content-Type header should already be present,
// So just add mime version header
$headers['MIME-Version'] = '1.0';
if (isset($xtra_headers)) {
$headers = array_merge($headers, $xtra_headers);
}
$this->_headers = array_merge($headers, $this->_headers);
 
return $this->_encodeHeaders($this->_headers);
}
 
/**
* Get the text version of the headers
* (usefull if you want to use the PHP mail() function)
*
* @param array $xtra_headers Assoc array with any extra headers.
* Optional.
* @return string Plain text headers
* @access public
*/
function txtHeaders($xtra_headers = null)
{
$headers = $this->headers($xtra_headers);
$ret = '';
foreach ($headers as $key => $val) {
$ret .= "$key: $val" . MAIL_MIME_CRLF;
}
return $ret;
}
 
/**
* Sets the Subject header
*
* @param string $subject String to set the subject to
* access public
*/
function setSubject($subject)
{
$this->_headers['Subject'] = $subject;
}
 
/**
* Set an email to the From (the sender) header
*
* @param string $email The email direction to add
* @access public
*/
function setFrom($email)
{
$this->_headers['From'] = $email;
}
 
/**
* Add an email to the Cc (carbon copy) header
* (multiple calls to this method are allowed)
*
* @param string $email The email direction to add
* @access public
*/
function addCc($email)
{
if (isset($this->_headers['Cc'])) {
$this->_headers['Cc'] .= ", $email";
} else {
$this->_headers['Cc'] = $email;
}
}
 
/**
* Add an email to the Bcc (blank carbon copy) header
* (multiple calls to this method are allowed)
*
* @param string $email The email direction to add
* @access public
*/
function addBcc($email)
{
if (isset($this->_headers['Bcc'])) {
$this->_headers['Bcc'] .= ", $email";
} else {
$this->_headers['Bcc'] = $email;
}
}
 
/**
* Encodes a header as per RFC2047
*
* @param string $input The header data to encode
* @return string Encoded data
* @access private
*/
function _encodeHeaders($input)
{
foreach ($input as $hdr_name => $hdr_value) {
preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e',
'"=" .
strtoupper(dechex(ord("\1")))',
$value);
$hdr_value = str_replace($value, '=?' .
$this->_build_params['head_charset'] .
'?Q?' . $replacement . '?=',
$hdr_value);
}
$input[$hdr_name] = $hdr_value;
}
 
return $input;
}
 
/**
* Set the object's end-of-line and define the constant if applicable
*
* @param string $eol End Of Line sequence
* @access private
*/
function _setEOL($eol)
{
$this->_eol = $eol;
if (!defined('MAIL_MIME_CRLF')) {
define('MAIL_MIME_CRLF', $this->_eol, true);
}
}
 
 
} // End of class
?>
/branches/v1.0-menes/api/pear/Mail/null.php
New file
0,0 → 1,60
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Phil Kernick <philk@rotfl.com.au> |
// +----------------------------------------------------------------------+
//
// $Id: null.php,v 1.1 2005-11-24 16:15:46 florian Exp $
//
 
/**
* Null implementation of the PEAR Mail:: interface.
* @access public
* @package Mail
* @version $Revision: 1.1 $
*/
class Mail_null extends Mail {
 
/**
* Implements Mail_null::send() function. Silently discards all
* mail.
*
* @param mixed $recipients Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid. This may contain recipients not
* specified in the headers, for Bcc:, resending
* messages, etc.
*
* @param array $headers The array of headers to send with the mail, in an
* associative array, where the array key is the
* header name (ie, 'Subject'), and the array value
* is the header value (ie, 'test'). The header
* produced from those values would be 'Subject:
* test'.
*
* @param string $body The full text of the message body, including any
* Mime parts, etc.
*
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
* @access public
*/
function send($recipients, $headers, $body)
{
return true;
}
 
}
/branches/v1.0-menes/api/pear/Mail/mimeDecode.php
New file
0,0 → 1,837
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | Copyright (c) 2003-2005 The PHP Group |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// +-----------------------------------------------------------------------+
 
require_once 'PEAR.php';
 
/**
* +----------------------------- 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. |
* +----------------------------------------------------------------------+
*
* Mime Decoding class
*
* This class will parse a raw mime email and return
* the structure. Returned structure is similar to
* that returned by imap_fetchstructure().
*
* USAGE: (assume $input is your raw email)
*
* $decode = new Mail_mimeDecode($input, "\r\n");
* $structure = $decode->decode();
* print_r($structure);
*
* Or statically:
*
* $params['input'] = $input;
* $structure = Mail_mimeDecode::decode($params);
* print_r($structure);
*
* TODO:
* o Implement multipart/appledouble
* o UTF8: ???
 
> 4. We have also found a solution for decoding the UTF-8
> headers. Therefore I made the following function:
>
> function decode_utf8($txt) {
> $trans=array("Å&#8216;"=>"õ","ű"=>"û","Ő"=>"Ã&#8226;","Å°"
=>"Ã&#8250;");
> $txt=strtr($txt,$trans);
> return(utf8_decode($txt));
> }
>
> And I have inserted the following line to the class:
>
> if (strtolower($charset)=="utf-8") $text=decode_utf8($text);
>
> ... before the following one in the "_decodeHeader" function:
>
> $input = str_replace($encoded, $text, $input);
>
> This way from now on it can easily decode the UTF-8 headers too.
 
*
* @author Richard Heyes <richard@phpguru.org>
* @version $Revision: 1.1 $
* @package Mail
*/
class Mail_mimeDecode extends PEAR
{
/**
* The raw email to decode
* @var string
*/
var $_input;
 
/**
* The header part of the input
* @var string
*/
var $_header;
 
/**
* The body part of the input
* @var string
*/
var $_body;
 
/**
* If an error occurs, this is used to store the message
* @var string
*/
var $_error;
 
/**
* Flag to determine whether to include bodies in the
* returned object.
* @var boolean
*/
var $_include_bodies;
 
/**
* Flag to determine whether to decode bodies
* @var boolean
*/
var $_decode_bodies;
 
/**
* Flag to determine whether to decode headers
* @var boolean
*/
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/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
?>
/branches/v1.0-menes/api/pear/Mail/sendmail.php
New file
0,0 → 1,145
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
 
/**
* Sendmail implementation of the PEAR Mail:: interface.
* @access public
* @package Mail
* @version $Revision: 1.1 $
*/
class Mail_sendmail extends Mail {
 
/**
* The location of the sendmail or sendmail wrapper binary on the
* filesystem.
* @var string
*/
var $sendmail_path = '/usr/sbin/sendmail';
 
/**
* Any extra command-line parameters to pass to the sendmail or
* sendmail wrapper binary.
* @var string
*/
var $sendmail_args = '';
 
/**
* Constructor.
*
* Instantiates a new Mail_sendmail:: object based on the parameters
* passed in. It looks for the following parameters:
* sendmail_path The location of the sendmail binary on the
* filesystem. Defaults to '/usr/sbin/sendmail'.
*
* sendmail_args Any extra parameters to pass to the sendmail
* or sendmail wrapper binary.
*
* If a parameter is present in the $params array, it replaces the
* default.
*
* @param array $params Hash containing any parameters different from the
* defaults.
* @access public
*/
function Mail_sendmail($params)
{
if (isset($params['sendmail_path'])) $this->sendmail_path = $params['sendmail_path'];
if (isset($params['sendmail_args'])) $this->sendmail_args = $params['sendmail_args'];
 
/*
* Because we need to pass message headers to the sendmail program on
* the commandline, we can't guarantee the use of the standard "\r\n"
* separator. Instead, we use the system's native line separator.
*/
$this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
}
 
/**
* Implements Mail::send() function using the sendmail
* command-line binary.
*
* @param mixed $recipients Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid. This may contain recipients not
* specified in the headers, for Bcc:, resending
* messages, etc.
*
* @param array $headers The array of headers to send with the mail, in an
* associative array, where the array key is the
* header name (ie, 'Subject'), and the array value
* is the header value (ie, 'test'). The header
* produced from those values would be 'Subject:
* test'.
*
* @param string $body The full text of the message body, including any
* Mime parts, etc.
*
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
* @access public
*/
function send($recipients, $headers, $body)
{
$recipients = $this->parseRecipients($recipients);
if (PEAR::isError($recipients)) {
return $recipients;
}
$recipients = escapeShellCmd(implode(' ', $recipients));
 
$headerElements = $this->prepareHeaders($headers);
if (PEAR::isError($headerElements)) {
return $headerElements;
}
list($from, $text_headers) = $headerElements;
 
if (!isset($from)) {
return PEAR::raiseError('No from address given.');
} elseif (strpos($from, ' ') !== false ||
strpos($from, ';') !== false ||
strpos($from, '&') !== false ||
strpos($from, '`') !== false) {
return PEAR::raiseError('From address specified with dangerous characters.');
}
 
$result = 0;
if (@is_file($this->sendmail_path)) {
$from = escapeShellCmd($from);
$mail = popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w');
fputs($mail, $text_headers);
fputs($mail, $this->sep); // newline to end the headers section
fputs($mail, $body);
$result = pclose($mail);
if (version_compare(phpversion(), '4.2.3') == -1) {
// With older php versions, we need to shift the
// pclose result to get the exit code.
$result = $result >> 8 & 0xFF;
}
} else {
return PEAR::raiseError('sendmail [' . $this->sendmail_path . '] is not a valid file');
}
 
if ($result != 0) {
return PEAR::raiseError('sendmail returned error code ' . $result,
$result);
}
 
return true;
}
 
}
/branches/v1.0-menes/api/pear/HTML/QuickForm.php
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/HTML/QuickForm.php
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/HTML/Template/IT.php
New file
0,0 → 1,990
<?php
//
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
// +----------------------------------------------------------------------+
// | This source file is subject to the New BSD license, That is bundled |
// | with this package in the file LICENSE, and is available through |
// | the world-wide-web at |
// | http://www.opensource.org/licenses/bsd-license.php |
// | If you did not receive a copy of the new BSDlicense and are unable |
// | to obtain it through the world-wide-web, please send a note to |
// | pajoye@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
// | Pierre-Alain Joye <pajoye@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
//
 
require_once 'PEAR.php';
 
define('IT_OK', 1);
define('IT_ERROR', -1);
define('IT_TPL_NOT_FOUND', -2);
define('IT_BLOCK_NOT_FOUND', -3);
define('IT_BLOCK_DUPLICATE', -4);
define('IT_UNKNOWN_OPTION', -6);
/**
* Integrated Template - IT
*
* Well there's not much to say about it. I needed a template class that
* supports a single template file with multiple (nested) blocks inside and
* a simple block API.
*
* The Isotemplate API is somewhat tricky for a beginner although it is the best
* one you can build. template::parse() [phplib template = Isotemplate] requests
* you to name a source and a target where the current block gets parsed into.
* Source and target can be block names or even handler names. This API gives you
* a maximum of fexibility but you always have to know what you do which is
* quite unusual for php skripter like me.
*
* I noticed that I do not any control on which block gets parsed into which one.
* If all blocks are within one file, the script knows how they are nested and in
* which way you have to parse them. IT knows that inner1 is a child of block2, there's
* no need to tell him about this.
*
* <table border>
* <tr>
* <td colspan=2>
* __global__
* <p>
* (hidden and automatically added)
* </td>
* </tr>
* <tr>
* <td>block1</td>
* <td>
* <table border>
* <tr>
* <td colspan=2>block2</td>
* </tr>
* <tr>
* <td>inner1</td>
* <td>inner2</td>
* </tr>
* </table>
* </td>
* </tr>
* </table>
*
* To add content to block1 you simply type:
* <code>$tpl->setCurrentBlock("block1");</code>
* and repeat this as often as needed:
* <code>
* $tpl->setVariable(...);
* $tpl->parseCurrentBlock();
* </code>
*
* To add content to block2 you would type something like:
* <code>
* $tpl->setCurrentBlock("inner1");
* $tpl->setVariable(...);
* $tpl->parseCurrentBlock();
*
* $tpl->setVariable(...);
* $tpl->parseCurrentBlock();
*
* $tpl->parse("block1");
* </code>
*
* This will result in one repition of block1 which contains two repitions
* of inner1. inner2 will be removed if $removeEmptyBlock is set to true which is the default.
*
* Usage:
* <code>
* $tpl = new HTML_Template_IT( [string filerootdir] );
*
* // load a template or set it with setTemplate()
* $tpl->loadTemplatefile( string filename [, boolean removeUnknownVariables, boolean removeEmptyBlocks] )
*
* // set "global" Variables meaning variables not beeing within a (inner) block
* $tpl->setVariable( string variablename, mixed value );
*
* // like with the Isotemplates there's a second way to use setVariable()
* $tpl->setVariable( array ( string varname => mixed value ) );
*
* // Let's use any block, even a deeply nested one
* $tpl->setCurrentBlock( string blockname );
*
* // repeat this as often as you need it.
* $tpl->setVariable( array ( string varname => mixed value ) );
* $tpl->parseCurrentBlock();
*
* // get the parsed template or print it: $tpl->show()
* $tpl->get();
* </code>
*
* @author Ulf Wendel <uw@netuse.de>
* @version $Id$
* @access public
* @package HTML_Template_IT
*/
class HTML_Template_IT
{
/**
* Contains the error objects
* @var array
* @access public
* @see halt(), $printError, $haltOnError
*/
var $err = array();
 
/**
* Clear cache on get()?
* @var boolean
*/
var $clearCache = false;
 
/**
* First character of a variable placeholder ( _{_VARIABLE} ).
* @var string
* @access public
* @see $closingDelimiter, $blocknameRegExp, $variablenameRegExp
*/
var $openingDelimiter = '{';
 
/**
* Last character of a variable placeholder ( {VARIABLE_}_ ).
* @var string
* @access public
* @see $openingDelimiter, $blocknameRegExp, $variablenameRegExp
*/
var $closingDelimiter = '}';
 
/**
* RegExp matching a block in the template.
* Per default "sm" is used as the regexp modifier, "i" is missing.
* That means a case sensitive search is done.
* @var string
* @access public
* @see $variablenameRegExp, $openingDelimiter, $closingDelimiter
*/
var $blocknameRegExp = '[0-9A-Za-z_-]+';
 
/**
* RegExp matching a variable placeholder in the template.
* Per default "sm" is used as the regexp modifier, "i" is missing.
* That means a case sensitive search is done.
* @var string
* @access public
* @see $blocknameRegExp, $openingDelimiter, $closingDelimiter
*/
var $variablenameRegExp = '[0-9A-Za-z_-]+';
 
/**
* RegExp used to find variable placeholder, filled by the constructor.
* @var string Looks somewhat like @(delimiter varname delimiter)@
* @access public
* @see IntegratedTemplate()
*/
var $variablesRegExp = '';
 
/**
* RegExp used to strip unused variable placeholder.
* @brother $variablesRegExp
*/
var $removeVariablesRegExp = '';
 
/**
* Controls the handling of unknown variables, default is remove.
* @var boolean
* @access public
*/
var $removeUnknownVariables = true;
 
/**
* Controls the handling of empty blocks, default is remove.
* @var boolean
* @access public
*/
var $removeEmptyBlocks = true;
 
/**
* RegExp used to find blocks an their content, filled by the constructor.
* @var string
* @see IntegratedTemplate()
*/
var $blockRegExp = '';
 
/**
* Name of the current block.
* @var string
*/
var $currentBlock = '__global__';
 
/**
* Content of the template.
* @var string
*/
var $template = '';
 
/**
* Array of all blocks and their content.
*
* @var array
* @see findBlocks()
*/
var $blocklist = array();
 
/**
* Array with the parsed content of a block.
*
* @var array
*/
var $blockdata = array();
 
/**
* Array of variables in a block.
* @var array
*/
var $blockvariables = array();
 
/**
* Array of inner blocks of a block.
* @var array
*/
var $blockinner = array();
 
/**
* List of blocks to preverse even if they are "empty".
*
* This is something special. Sometimes you have blocks that
* should be preserved although they are empty (no placeholder replaced).
* Think of a shopping basket. If it's empty you have to drop a message to
* the user. If it's filled you have to show the contents of
* the shopping baseket. Now where do you place the message that the basket
* is empty? It's no good idea to place it in you applications as customers
* tend to like unecessary minor text changes. Having another template file
* for an empty basket means that it's very likely that one fine day
* the filled and empty basket templates have different layout. I decided
* to introduce blocks that to not contain any placeholder but only
* text such as the message "Your shopping basked is empty".
*
* Now if there is no replacement done in such a block the block will
* be recognized as "empty" and by default ($removeEmptyBlocks = true) be
* stripped off. To avoid thisyou can now call touchBlock() to avoid this.
*
* The array $touchedBlocks stores a list of touched block which must not
* be removed even if they are empty.
*
* @var array $touchedBlocks
* @see touchBlock(), $removeEmptyBlocks
*/
var $touchedBlocks = array();
 
/**
* List of blocks which should not be shown even if not "empty"
* @var array $_hiddenBlocks
* @see hideBlock(), $removeEmptyBlocks
*/
var $_hiddenBlocks = array();
 
/**
* Variable cache.
*
* Variables get cached before any replacement is done.
* Advantage: empty blocks can be removed automatically.
* Disadvantage: might take some more memory
*
* @var array
* @see setVariable(), $clearCacheOnParse
*/
var $variableCache = array();
 
/**
* Clear the variable cache on parse?
*
* If you're not an expert just leave the default false.
* True reduces memory consumption somewhat if you tend to
* add lots of values for unknown placeholder.
*
* @var boolean
*/
var $clearCacheOnParse = false;
 
/**
* Root directory for all file operations.
* The string gets prefixed to all filenames given.
* @var string
* @see HTML_Template_IT(), setRoot()
*/
var $fileRoot = '';
 
/**
* Internal flag indicating that a blockname was used multiple times.
* @var boolean
*/
var $flagBlocktrouble = false;
 
/**
* Flag indicating that the global block was parsed.
* @var boolean
*/
var $flagGlobalParsed = false;
 
/**
* EXPERIMENTAL! FIXME!
* Flag indication that a template gets cached.
*
* Complex templates require some times to be preparsed
* before the replacement can take place. Often I use
* one template file over and over again but I don't know
* before that I will use the same template file again.
* Now IT could notice this and skip the preparse.
*
* @var boolean
*/
var $flagCacheTemplatefile = true;
 
/**
* EXPERIMENTAL! FIXME!
*/
var $lastTemplatefile = '';
 
/**
* $_options['preserve_data'] Whether to substitute variables and remove
* empty placeholders in data passed through setVariable
* (see also bugs #20199, #21951).
* $_options['use_preg'] Whether to use preg_replace instead of
* str_replace in parse()
* (this is a backwards compatibility feature, see also bugs #21951, #20392)
*/
var $_options = array(
'preserve_data' => false,
'use_preg' => true
);
 
/**
* Builds some complex regular expressions and optinally sets the
* file root directory.
*
* Make sure that you call this constructor if you derive your template
* class from this one.
*
* @param string File root directory, prefix for all filenames
* given to the object.
* @see setRoot()
*/
function HTML_Template_IT($root = '', $options = null)
{
if (!is_null($options)) {
$this->setOptions($options);
}
$this->variablesRegExp = '@' . $this->openingDelimiter .
'(' . $this->variablenameRegExp . ')' .
$this->closingDelimiter . '@sm';
$this->removeVariablesRegExp = '@' . $this->openingDelimiter .
"\s*(" . $this->variablenameRegExp .
")\s*" . $this->closingDelimiter .'@sm';
 
$this->blockRegExp = '@<!--\s+BEGIN\s+(' . $this->blocknameRegExp .
')\s+-->(.*)<!--\s+END\s+\1\s+-->@sm';
 
$this->setRoot($root);
} // end constructor
 
 
/**
* Sets the option for the template class
*
* @access public
* @param string option name
* @param mixed option value
* @return mixed IT_OK on success, error object on failure
*/
function setOption($option, $value)
{
if (array_key_exists($option, $this->_options)) {
$this->_options[$option] = $value;
return IT_OK;
}
 
return PEAR::raiseError(
$this->errorMessage(IT_UNKNOWN_OPTION) . ": '{$option}'",
IT_UNKNOWN_OPTION
);
}
 
/**
* Sets the options for the template class
*
* @access public
* @param string options array of options
* default value:
* 'preserve_data' => false,
* 'use_preg' => true
* @param mixed option value
* @return mixed IT_OK on success, error object on failure
* @see $options
*/
function setOptions($options)
{
if (is_array($options)) {
foreach ($options as $option => $value) {
$error = $this->setOption($option, $value);
if (PEAR::isError($error)) {
return $error;
}
}
}
 
return IT_OK;
}
 
/**
* Print a certain block with all replacements done.
* @brother get()
*/
function show($block = '__global__')
{
print $this->get($block);
} // end func show
 
/**
* Returns a block with all replacements done.
*
* @param string name of the block
* @return string
* @throws PEAR_Error
* @access public
* @see show()
*/
function get($block = '__global__')
{
if ($block == '__global__' && !$this->flagGlobalParsed) {
$this->parse('__global__');
}
 
if (!isset($this->blocklist[$block])) {
$this->err[] = PEAR::raiseError(
$this->errorMessage(IT_BLOCK_NOT_FOUND) .
'"' . $block . "'",
IT_BLOCK_NOT_FOUND
);
return '';
}
 
if (isset($this->blockdata[$block])) {
$ret = $this->blockdata[$block];
if ($this->clearCache) {
unset($this->blockdata[$block]);
}
if ($this->_options['preserve_data']) {
$ret = str_replace(
$this->openingDelimiter .
'%preserved%' . $this->closingDelimiter,
$this->openingDelimiter,
$ret
);
}
return $ret;
}
 
return '';
} // end func get()
 
/**
* Parses the given block.
*
* @param string name of the block to be parsed
* @access public
* @see parseCurrentBlock()
* @throws PEAR_Error
*/
function parse($block = '__global__', $flag_recursion = false)
{
static $regs, $values;
 
if (!isset($this->blocklist[$block])) {
return PEAR::raiseError(
$this->errorMessage( IT_BLOCK_NOT_FOUND ) . '"' . $block . "'",
IT_BLOCK_NOT_FOUND
);
}
 
if ($block == '__global__') {
$this->flagGlobalParsed = true;
}
 
if (!$flag_recursion) {
$regs = array();
$values = array();
}
$outer = $this->blocklist[$block];
$empty = true;
 
if ($this->clearCacheOnParse) {
foreach ($this->variableCache as $name => $value) {
$regs[] = $this->openingDelimiter .
$name . $this->closingDelimiter;
$values[] = $value;
$empty = false;
}
$this->variableCache = array();
} else {
foreach ($this->blockvariables[$block] as $allowedvar => $v) {
 
if (isset($this->variableCache[$allowedvar])) {
$regs[] = $this->openingDelimiter .
$allowedvar . $this->closingDelimiter;
$values[] = $this->variableCache[$allowedvar];
unset($this->variableCache[$allowedvar]);
$empty = false;
}
}
}
 
if (isset($this->blockinner[$block])) {
foreach ($this->blockinner[$block] as $k => $innerblock) {
 
$this->parse($innerblock, true);
if ($this->blockdata[$innerblock] != '') {
$empty = false;
}
 
$placeholder = $this->openingDelimiter . "__" .
$innerblock . "__" . $this->closingDelimiter;
$outer = str_replace(
$placeholder,
$this->blockdata[$innerblock], $outer
);
$this->blockdata[$innerblock] = "";
}
 
}
 
if (!$flag_recursion && 0 != count($values)) {
if ($this->_options['use_preg']) {
$regs = array_map(array(
&$this, '_addPregDelimiters'),
$regs
);
$funcReplace = 'preg_replace';
} else {
$funcReplace = 'str_replace';
}
 
if ($this->_options['preserve_data']) {
$values = array_map(
array(&$this, '_preserveOpeningDelimiter'), $values
);
}
 
$outer = $funcReplace($regs, $values, $outer);
 
if ($this->removeUnknownVariables) {
$outer = preg_replace($this->removeVariablesRegExp, "", $outer);
}
}
 
if ($empty) {
if (!$this->removeEmptyBlocks) {
$this->blockdata[$block ].= $outer;
} else {
if (isset($this->touchedBlocks[$block])) {
$this->blockdata[$block] .= $outer;
unset($this->touchedBlocks[$block]);
}
}
} else {
$this->blockdata[$block] .= $outer;
}
 
return $empty;
} // end func parse
 
/**
* Parses the current block
* @see parse(), setCurrentBlock(), $currentBlock
* @access public
*/
function parseCurrentBlock()
{
return $this->parse($this->currentBlock);
} // end func parseCurrentBlock
 
/**
* Sets a variable value.
*
* The function can be used eighter like setVariable( "varname", "value")
* or with one array $variables["varname"] = "value"
* given setVariable($variables) quite like phplib templates set_var().
*
* @param mixed string with the variable name or an array
* %variables["varname"] = "value"
* @param string value of the variable or empty if $variable
* is an array.
* @param string prefix for variable names
* @access public
*/
function setVariable($variable, $value = '')
{
if (is_array($variable)) {
$this->variableCache = array_merge(
$this->variableCache, $variable
);
} else {
$this->variableCache[$variable] = $value;
}
} // end func setVariable
 
/**
* Sets the name of the current block that is the block where variables
* are added.
*
* @param string name of the block
* @return boolean false on failure, otherwise true
* @throws PEAR_Error
* @access public
*/
function setCurrentBlock($block = '__global__')
{
 
if (!isset($this->blocklist[$block])) {
return PEAR::raiseError(
$this->errorMessage( IT_BLOCK_NOT_FOUND ) .
'"' . $block . "'", IT_BLOCK_NOT_FOUND
);
}
 
$this->currentBlock = $block;
 
return true;
} // end func setCurrentBlock
 
/**
* Preserves an empty block even if removeEmptyBlocks is true.
*
* @param string name of the block
* @return boolean false on false, otherwise true
* @throws PEAR_Error
* @access public
* @see $removeEmptyBlocks
*/
function touchBlock($block)
{
if (!isset($this->blocklist[$block])) {
return PEAR::raiseError(
$this->errorMessage(IT_BLOCK_NOT_FOUND) .
'"' . $block . "'", IT_BLOCK_NOT_FOUND);
}
 
$this->touchedBlocks[$block] = true;
 
return true;
} // end func touchBlock
 
/**
* Clears all datafields of the object and rebuild the internal blocklist
*
* LoadTemplatefile() and setTemplate() automatically call this function
* when a new template is given. Don't use this function
* unless you know what you're doing.
*
* @access public
* @see free()
*/
function init()
{
$this->free();
$this->findBlocks($this->template);
// we don't need it any more
$this->template = '';
$this->buildBlockvariablelist();
} // end func init
 
/**
* Clears all datafields of the object.
*
* Don't use this function unless you know what you're doing.
*
* @access public
* @see init()
*/
function free()
{
$this->err = array();
 
$this->currentBlock = '__global__';
 
$this->variableCache = array();
$this->blocklookup = array();
$this->touchedBlocks = array();
 
$this->flagBlocktrouble = false;
$this->flagGlobalParsed = false;
} // end func free
 
/**
* Sets the template.
*
* You can eighter load a template file from disk with
* LoadTemplatefile() or set the template manually using this function.
*
* @param string template content
* @param boolean remove unknown/unused variables?
* @param boolean remove empty blocks?
* @see LoadTemplatefile(), $template
* @access public
*/
function setTemplate( $template, $removeUnknownVariables = true,
$removeEmptyBlocks = true)
{
$this->removeUnknownVariables = $removeUnknownVariables;
$this->removeEmptyBlocks = $removeEmptyBlocks;
 
if ($template == '' && $this->flagCacheTemplatefile) {
$this->variableCache = array();
$this->blockdata = array();
$this->touchedBlocks = array();
$this->currentBlock = '__global__';
} else {
$this->template = '<!-- BEGIN __global__ -->' . $template .
'<!-- END __global__ -->';
$this->init();
}
 
if ($this->flagBlocktrouble) {
return false;
}
 
return true;
} // end func setTemplate
 
/**
* Reads a template file from the disk.
*
* @param string name of the template file
* @param bool how to handle unknown variables.
* @param bool how to handle empty blocks.
* @access public
* @return boolean false on failure, otherwise true
* @see $template, setTemplate(), $removeUnknownVariables,
* $removeEmptyBlocks
*/
function loadTemplatefile( $filename,
$removeUnknownVariables = true,
$removeEmptyBlocks = true )
{
$template = '';
if (!$this->flagCacheTemplatefile ||
$this->lastTemplatefile != $filename
) {
$template = $this->getFile($filename);
}
$this->lastTemplatefile = $filename;
 
return $template != '' ?
$this->setTemplate(
$template,$removeUnknownVariables, $removeEmptyBlocks
) : false;
} // end func LoadTemplatefile
 
/**
* Sets the file root. The file root gets prefixed to all filenames passed
* to the object.
*
* Make sure that you override this function when using the class
* on windows.
*
* @param string
* @see IntegratedTemplate()
* @access public
*/
function setRoot($root)
{
if ($root != '' && substr($root, -1) != '/') {
$root .= '/';
}
 
$this->fileRoot = $root;
} // end func setRoot
 
/**
* Build a list of all variables within of a block
*/
function buildBlockvariablelist()
{
foreach ($this->blocklist as $name => $content) {
preg_match_all($this->variablesRegExp, $content, $regs);
 
if (count($regs[1]) != 0) {
foreach ($regs[1] as $k => $var) {
$this->blockvariables[$name][$var] = true;
}
} else {
$this->blockvariables[$name] = array();
}
}
} // end func buildBlockvariablelist
 
/**
* Returns a list of all global variables
*/
function getGlobalvariables()
{
$regs = array();
$values = array();
 
foreach ($this->blockvariables['__global__'] as $allowedvar => $v) {
if (isset($this->variableCache[$allowedvar])) {
$regs[] = '@' . $this->openingDelimiter .
$allowedvar . $this->closingDelimiter . '@';
$values[] = $this->variableCache[$allowedvar];
unset($this->variableCache[$allowedvar]);
}
}
 
return array($regs, $values);
} // end func getGlobalvariables
 
/**
* Recusively builds a list of all blocks within the template.
*
* @param string string that gets scanned
* @see $blocklist
*/
function findBlocks($string)
{
$blocklist = array();
 
if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) {
foreach ($regs as $k => $match) {
$blockname = $match[1];
$blockcontent = $match[2];
 
if (isset($this->blocklist[$blockname])) {
$this->err[] = PEAR::raiseError(
$this->errorMessage(
IT_BLOCK_DUPLICATE, $blockname),
IT_BLOCK_DUPLICATE
);
$this->flagBlocktrouble = true;
}
 
$this->blocklist[$blockname] = $blockcontent;
$this->blockdata[$blockname] = "";
 
$blocklist[] = $blockname;
 
$inner = $this->findBlocks($blockcontent);
foreach ($inner as $k => $name) {
$pattern = sprintf(
'@<!--\s+BEGIN\s+%s\s+-->(.*)<!--\s+END\s+%s\s+-->@sm',
$name,
$name
);
 
$this->blocklist[$blockname] = preg_replace(
$pattern,
$this->openingDelimiter .
'__' . $name . '__' .
$this->closingDelimiter,
$this->blocklist[$blockname]
);
$this->blockinner[$blockname][] = $name;
$this->blockparents[$name] = $blockname;
}
}
}
 
return $blocklist;
} // end func findBlocks
 
/**
* Reads a file from disk and returns its content.
* @param string Filename
* @return string Filecontent
*/
function getFile($filename)
{
if ($filename{0} == '/' && substr($this->fileRoot, -1) == '/') {
$filename = substr($filename, 1);
}
 
$filename = $this->fileRoot . $filename;
 
if (!($fh = @fopen($filename, 'r'))) {
$this->err[] = PEAR::raiseError(
$this->errorMessage(IT_TPL_NOT_FOUND) .
': "' .$filename .'"',
IT_TPL_NOT_FOUND
);
return "";
}
 
$content = fread($fh, filesize($filename));
fclose($fh);
 
return preg_replace(
"#<!-- INCLUDE (.*) -->#ime", "\$this->getFile('\\1')", $content
);
} // end func getFile
 
/**
* Adds delimiters to a string, so it can be used as a pattern
* in preg_* functions
*
* @param string
* @return string
*/
function _addPregDelimiters($str)
{
return '@' . $str . '@';
}
 
/**
* Replaces an opening delimiter by a special string
*
* @param string
* @return string
*/
function _preserveOpeningDelimiter($str)
{
return (false === strpos($str, $this->openingDelimiter))?
$str:
str_replace(
$this->openingDelimiter,
$this->openingDelimiter .
'%preserved%' . $this->closingDelimiter,
$str
);
}
 
/**
* Return a textual error message for a IT error code
*
* @param integer $value error code
*
* @return string error message, or false if the error code was
* not recognized
*/
function errorMessage($value, $blockname = '')
{
static $errorMessages;
if (!isset($errorMessages)) {
$errorMessages = array(
IT_OK => '',
IT_ERROR => 'unknown error',
IT_TPL_NOT_FOUND => 'Cannot read the template file',
IT_BLOCK_NOT_FOUND => 'Cannot find this block',
IT_BLOCK_DUPLICATE => 'The name of a block must be'.
' uniquewithin a template.'.
' Found "' . $blockname . '" twice.'.
'Unpredictable results '.
'may appear.',
IT_UNKNOWN_OPTION => 'Unknown option'
);
}
 
if (PEAR::isError($value)) {
$value = $value->getCode();
}
 
return isset($errorMessages[$value]) ?
$errorMessages[$value] : $errorMessages[IT_ERROR];
}
} // end class IntegratedTemplate
?>
/branches/v1.0-menes/api/pear/HTML/Template/ITX.php
New file
0,0 → 1,809
<?php
//
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
// +----------------------------------------------------------------------+
// | This source file is subject to the New BSD license, That is bundled |
// | with this package in the file LICENSE, and is available through |
// | the world-wide-web at |
// | http://www.opensource.org/licenses/bsd-license.php |
// | If you did not receive a copy of the new BSD license and are unable |
// | to obtain it through the world-wide-web, please send a note to |
// | pajoye@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
// | Pierre-Alain Joye <pajoye@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
//
 
require_once 'HTML/Template/IT.php';
require_once 'HTML/Template/IT_Error.php';
 
/**
* Integrated Template Extension - ITX
*
* With this class you get the full power of the phplib template class.
* You may have one file with blocks in it but you have as well one main file
* and multiple files one for each block. This is quite usefull when you have
* user configurable websites. Using blocks not in the main template allows
* you to modify some parts of your layout easily.
*
* Note that you can replace an existing block and add new blocks at runtime.
* Adding new blocks means changing a variable placeholder to a block.
*
* @author Ulf Wendel <uw@netuse.de>
* @access public
* @version $Id$
* @package IT[X]
*/
class HTML_Template_ITX extends HTML_Template_IT
{
/**
* Array with all warnings.
* @var array
* @access public
* @see $printWarning, $haltOnWarning, warning()
*/
var $warn = array();
 
/**
* Print warnings?
* @var array
* @access public
* @see $haltOnWarning, $warn, warning()
*/
var $printWarning = false;
 
/**
* Call die() on warning?
* @var boolean
* @access public
* @see $warn, $printWarning, warning()
*/
var $haltOnWarning = false;
 
/**
* RegExp used to test for a valid blockname.
* @var string
*/
var $checkblocknameRegExp = '';
 
/**
* Functionnameprefix used when searching function calls in the template.
* @var string
*/
var $functionPrefix = 'func_';
 
/**
* Functionname RegExp.
* @var string
*/
var $functionnameRegExp = '[_a-zA-Z]+[A-Za-z_0-9]*';
 
/**
* RegExp used to grep function calls in the template.
*
* The variable gets set by the constructor.
*
* @var string
* @see HTML_Template_IT()
*/
var $functionRegExp = '';
 
/**
* List of functions found in the template.
*
* @var array
*/
var $functions = array();
 
/**
* List of callback functions specified by the user.
*
* @var array
*/
var $callback = array();
 
/**
* Builds some complex regexps and calls the constructor
* of the parent class.
*
* Make sure that you call this constructor if you derive your own
* template class from this one.
*
* @see HTML_Template_IT()
*/
function HTML_Template_ITX($root = '')
{
 
$this->checkblocknameRegExp = '@' . $this->blocknameRegExp . '@';
$this->functionRegExp = '@' . $this->functionPrefix . '(' .
$this->functionnameRegExp . ')\s*\(@sm';
 
$this->HTML_Template_IT($root);
} // end func constructor
 
function init()
{
$this->free();
$this->buildFunctionlist();
$this->findBlocks($this->template);
// we don't need it any more
$this->template = '';
$this->buildBlockvariablelist();
 
} // end func init
 
/**
* Replaces an existing block with new content.
*
* This function will replace a block of the template and all blocks
* contained in the replaced block and add a new block insted, means
* you can dynamically change your template.
*
* Note that changing the template structure violates one of the IT[X]
* development goals. I've tried to write a simple to use template engine
* supporting blocks. In contrast to other systems IT[X] analyses the way
* you've nested blocks and knows which block belongs into another block.
* The nesting information helps to make the API short and simple. Replacing
* blocks does not only mean that IT[X] has to update the nesting
* information (relatively time consumpting task) but you have to make sure
* that you do not get confused due to the template change itself.
*
* @param string Blockname
* @param string Blockcontent
* @param boolean true if the new block inherits the content
* of the old block
* @return boolean
* @throws IT_Error
* @see replaceBlockfile(), addBlock(), addBlockfile()
* @access public
*/
function replaceBlock($block, $template, $keep_content = false)
{
if (!isset($this->blocklist[$block])) {
return new IT_Error(
"The block "."'$block'".
" does not exist in the template and thus it can't be replaced.",
__FILE__, __LINE__
);
}
 
if ($template == '') {
return new IT_Error('No block content given.', __FILE__, __LINE__);
}
 
if ($keep_content) {
$blockdata = $this->blockdata[$block];
}
 
// remove all kinds of links to the block / data of the block
$this->removeBlockData($block);
 
$template = "<!-- BEGIN $block -->" . $template . "<!-- END $block -->";
$parents = $this->blockparents[$block];
$this->findBlocks($template);
$this->blockparents[$block] = $parents;
 
// KLUDGE: rebuild the list for all block - could be done faster
$this->buildBlockvariablelist();
 
if ($keep_content) {
$this->blockdata[$block] = $blockdata;
}
 
// old TODO - I'm not sure if we need this
// update caches
 
return true;
} // end func replaceBlock
 
/**
* Replaces an existing block with new content from a file.
*
* @brother replaceBlock()
* @param string Blockname
* @param string Name of the file that contains the blockcontent
* @param boolean true if the new block inherits the content of the old block
*/
function replaceBlockfile($block, $filename, $keep_content = false)
{
return $this->replaceBlock($block, $this->getFile($filename), $keep_content);
} // end func replaceBlockfile
 
/**
* Adds a block to the template changing a variable placeholder
* to a block placeholder.
*
* Add means "replace a variable placeholder by a new block".
* This is different to PHPLibs templates. The function loads a
* block, creates a handle for it and assigns it to a certain
* variable placeholder. To to the same with PHPLibs templates you would
* call set_file() to create the handle and parse() to assign the
* parsed block to a variable. By this PHPLibs templates assume
* that you tend to assign a block to more than one one placeholder.
* To assign a parsed block to more than only the placeholder you specify
* in this function you have to use a combination of getBlock()
* and setVariable().
*
* As no updates to cached data is necessary addBlock() and addBlockfile()
* are rather "cheap" meaning quick operations.
*
* The block content must not start with <!-- BEGIN blockname -->
* and end with <!-- END blockname --> this would cause overhead and
* produce an error.
*
* @param string Name of the variable placeholder, the name must be unique
* within the template.
* @param string Name of the block to be added
* @param string Content of the block
* @return boolean
* @throws IT_Error
* @see addBlockfile()
* @access public
*/
function addBlock($placeholder, $blockname, $template)
{
// Don't trust any user even if it's a programmer or yourself...
if ($placeholder == '') {
return new IT_Error('No variable placeholder given.',
__FILE__, __LINE__
);
} elseif ($blockname == '' ||
!preg_match($this->checkblocknameRegExp, $blockname)
) {
return new IT_Error("No or invalid blockname '$blockname' given.",
__FILE__, __LINE__
);
} elseif ($template == '') {
return new IT_Error('No block content given.', __FILE__, __LINE__);
} elseif (isset($this->blocklist[$blockname])) {
return new IT_Error('The block already exists.',
__FILE__, __LINE__
);
}
 
// find out where to insert the new block
$parents = $this->findPlaceholderBlocks($placeholder);
if (count($parents) == 0) {
 
return new IT_Error(
"The variable placeholder".
" '$placeholder' was not found in the template.",
__FILE__, __LINE__
);
 
} elseif (count($parents) > 1) {
 
reset($parents);
while (list($k, $parent) = each($parents)) {
$msg .= "$parent, ";
}
$msg = substr($parent, -2);
 
return new IT_Error("The variable placeholder "."'$placeholder'".
" must be unique, found in multiple blocks '$msg'.",
__FILE__, __LINE__
);
}
 
$template = "<!-- BEGIN $blockname -->" . $template . "<!-- END $blockname -->";
$this->findBlocks($template);
if ($this->flagBlocktrouble) {
return false; // findBlocks() already throws an exception
}
$this->blockinner[$parents[0]][] = $blockname;
$this->blocklist[$parents[0]] = preg_replace(
'@' . $this->openingDelimiter . $placeholder .
$this->closingDelimiter . '@',
 
$this->openingDelimiter . '__' . $blockname . '__' .
$this->closingDelimiter,
 
$this->blocklist[$parents[0]]
);
 
$this->deleteFromBlockvariablelist($parents[0], $placeholder);
$this->updateBlockvariablelist($blockname);
/*
// check if any inner blocks were found
if(is_array($this->blockinner[$blockname]) and count($this->blockinner[$blockname]) > 0) {
// loop through inner blocks, registering the variable placeholders in each
foreach($this->blockinner[$blockname] as $childBlock) {
$this->updateBlockvariablelist($childBlock);
}
}
*/
return true;
} // end func addBlock
 
/**
* Adds a block taken from a file to the template changing a variable
* placeholder to a block placeholder.
*
* @param string Name of the variable placeholder to be converted
* @param string Name of the block to be added
* @param string File that contains the block
* @brother addBlock()
*/
function addBlockfile($placeholder, $blockname, $filename)
{
return $this->addBlock($placeholder, $blockname, $this->getFile($filename));
} // end func addBlockfile
 
/**
* Returns the name of the (first) block that contains
* the specified placeholder.
*
* @param string Name of the placeholder you're searching
* @param string Name of the block to scan. If left out (default)
* all blocks are scanned.
* @return string Name of the (first) block that contains
* the specified placeholder.
* If the placeholder was not found or an error occured
* an empty string is returned.
* @throws IT_Error
* @access public
*/
function placeholderExists($placeholder, $block = '')
{
if ($placeholder == '') {
new IT_Error('No placeholder name given.', __FILE__, __LINE__);
return '';
}
 
if ($block != '' && !isset($this->blocklist[$block])) {
new IT_Error("Unknown block '$block'.", __FILE__, __LINE__);
return '';
}
 
// name of the block where the given placeholder was found
$found = '';
 
if ($block != '') {
if (is_array($variables = $this->blockvariables[$block])) {
// search the value in the list of blockvariables
reset($variables);
while (list($k, $variable) = each($variables)) {
if ($k == $placeholder) {
$found = $block;
break;
}
}
}
} else {
 
// search all blocks and return the name of the first block that
// contains the placeholder
reset($this->blockvariables);
while (list($blockname, $variables) = each($this->blockvariables)){
if (is_array($variables) && isset($variables[$placeholder])) {
$found = $blockname;
break;
}
}
}
 
return $found;
} // end func placeholderExists
 
/**
* Checks the list of function calls in the template and
* calls their callback function.
*
* @access public
*/
function performCallback()
{
reset($this->functions);
while (list($func_id, $function) = each($this->functions)) {
if (isset($this->callback[$function['name']])) {
if ($this->callback[$function['name']]['object'] != '') {
$this->variableCache['__function' . $func_id . '__'] =
call_user_func(
array(
&$GLOBALS[$this->callback[$function['name']]['object']],
$this->callback[$function['name']]['function']),
$function['args']
);
} else {
$this->variableCache['__function' . $func_id . '__'] =
call_user_func(
$this->callback[$function['name']]['function'],
$function['args']
);
}
}
}
 
} // end func performCallback
 
/**
* Returns a list of all function calls in the current template.
*
* @return array
* @access public
*/
function getFunctioncalls()
{
return $this->functions;
} // end func getFunctioncalls
 
/**
* Replaces a function call with the given replacement.
*
* @param int Function ID
* @param string Replacement
* @deprec
*/
function setFunctioncontent($functionID, $replacement)
{
$this->variableCache['__function' . $functionID . '__'] = $replacement;
} // end func setFunctioncontent
 
/**
* Sets a callback function.
*
* IT[X] templates (note the X) can contain simple function calls.
* "function call" means that the editor of the template can add
* special placeholder to the template like 'func_h1("embedded in h1")'.
* IT[X] will grab this function calls and allow you to define a callback
* function for them.
*
* This is an absolutely evil feature. If your application makes heavy
* use of such callbacks and you're even implementing if-then etc. on
* the level of a template engine you're reiventing the wheel... - that's
* actually how PHP came into life. Anyway, sometimes it's handy.
*
* Consider also using XML/XSLT or native PHP. And please do not push
* IT[X] any further into this direction of adding logics to the template
* engine.
*
* For those of you ready for the X in IT[X]:
*
* <?php
* ...
* function h_one($args) {
* return sprintf('<h1>%s</h1>', $args[0]);
* }
*
* ...
* $itx = new HTML_Template_ITX( ... );
* ...
* $itx->setCallbackFunction('h1', 'h_one');
* $itx->performCallback();
* ?>
*
* template:
* func_h1('H1 Headline');
*
* @param string Function name in the template
* @param string Name of the callback function
* @param string Name of the callback object
* @return boolean False on failure.
* @throws IT_Error
* @access public
*/
function
setCallbackFunction($tplfunction, $callbackfunction, $callbackobject = '')
{
if ($tplfunction == '' || $callbackfunction == '') {
return new IT_Error(
"No template function "."('$tplfunction')".
" and/or no callback function ('$callback') given.",
__FILE__, __LINE__
);
}
$this->callback[$tplfunction] = array(
'function' => $callbackfunction,
'object' => $callbackobject
);
 
return true;
} // end func setCallbackFunction
 
/**
* Sets the Callback function lookup table
*
* @param array function table
* array[templatefunction] =
* array(
* "function" => userfunction,
* "object" => userobject
* )
* @access public
*/
function setCallbackFuntiontable($functions)
{
$this->callback = $functions;
} // end func setCallbackFunctiontable
 
/**
* Recursively removes all data assiciated with a block, including all inner blocks
*
* @param string block to be removed
*/
function removeBlockData($block)
{
if (isset($this->blockinner[$block])) {
foreach ($this->blockinner[$block] as $k => $inner) {
$this->removeBlockData($inner);
}
 
unset($this->blockinner[$block]);
}
 
unset($this->blocklist[$block]);
unset($this->blockdata[$block]);
unset($this->blockvariables[$block]);
unset($this->touchedBlocks[$block]);
 
} // end func removeBlockinner
 
/**
* Returns a list of blocknames in the template.
*
* @return array [blockname => blockname]
* @access public
* @see blockExists()
*/
function getBlocklist()
{
$blocklist = array();
foreach ($this->blocklist as $block => $content) {
$blocklist[$block] = $block;
}
 
return $blocklist;
} // end func getBlocklist
 
/**
* Checks wheter a block exists.
*
* @param string
* @return boolean
* @access public
* @see getBlocklist()
*/
function blockExists($blockname)
{
return isset($this->blocklist[$blockname]);
} // end func blockExists
 
/**
* Returns a list of variables of a block.
*
* @param string Blockname
* @return array [varname => varname]
* @access public
* @see BlockvariableExists()
*/
function getBlockvariables($block)
{
if (!isset($this->blockvariables[$block])) {
return array();
}
 
$variables = array();
foreach ($this->blockvariables[$block] as $variable => $v) {
$variables[$variable] = $variable;
}
 
return $variables;
} // end func getBlockvariables
 
/**
* Checks wheter a block variable exists.
*
* @param string Blockname
* @param string Variablename
* @return boolean
* @access public
* @see getBlockvariables()
*/
function BlockvariableExists($block, $variable)
{
return isset($this->blockvariables[$block][$variable]);
} // end func BlockvariableExists
 
/**
* Builds a functionlist from the template.
*/
function buildFunctionlist()
{
$this->functions = array();
 
$template = $this->template;
$num = 0;
 
while (preg_match($this->functionRegExp, $template, $regs)) {
 
$pos = strpos($template, $regs[0]);
$template = substr($template, $pos + strlen($regs[0]));
 
$head = $this->getValue($template, ')');
$args = array();
 
$search = $regs[0] . $head . ')';
 
$replace = $this->openingDelimiter .
'__function' . $num . '__' .
$this->closingDelimiter;
 
$this->template = str_replace($search, $replace, $this->template);
$template = str_replace($search, $replace, $template);
 
while ($head != '' && $args2 = $this->getValue($head, ',')) {
$arg2 = trim($args2);
$args[] = ('"' == $arg2{0} || "'" == $arg2{0}) ?
substr($arg2, 1, -1) : $arg2;
if ($arg2 == $head) {
break;
}
$head = substr($head, strlen($arg2) + 1);
}
 
$this->functions[$num++] = array(
'name' => $regs[1],
'args' => $args
);
}
 
} // end func buildFunctionlist
 
function getValue($code, $delimiter) {
if ($code == '') {
return '';
}
 
if (!is_array($delimiter)) {
$delimiter = array( $delimiter => true );
}
 
$len = strlen($code);
$enclosed = false;
$enclosed_by = '';
 
if (isset($delimiter[$code[0]])) {
$i = 1;
} else {
for ($i = 0; $i < $len; ++$i) {
$char = $code[$i];
 
if (
($char == '"' || $char = "'") &&
($char == $enclosed_by || '' == $enclosed_by) &&
(0 == $i || ($i > 0 && '\\' != $code[$i - 1]))
) {
 
if (!$enclosed) {
$enclosed_by = $char;
} else {
$enclosed_by = "";
}
$enclosed = !$enclosed;
 
}
 
if (!$enclosed && isset($delimiter[$char])) {
break;
}
}
}
 
return substr($code, 0, $i);
} // end func getValue
 
/**
* Deletes one or many variables from the block variable list.
*
* @param string Blockname
* @param mixed Name of one variable or array of variables
* ( array ( name => true ) ) to be stripped.
*/
function deleteFromBlockvariablelist($block, $variables)
{
if (!is_array($variables)) {
$variables = array($variables => true);
}
 
reset($this->blockvariables[$block]);
while (list($varname, $val) = each($this->blockvariables[$block])) {
if (isset($variables[$varname])) {
unset($this->blockvariables[$block][$varname]);
}
}
} // end deleteFromBlockvariablelist
 
/**
* Updates the variable list of a block.
*
* @param string Blockname
*/
function updateBlockvariablelist($block)
{
preg_match_all( $this->variablesRegExp,
$this->blocklist[$block], $regs
);
 
if (count($regs[1]) != 0) {
foreach ($regs[1] as $k => $var) {
$this->blockvariables[$block][$var] = true;
}
} else {
$this->blockvariables[$block] = array();
}
 
// check if any inner blocks were found
if (isset($this->blockinner[$block]) &&
is_array($this->blockinner[$block]) &&
count($this->blockinner[$block]) > 0
) {
/*
* loop through inner blocks, registering the variable
* placeholders in each
*/
foreach ($this->blockinner[$block] as $childBlock) {
$this->updateBlockvariablelist($childBlock);
}
}
} // end func updateBlockvariablelist
 
/**
* Returns an array of blocknames where the given variable
* placeholder is used.
*
* @param string Variable placeholder
* @return array $parents parents[0..n] = blockname
*/
function findPlaceholderBlocks($variable)
{
$parents = array();
reset($this->blocklist);
while (list($blockname, $content) = each($this->blocklist)) {
reset($this->blockvariables[$blockname]);
while (
list($varname, $val) = each($this->blockvariables[$blockname]))
{
if ($variable == $varname) {
$parents[] = $blockname;
}
}
}
 
return $parents;
} // end func findPlaceholderBlocks
 
/**
* Handles warnings, saves them to $warn and prints them or
* calls die() depending on the flags
*
* @param string Warning
* @param string File where the warning occured
* @param int Linenumber where the warning occured
* @see $warn, $printWarning, $haltOnWarning
*/
function warning($message, $file = '', $line = 0)
{
$message = sprintf(
'HTML_Template_ITX Warning: %s [File: %s, Line: %d]',
$message,
$file,
$line
);
 
$this->warn[] = $message;
 
if ($this->printWarning) {
print $message;
}
 
if ($this->haltOnWarning) {
die($message);
}
} // end func warning
 
} // end class HTML_Template_ITX
?>
/branches/v1.0-menes/api/pear/HTML/Template/IT_Error.php
New file
0,0 → 1,51
<?php
//
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
// +----------------------------------------------------------------------+
// | This source file is subject to the New BSD license, That is bundled |
// | with this package in the file LICENSE, and is available through |
// | the world-wide-web at |
// | http://www.opensource.org/licenses/bsd-license.php |
// | If you did not receive a copy of the new BSD license and are unable |
// | to obtain it through the world-wide-web, please send a note to |
// | pajoye@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
// | Pierre-Alain Joye <pajoye@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
 
require_once "PEAR.php";
 
/**
* IT[X] Error class
*
* @package IT[X]
*/
class IT_Error extends PEAR_Error {
 
 
/**
* Prefix of all error messages.
*
* @var string
*/
var $error_message_prefix = "IntegratedTemplate Error: ";
/**
* Creates an cache error object.
*
* @param string error message
* @param string file where the error occured
* @param string linenumber where the error occured
*/
function IT_Error($msg, $file = __FILE__, $line = __LINE__) {
$this->PEAR_Error(sprintf("%s [%s on line %d].", $msg, $file, $line));
} // end func IT_Error
} // end class IT_Error
?>
/branches/v1.0-menes/api/pear/HTML/Table.php
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/HTML/Table.php
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/HTML/Common.php
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/HTML/Common.php
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/HTML/QuickForm/html.php
New file
0,0 → 1,67
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Alexey Borzov <borz_off@cs.msu.su> |
// +----------------------------------------------------------------------+
//
// $Id: html.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/static.php';
 
/**
* A pseudo-element used for adding raw HTML to form
*
* Intended for use with the default renderer only, template-based
* ones may (and probably will) completely ignore this
*
* @author Alexey Borzov <borz_off@cs.msu.su>
* @access public
*/
class HTML_QuickForm_html extends HTML_QuickForm_static
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $text raw HTML to add
* @access public
* @return void
*/
function HTML_QuickForm_html($text = null)
{
$this->HTML_QuickForm_static(null, null, $text);
$this->_type = 'html';
}
 
// }}}
// {{{ accept()
 
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @access public
* @return void
*/
function accept(&$renderer)
{
$renderer->renderHtml($this);
} // end func accept
 
// }}}
 
} //end class HTML_QuickForm_header
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer.php
New file
0,0 → 1,150
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Alexey Borzov <borz_off@cs.msu.su> |
// +----------------------------------------------------------------------+
//
// $Id: Renderer.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
/**
* An abstract base class for QuickForm renderers
*
* The class implements a Visitor design pattern
*
* @abstract
* @author Alexey Borzov <borz_off@cs.msu.su>
*/
class HTML_QuickForm_Renderer
{
/**
* Constructor
*
* @access public
*/
function HTML_QuickForm_Renderer()
{
} // end constructor
 
/**
* Called when visiting a form, before processing any form elements
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
* @abstract
*/
function startForm(&$form)
{
return;
} // end func startForm
 
/**
* Called when visiting a form, after processing all form elements
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
* @abstract
*/
function finishForm(&$form)
{
return;
} // end func finishForm
 
/**
* Called when visiting a header element
*
* @param object An HTML_QuickForm_header element being visited
* @access public
* @return void
* @abstract
*/
function renderHeader(&$header)
{
return;
} // end func renderHeader
 
/**
* Called when visiting an element
*
* @param object An HTML_QuickForm_element object being visited
* @param bool Whether an element is required
* @param string An error message associated with an element
* @access public
* @return void
* @abstract
*/
function renderElement(&$element, $required, $error)
{
return;
} // end func renderElement
 
/**
* Called when visiting a hidden element
*
* @param object An HTML_QuickForm_hidden object being visited
* @access public
* @return void
* @abstract
*/
function renderHidden(&$element)
{
return;
} // end func renderHidden
 
/**
* Called when visiting a raw HTML/text pseudo-element
*
* Seems that this should not be used when using a template-based renderer
*
* @param object An HTML_QuickForm_html element being visited
* @access public
* @return void
* @abstract
*/
function renderHtml(&$data)
{
return;
} // end func renderHtml
 
/**
* Called when visiting a group, before processing any group elements
*
* @param object An HTML_QuickForm_group object being visited
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
* @abstract
*/
function startGroup(&$group, $required, $error)
{
return;
} // end func startGroup
 
/**
* Called when visiting a group, after processing all group elements
*
* @param object An HTML_QuickForm_group object being visited
* @access public
* @return void
* @abstract
*/
function finishGroup(&$group)
{
return;
} // end func finishGroup
} // end class HTML_QuickForm_Renderer
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule.php
New file
0,0 → 1,67
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Rule.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
class HTML_QuickForm_Rule
{
/**
* Name of the rule to use in validate method
*
* This property is used in more global rules like Callback and Regex
* to determine which callback and which regex is to be used for validation
*
* @var string
* @access public
*/
var $name;
 
/**
* Validates a value
*
* @access public
* @abstract
*/
function validate($value)
{
return true;
}
 
/**
* Sets the rule name
*
* @access public
*/
function setName($ruleName)
{
$this->name = $ruleName;
}
 
/**
* Returns the javascript test (the test should return true if the value is INVALID)
*
* @param mixed Options for the rule
* @access public
* @return array first element is code to setup validation, second is the check itself
*/
function getValidationScript($options = null)
{
return array('', '');
}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/button.php
New file
0,0 → 1,73
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: button.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a button type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.1
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_button extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $value (optional)Input field value
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_button($elementName=null, $value=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
$this->_persistantFreeze = false;
$this->setValue($value);
$this->setType('button');
} //end constructor
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
} //end class HTML_QuickForm_button
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/date.php
New file
0,0 → 1,484
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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: Alexey Borzov <avb@php.net> |
// | Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: date.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/group.php';
require_once 'HTML/QuickForm/select.php';
 
/**
* Class for a group of elements used to input dates (and times).
*
* Inspired by original 'date' element but reimplemented as a subclass
* of HTML_QuickForm_group
*
* @author Alexey Borzov <avb@php.net>
* @access public
*/
class HTML_QuickForm_date extends HTML_QuickForm_group
{
// {{{ properties
 
/**
* Various options to control the element's display.
*
* Currently known options are
* 'language': date language
* 'format': Format of the date, based on PHP's date() function.
* The following characters are recognised in format string:
* D => Short names of days
* l => Long names of days
* d => Day numbers
* M => Short names of months
* F => Long names of months
* m => Month numbers
* Y => Four digit year
* y => Two digit year
* h => 12 hour format
* H => 23 hour format
* i => Minutes
* s => Seconds
* a => am/pm
* A => AM/PM
* 'minYear': Minimum year in year select
* 'maxYear': Maximum year in year select
* 'addEmptyOption': Should an empty option be added to the top of
* each select box?
* 'emptyOptionValue': The value passed by the empty option.
* 'emptyOptionText': The text displayed for the empty option.
* 'optionIncrement': Step to increase the option values by (works for 'i' and 's')
*
* @access private
* @var array
*/
var $_options = array(
'language' => 'en',
'format' => 'dMY',
'minYear' => 2001,
'maxYear' => 2010,
'addEmptyOption' => false,
'emptyOptionValue' => '',
'emptyOptionText' => '&nbsp;',
'optionIncrement' => array('i' => 1, 's' => 1)
);
 
/**
* These complement separators, they are appended to the resultant HTML
* @access private
* @var array
*/
var $_wrap = array('', '');
 
/**
* Options in different languages
*
* Note to potential translators: to avoid encoding problems please send
* your translations with "weird" letters encoded as HTML Unicode entities
*
* @access private
* @var array
*/
var $_locale = array(
'en' => array (
'weekdays_short'=> array ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'),
'weekdays_long' => array ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
'months_long' => array ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
),
'de' => array (
'weekdays_short'=> array ('So', 'Mon', 'Di', 'Mi', 'Do', 'Fr', 'Sa'),
'weekdays_long' => array ('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'),
'months_short' => array ('Jan', 'Feb', 'M&#xe4;rz', 'April', 'Mai', 'Juni', 'Juli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dez'),
'months_long' => array ('Januar', 'Februar', 'M&#xe4;rz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember')
),
'fr' => array (
'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'),
'weekdays_long' => array ('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'),
'months_short' => array ('Jan', 'F&#xe9;v', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Ao&#xfb;t', 'Sep', 'Oct', 'Nov', 'D&#xe9;c'),
'months_long' => array ('Janvier', 'F&#xe9;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao&#xfb;t', 'Septembre', 'Octobre', 'Novembre', 'D&#xe9;cembre')
),
'hu' => array (
'weekdays_short'=> array ('V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'),
'weekdays_long' => array ('vas&#xe1;rnap', 'h&#xe9;tf&#x151;', 'kedd', 'szerda', 'cs&#xfc;t&#xf6;rt&#xf6;k', 'p&#xe9;ntek', 'szombat'),
'months_short' => array ('jan', 'feb', 'm&#xe1;rc', '&#xe1;pr', 'm&#xe1;j', 'j&#xfa;n', 'j&#xfa;l', 'aug', 'szept', 'okt', 'nov', 'dec'),
'months_long' => array ('janu&#xe1;r', 'febru&#xe1;r', 'm&#xe1;rcius', '&#xe1;prilis', 'm&#xe1;jus', 'j&#xfa;nius', 'j&#xfa;lius', 'augusztus', 'szeptember', 'okt&#xf3;ber', 'november', 'december')
),
'pl' => array (
'weekdays_short'=> array ('Nie', 'Pn', 'Wt', '&#x15a;r', 'Czw', 'Pt', 'Sob'),
'weekdays_long' => array ('Niedziela', 'Poniedzia&#x142;ek', 'Wtorek', '&#x15a;roda', 'Czwartek', 'Pi&#x105;tek', 'Sobota'),
'months_short' => array ('Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Pa&#x17a;', 'Lis', 'Gru'),
'months_long' => array ('Stycze&#x144;', 'Luty', 'Marzec', 'Kwiecie&#x144;', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpie&#x144;', 'Wrzesie&#x144;', 'Pa&#x17a;dziernik', 'Listopad', 'Grudzie&#x144;')
),
'sl' => array (
'weekdays_short'=> array ('Ned', 'Pon', 'Tor', 'Sre', 'Cet', 'Pet', 'Sob'),
'weekdays_long' => array ('Nedelja', 'Ponedeljek', 'Torek', 'Sreda', 'Cetrtek', 'Petek', 'Sobota'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Januar', 'Februar', 'Marec', 'April', 'Maj', 'Junij', 'Julij', 'Avgust', 'September', 'Oktober', 'November', 'December')
),
'ru' => array (
'weekdays_short'=> array ('&#x412;&#x441;', '&#x41f;&#x43d;', '&#x412;&#x442;', '&#x421;&#x440;', '&#x427;&#x442;', '&#x41f;&#x442;', '&#x421;&#x431;'),
'weekdays_long' => array ('&#x412;&#x43e;&#x441;&#x43a;&#x440;&#x435;&#x441;&#x435;&#x43d;&#x44c;&#x435;', '&#x41f;&#x43e;&#x43d;&#x435;&#x434;&#x435;&#x43b;&#x44c;&#x43d;&#x438;&#x43a;', '&#x412;&#x442;&#x43e;&#x440;&#x43d;&#x438;&#x43a;', '&#x421;&#x440;&#x435;&#x434;&#x430;', '&#x427;&#x435;&#x442;&#x432;&#x435;&#x440;&#x433;', '&#x41f;&#x44f;&#x442;&#x43d;&#x438;&#x446;&#x430;', '&#x421;&#x443;&#x431;&#x431;&#x43e;&#x442;&#x430;'),
'months_short' => array ('&#x42f;&#x43d;&#x432;', '&#x424;&#x435;&#x432;', '&#x41c;&#x430;&#x440;', '&#x410;&#x43f;&#x440;', '&#x41c;&#x430;&#x439;', '&#x418;&#x44e;&#x43d;', '&#x418;&#x44e;&#x43b;', '&#x410;&#x432;&#x433;', '&#x421;&#x435;&#x43d;', '&#x41e;&#x43a;&#x442;', '&#x41d;&#x43e;&#x44f;', '&#x414;&#x435;&#x43a;'),
'months_long' => array ('&#x42f;&#x43d;&#x432;&#x430;&#x440;&#x44c;', '&#x424;&#x435;&#x432;&#x440;&#x430;&#x43b;&#x44c;', '&#x41c;&#x430;&#x440;&#x442;', '&#x410;&#x43f;&#x440;&#x435;&#x43b;&#x44c;', '&#x41c;&#x430;&#x439;', '&#x418;&#x44e;&#x43d;&#x44c;', '&#x418;&#x44e;&#x43b;&#x44c;', '&#x410;&#x432;&#x433;&#x443;&#x441;&#x442;', '&#x421;&#x435;&#x43d;&#x442;&#x44f;&#x431;&#x440;&#x44c;', '&#x41e;&#x43a;&#x442;&#x44f;&#x431;&#x440;&#x44c;', '&#x41d;&#x43e;&#x44f;&#x431;&#x440;&#x44c;', '&#x414;&#x435;&#x43a;&#x430;&#x431;&#x440;&#x44c;')
),
'es' => array (
'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mi&#xe9;', 'Jue', 'Vie', 'S&#xe1;b'),
'weekdays_long' => array ('Domingo', 'Lunes', 'Martes', 'Mi&#xe9;rcoles', 'Jueves', 'Viernes', 'S&#xe1;bado'),
'months_short' => array ('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'),
'months_long' => array ('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre')
),
'da' => array (
'weekdays_short'=> array ('S&#xf8;n', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#xf8;r'),
'weekdays_long' => array ('S&#xf8;ndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf8;rdag'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December')
),
'is' => array (
'weekdays_short'=> array ('Sun', 'M&#xe1;n', '&#xde;ri', 'Mi&#xf0;', 'Fim', 'F&#xf6;s', 'Lau'),
'weekdays_long' => array ('Sunnudagur', 'M&#xe1;nudagur', '&#xde;ri&#xf0;judagur', 'Mi&#xf0;vikudagur', 'Fimmtudagur', 'F&#xf6;studagur', 'Laugardagur'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Ma&#xed;', 'J&#xfa;n', 'J&#xfa;l', '&#xc1;g&#xfa;', 'Sep', 'Okt', 'N&#xf3;v', 'Des'),
'months_long' => array ('Jan&#xfa;ar', 'Febr&#xfa;ar', 'Mars', 'Apr&#xed;l', 'Ma&#xed;', 'J&#xfa;n&#xed;', 'J&#xfa;l&#xed;', '&#xc1;g&#xfa;st', 'September', 'Okt&#xf3;ber', 'N&#xf3;vember', 'Desember')
),
'it' => array (
'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'),
'weekdays_long' => array ('Domenica', 'Luned&#xec;', 'Marted&#xec;', 'Mercoled&#xec;', 'Gioved&#xec;', 'Venerd&#xec;', 'Sabato'),
'months_short' => array ('Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'),
'months_long' => array ('Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre')
),
'sk' => array (
'weekdays_short'=> array ('Ned', 'Pon', 'Uto', 'Str', '&#x8a;tv', 'Pia', 'Sob'),
'weekdays_long' => array ('Nede&#x17e;a', 'Pondelok', 'Utorok', 'Streda', '&#x8a;tvrtok', 'Piatok', 'Sobota'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'M&#xe1;j', 'J&#xfa;n', 'J&#xfa;l', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Janu&#xe1;r', 'Febru&#xe1;r', 'Marec', 'Apr&#xed;l', 'M&#xe1;j', 'J&#xfa;n', 'J&#xfa;l', 'August', 'September', 'Okt&#xf3;ber', 'November', 'December')
),
'cs' => array (
'weekdays_short'=> array ('Ne', 'Po', '&#xda;t', 'St', '&#x10c;t', 'P&#xe1;', 'So'),
'weekdays_long' => array ('Ned&#x11b;le', 'Pond&#x11b;l&#xed;', '&#xda;ter&#xfd;', 'St&#x159;eda', '&#x10c;tvrtek', 'P&#xe1;tek', 'Sobota'),
'months_short' => array ('Led', '&#xda;no', 'B&#x159;e', 'Dub', 'Kv&#x11b;', '&#x10c;en', '&#x10c;ec', 'Srp', 'Z&#xe1;&#x159;', '&#x158;&#xed;j', 'Lis', 'Pro'),
'months_long' => array ('Leden', '&#xda;nor', 'B&#x159;ezen', 'Duben', 'Kv&#x11b;ten', '&#x10c;erven', '&#x10c;ervenec', 'Srpen', 'Z&#xe1;&#x159;&#xed;', '&#x158;&#xed;jen', 'Listopad', 'Prosinec')
),
'hy' => array (
'weekdays_short'=> array ('&#x53f;&#x580;&#x56f;', '&#x535;&#x580;&#x56f;', '&#x535;&#x580;&#x584;', '&#x549;&#x580;&#x584;', '&#x540;&#x576;&#x563;', '&#x548;&#x582;&#x580;', '&#x547;&#x562;&#x569;'),
'weekdays_long' => array ('&#x53f;&#x56b;&#x580;&#x561;&#x56f;&#x56b;', '&#x535;&#x580;&#x56f;&#x578;&#x582;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x535;&#x580;&#x565;&#x584;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x549;&#x578;&#x580;&#x565;&#x584;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x540;&#x56b;&#x576;&#x563;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x548;&#x582;&#x580;&#x562;&#x561;&#x569;', '&#x547;&#x561;&#x562;&#x561;&#x569;'),
'months_short' => array ('&#x540;&#x576;&#x57e;', '&#x553;&#x57f;&#x580;', '&#x544;&#x580;&#x57f;', '&#x531;&#x57a;&#x580;', '&#x544;&#x575;&#x57d;', '&#x540;&#x576;&#x57d;', '&#x540;&#x56c;&#x57d;', '&#x555;&#x563;&#x57d;', '&#x54d;&#x57a;&#x57f;', '&#x540;&#x56f;&#x57f;', '&#x546;&#x575;&#x574;', '&#x534;&#x56f;&#x57f;'),
'months_long' => array ('&#x540;&#x578;&#x582;&#x576;&#x57e;&#x561;&#x580;', '&#x553;&#x565;&#x57f;&#x580;&#x57e;&#x561;&#x580;', '&#x544;&#x561;&#x580;&#x57f;', '&#x531;&#x57a;&#x580;&#x56b;&#x56c;', '&#x544;&#x561;&#x575;&#x56b;&#x57d;', '&#x540;&#x578;&#x582;&#x576;&#x56b;&#x57d;', '&#x540;&#x578;&#x582;&#x56c;&#x56b;&#x57d;', '&#x555;&#x563;&#x578;&#x57d;&#x57f;&#x578;&#x57d;', '&#x54d;&#x565;&#x57a;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x540;&#x578;&#x56f;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x546;&#x578;&#x575;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x534;&#x565;&#x56f;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;')
),
'nl' => array (
'weekdays_short'=> array ('Zo', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za'),
'weekdays_long' => array ('Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December')
),
'et' => array (
'weekdays_short'=> array ('P', 'E', 'T', 'K', 'N', 'R', 'L'),
'weekdays_long' => array ('P&#xfc;hap&#xe4;ev', 'Esmasp&#xe4;ev', 'Teisip&#xe4;ev', 'Kolmap&#xe4;ev', 'Neljap&#xe4;ev', 'Reede', 'Laup&#xe4;ev'),
'months_short' => array ('Jaan', 'Veebr', 'M&#xe4;rts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'),
'months_long' => array ('Jaanuar', 'Veebruar', 'M&#xe4;rts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'August', 'September', 'Oktoober', 'November', 'Detsember')
),
'tr' => array (
'weekdays_short'=> array ('Paz', 'Pzt', 'Sal', '&#xc7;ar', 'Per', 'Cum', 'Cts'),
'weekdays_long' => array ('Pazar', 'Pazartesi', 'Sal&#x131;', '&#xc7;ar&#x15f;amba', 'Per&#x15f;embe', 'Cuma', 'Cumartesi'),
'months_short' => array ('Ock', '&#x15e;bt', 'Mrt', 'Nsn', 'Mys', 'Hzrn', 'Tmmz', 'A&#x11f;st', 'Eyl', 'Ekm', 'Ksm', 'Arlk'),
'months_long' => array ('Ocak', '&#x15e;ubat', 'Mart', 'Nisan', 'May&#x131;s', 'Haziran', 'Temmuz', 'A&#x11f;ustos', 'Eyl&#xfc;l', 'Ekim', 'Kas&#x131;m', 'Aral&#x131;k')
),
'no' => array (
'weekdays_short'=> array ('S&#xf8;n', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#xf8;r'),
'weekdays_long' => array ('S&#xf8;ndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf8;rdag'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'),
'months_long' => array ('Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember')
),
'eo' => array (
'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', '&#x134;a&#x16D;', 'Ven', 'Sab'),
'weekdays_long' => array ('Diman&#x109;o', 'Lundo', 'Mardo', 'Merkredo', '&#x134;a&#x16D;do', 'Vendredo', 'Sabato'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'A&#x16D;g', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Januaro', 'Februaro', 'Marto', 'Aprilo', 'Majo', 'Junio', 'Julio', 'A&#x16D;gusto', 'Septembro', 'Oktobro', 'Novembro', 'Decembro')
),
'ua' => array (
'weekdays_short'=> array('&#x41d;&#x434;&#x43b;', '&#x41f;&#x43d;&#x434;', '&#x412;&#x442;&#x440;', '&#x421;&#x440;&#x434;', '&#x427;&#x442;&#x432;', '&#x41f;&#x442;&#x43d;', '&#x421;&#x431;&#x442;'),
'weekdays_long' => array('&#x41d;&#x435;&#x434;&#x456;&#x43b;&#x44f;', '&#x41f;&#x43e;&#x43d;&#x435;&#x434;&#x456;&#x43b;&#x43e;&#x43a;', '&#x412;&#x456;&#x432;&#x442;&#x43e;&#x440;&#x43e;&#x43a;', '&#x421;&#x435;&#x440;&#x435;&#x434;&#x430;', '&#x427;&#x435;&#x442;&#x432;&#x435;&#x440;', '&#x41f;\'&#x44f;&#x442;&#x43d;&#x438;&#x446;&#x44f;', '&#x421;&#x443;&#x431;&#x43e;&#x442;&#x430;'),
'months_short' => array('&#x421;&#x456;&#x447;', '&#x41b;&#x44e;&#x442;', '&#x411;&#x435;&#x440;', '&#x41a;&#x432;&#x456;', '&#x422;&#x440;&#x430;', '&#x427;&#x435;&#x440;', '&#x41b;&#x438;&#x43f;', '&#x421;&#x435;&#x440;', '&#x412;&#x435;&#x440;', '&#x416;&#x43e;&#x432;', '&#x41b;&#x438;&#x441;', '&#x413;&#x440;&#x443;'),
'months_long' => array('&#x421;&#x456;&#x447;&#x435;&#x43d;&#x44c;', '&#x41b;&#x44e;&#x442;&#x438;&#x439;', '&#x411;&#x435;&#x440;&#x435;&#x437;&#x435;&#x43d;&#x44c;', '&#x41a;&#x432;&#x456;&#x442;&#x435;&#x43d;&#x44c;', '&#x422;&#x440;&#x430;&#x432;&#x435;&#x43d;&#x44c;', '&#x427;&#x435;&#x440;&#x432;&#x435;&#x43d;&#x44c;', '&#x41b;&#x438;&#x43f;&#x435;&#x43d;&#x44c;', '&#x421;&#x435;&#x440;&#x43f;&#x435;&#x43d;&#x44c;', '&#x412;&#x435;&#x440;&#x435;&#x441;&#x435;&#x43d;&#x44c;', '&#x416;&#x43e;&#x432;&#x442;&#x435;&#x43d;&#x44c;', '&#x41b;&#x438;&#x441;&#x442;&#x43e;&#x43f;&#x430;&#x434;', '&#x413;&#x440;&#x443;&#x434;&#x435;&#x43d;&#x44c;')
),
'ro' => array (
'weekdays_short'=> array ('Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam'),
'weekdays_long' => array ('Duminica', 'Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sambata'),
'months_short' => array ('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
'months_long' => array ('Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie')
),
'he' => array (
'weekdays_short'=> array ('&#1512;&#1488;&#1513;&#1493;&#1503;', '&#1513;&#1504;&#1497;', '&#1513;&#1500;&#1497;&#1513;&#1497;', '&#1512;&#1489;&#1497;&#1506;&#1497;', '&#1495;&#1502;&#1497;&#1513;&#1497;', '&#1513;&#1497;&#1513;&#1497;', '&#1513;&#1489;&#1514;'),
'weekdays_long' => array ('&#1497;&#1493;&#1501; &#1512;&#1488;&#1513;&#1493;&#1503;', '&#1497;&#1493;&#1501; &#1513;&#1504;&#1497;', '&#1497;&#1493;&#1501; &#1513;&#1500;&#1497;&#1513;&#1497;', '&#1497;&#1493;&#1501; &#1512;&#1489;&#1497;&#1506;&#1497;', '&#1497;&#1493;&#1501; &#1495;&#1502;&#1497;&#1513;&#1497;', '&#1497;&#1493;&#1501; &#1513;&#1497;&#1513;&#1497;', '&#1513;&#1489;&#1514;'),
'months_short' => array ('&#1497;&#1504;&#1493;&#1488;&#1512;', '&#1508;&#1489;&#1512;&#1493;&#1488;&#1512;', '&#1502;&#1512;&#1509;', '&#1488;&#1508;&#1512;&#1497;&#1500;', '&#1502;&#1488;&#1497;', '&#1497;&#1493;&#1504;&#1497;', '&#1497;&#1493;&#1500;&#1497;', '&#1488;&#1493;&#1490;&#1493;&#1505;&#1496;', '&#1505;&#1508;&#1496;&#1502;&#1489;&#1512;', '&#1488;&#1493;&#1511;&#1496;&#1493;&#1489;&#1512;', '&#1504;&#1493;&#1489;&#1502;&#1489;&#1512;', '&#1491;&#1510;&#1502;&#1489;&#1512;'),
'months_long' => array ('&#1497;&#1504;&#1493;&#1488;&#1512;', '&#1508;&#1489;&#1512;&#1493;&#1488;&#1512;', '&#1502;&#1512;&#1509;', '&#1488;&#1508;&#1512;&#1497;&#1500;', '&#1502;&#1488;&#1497;', '&#1497;&#1493;&#1504;&#1497;', '&#1497;&#1493;&#1500;&#1497;', '&#1488;&#1493;&#1490;&#1493;&#1505;&#1496;', '&#1505;&#1508;&#1496;&#1502;&#1489;&#1512;', '&#1488;&#1493;&#1511;&#1496;&#1493;&#1489;&#1512;', '&#1504;&#1493;&#1489;&#1502;&#1489;&#1512;', '&#1491;&#1510;&#1502;&#1489;&#1512;')
),
'sv' => array (
'weekdays_short'=> array ('S&#xf6;n', 'M&#xe5;n', 'Tis', 'Ons', 'Tor', 'Fre', 'L&#xf6;r'),
'weekdays_long' => array ('S&#xf6;ndag', 'M&#xe5;ndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf6;rdag'),
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
'months_long' => array ('Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December')
),
'pt' => array (
'weekdays_short'=> array ('Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'S&aacute;b'),
'weekdays_long' => array ('Domingo', 'Segunda-feira', 'Ter&ccedil;a-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'S&aacute;bado'),
'months_short' => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'),
'months_long' => array ('Janeiro', 'Fevereiro', 'Mar&ccedil;o', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro')
)
);
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @access public
* @param string Element's name
* @param mixed Label(s) for an element
* @param array Options to control the element's display
* @param mixed Either a typical HTML attribute string or an associative array
*/
function HTML_QuickForm_date($elementName = null, $elementLabel = null, $options = array(), $attributes = null)
{
$this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_appendName = true;
$this->_type = 'date';
// set the options, do not bother setting bogus ones
if (is_array($options)) {
foreach ($options as $name => $value) {
if ('language' == $name) {
$this->_options['language'] = isset($this->_locale[$value])? $value: 'en';
} elseif (isset($this->_options[$name])) {
if (is_array($value)) {
$this->_options[$name] = @array_merge($this->_options[$name], $value);
} else {
$this->_options[$name] = $value;
}
}
}
}
}
 
// }}}
// {{{ _createElements()
 
function _createElements()
{
$this->_separator = $this->_elements = array();
$separator = '';
$locale =& $this->_locale[$this->_options['language']];
$backslash = false;
for ($i = 0, $length = strlen($this->_options['format']); $i < $length; $i++) {
$sign = $this->_options['format']{$i};
if ($backslash) {
$backslash = false;
$separator .= $sign;
} else {
$loadSelect = true;
switch ($sign) {
case 'D':
// Sunday is 0 like with 'w' in date()
$options = $locale['weekdays_short'];
break;
case 'l':
$options = $locale['weekdays_long'];
break;
case 'd':
$options = $this->_createOptionList(1, 31);
break;
case 'M':
$options = $locale['months_short'];
array_unshift($options , '');
unset($options[0]);
break;
case 'm':
$options = $this->_createOptionList(1, 12);
break;
case 'F':
$options = $locale['months_long'];
array_unshift($options , '');
unset($options[0]);
break;
case 'Y':
$options = $this->_createOptionList(
$this->_options['minYear'],
$this->_options['maxYear'],
$this->_options['minYear'] > $this->_options['maxYear']? -1: 1
);
break;
case 'y':
$options = $this->_createOptionList(
$this->_options['minYear'],
$this->_options['maxYear'],
$this->_options['minYear'] > $this->_options['maxYear']? -1: 1
);
array_walk($options, create_function('&$v,$k','$v = substr($v,-2);'));
break;
case 'h':
$options = $this->_createOptionList(1, 12);
break;
case 'g':
$options = $this->_createOptionList(1, 12);
array_walk($options, create_function('&$v,$k', '$v = intval($v);'));
break;
case 'H':
$options = $this->_createOptionList(0, 23);
break;
case 'i':
$options = $this->_createOptionList(0, 59, $this->_options['optionIncrement']['i']);
break;
case 's':
$options = $this->_createOptionList(0, 59, $this->_options['optionIncrement']['s']);
break;
case 'a':
$options = array('am' => 'am', 'pm' => 'pm');
break;
case 'A':
$options = array('AM' => 'AM', 'PM' => 'PM');
break;
case 'W':
$options = $this->_createOptionList(1, 53);
break;
case '\\':
$backslash = true;
$loadSelect = false;
break;
default:
$separator .= (' ' == $sign? '&nbsp;': $sign);
$loadSelect = false;
}
if ($loadSelect) {
if (0 < count($this->_elements)) {
$this->_separator[] = $separator;
} else {
$this->_wrap[0] = $separator;
}
$separator = '';
// Should we add an empty option to the top of the select?
if (!is_array($this->_options['addEmptyOption']) && $this->_options['addEmptyOption'] ||
is_array($this->_options['addEmptyOption']) && !empty($this->_options['addEmptyOption'][$sign])) {
 
// Using '+' array operator to preserve the keys
if (is_array($this->_options['emptyOptionText']) && !empty($this->_options['emptyOptionText'][$sign])) {
$options = array($this->_options['emptyOptionValue'] => $this->_options['emptyOptionText'][$sign]) + $options;
} else {
$options = array($this->_options['emptyOptionValue'] => $this->_options['emptyOptionText']) + $options;
}
}
$this->_elements[] =& new HTML_QuickForm_select($sign, null, $options, $this->getAttributes());
}
}
}
$this->_wrap[1] = $separator . ($backslash? '\\': '');
}
 
// }}}
// {{{ _createOptionList()
 
/**
* Creates an option list containing the numbers from the start number to the end, inclusive
*
* @param int The start number
* @param int The end number
* @param int Increment by this value
* @access private
* @return array An array of numeric options.
*/
function _createOptionList($start, $end, $step = 1)
{
for ($i = $start, $options = array(); $start > $end? $i >= $end: $i <= $end; $i += $step) {
$options[$i] = sprintf('%02d', $i);
}
return $options;
}
 
// }}}
// {{{ setValue()
 
function setValue($value)
{
if (empty($value)) {
$value = array();
} elseif (is_scalar($value)) {
if (!is_numeric($value)) {
$value = strtotime($value);
}
// might be a unix epoch, then we fill all possible values
$arr = explode('-', date('w-d-n-Y-h-H-i-s-a-A-W', (int)$value));
$value = array(
'D' => $arr[0],
'l' => $arr[0],
'd' => $arr[1],
'M' => $arr[2],
'm' => $arr[2],
'F' => $arr[2],
'Y' => $arr[3],
'y' => $arr[3],
'h' => $arr[4],
'g' => $arr[4],
'H' => $arr[5],
'i' => $arr[6],
's' => $arr[7],
'a' => $arr[8],
'A' => $arr[9],
'W' => $arr[10]
);
}
parent::setValue($value);
}
 
// }}}
// {{{ toHtml()
 
function toHtml()
{
include_once('HTML/QuickForm/Renderer/Default.php');
$renderer =& new HTML_QuickForm_Renderer_Default();
$renderer->setElementTemplate('{element}');
parent::accept($renderer);
return $this->_wrap[0] . $renderer->toHtml() . $this->_wrap[1];
}
 
// }}}
// {{{ accept()
 
function accept(&$renderer, $required = false, $error = null)
{
$renderer->renderElement($this, $required, $error);
}
 
// }}}
// {{{ onQuickFormEvent()
 
function onQuickFormEvent($event, $arg, &$caller)
{
if ('updateValue' == $event) {
// we need to call setValue(), 'cause the default/constant value
// may be in fact a timestamp, not an array
return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller);
} else {
return parent::onQuickFormEvent($event, $arg, $caller);
}
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/textarea.php
New file
0,0 → 1,222
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: textarea.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/element.php");
 
/**
* HTML class for a textarea type field
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_textarea extends HTML_QuickForm_element
{
// {{{ properties
 
/**
* Field value
* @var string
* @since 1.0
* @access private
*/
var $_value = null;
 
// }}}
// {{{ constructor
/**
* Class constructor
*
* @param string Input field name attribute
* @param mixed Label(s) for a field
* @param mixed Either a typical HTML attribute string or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_textarea($elementName=null, $elementLabel=null, $attributes=null)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_type = 'textarea';
} //end constructor
// }}}
// {{{ setName()
 
/**
* Sets the input field name
*
* @param string $name Input field name attribute
* @since 1.0
* @access public
* @return void
*/
function setName($name)
{
$this->updateAttributes(array('name'=>$name));
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @since 1.0
* @access public
* @return string
*/
function getName()
{
return $this->getAttribute('name');
} //end func getName
 
// }}}
// {{{ setValue()
 
/**
* Sets value for textarea element
*
* @param string $value Value for textarea element
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
$this->_value = $value;
} //end func setValue
// }}}
// {{{ getValue()
 
/**
* Returns the value of the form element
*
* @since 1.0
* @access public
* @return string
*/
function getValue()
{
return $this->_value;
} // end func getValue
 
// }}}
// {{{ setWrap()
 
/**
* Sets wrap type for textarea element
*
* @param string $wrap Wrap type
* @since 1.0
* @access public
* @return void
*/
function setWrap($wrap)
{
$this->updateAttributes(array('wrap' => $wrap));
} //end func setWrap
// }}}
// {{{ setRows()
 
/**
* Sets height in rows for textarea element
*
* @param string $rows Height expressed in rows
* @since 1.0
* @access public
* @return void
*/
function setRows($rows)
{
$this->updateAttributes(array('rows' => $rows));
} //end func setRows
 
// }}}
// {{{ setCols()
 
/**
* Sets width in cols for textarea element
*
* @param string $cols Width expressed in cols
* @since 1.0
* @access public
* @return void
*/
function setCols($cols)
{
$this->updateAttributes(array('cols' => $cols));
} //end func setCols
 
// }}}
// {{{ toHtml()
 
/**
* Returns the textarea element in HTML
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
if ($this->_flagFrozen) {
return $this->getFrozenHtml();
} else {
return $this->_getTabs() .
'<textarea' . $this->_getAttrString($this->_attributes) . '>' .
// because we wrap the form later we don't want the text indented
preg_replace("/(\r\n|\n|\r)/", '&#010;', htmlspecialchars($this->_value)) .
'</textarea>';
}
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags (in this case, value is changed to a mask)
*
* @since 1.0
* @access public
* @return string
*/
function getFrozenHtml()
{
$value = htmlspecialchars($this->getValue());
if ($this->getAttribute('wrap') == 'off') {
$html = $this->_getTabs() . '<pre>' . $value."</pre>\n";
} else {
$html = nl2br($value)."\n";
}
return $html . $this->_getPersistantData();
} //end func getFrozenHtml
 
// }}}
 
} //end class HTML_QuickForm_textarea
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/file.php
New file
0,0 → 1,346
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: file.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
// register file-related rules
if (class_exists('HTML_QuickForm')) {
HTML_QuickForm::registerRule('uploadedfile', 'callback', '_ruleIsUploadedFile', 'HTML_QuickForm_file');
HTML_QuickForm::registerRule('maxfilesize', 'callback', '_ruleCheckMaxFileSize', 'HTML_QuickForm_file');
HTML_QuickForm::registerRule('mimetype', 'callback', '_ruleCheckMimeType', 'HTML_QuickForm_file');
HTML_QuickForm::registerRule('filename', 'callback', '_ruleCheckFileName', 'HTML_QuickForm_file');
}
 
/**
* HTML class for a file type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_file extends HTML_QuickForm_input
{
// {{{ properties
 
/**
* Uploaded file data, from $_FILES
* @var array
*/
var $_value = null;
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string Input field name attribute
* @param string Input field label
* @param mixed (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
*/
function HTML_QuickForm_file($elementName=null, $elementLabel=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
$this->setType('file');
} //end constructor
// }}}
// {{{ setSize()
 
/**
* Sets size of file element
*
* @param int Size of file element
* @since 1.0
* @access public
*/
function setSize($size)
{
$this->updateAttributes(array('size' => $size));
} //end func setSize
// }}}
// {{{ getSize()
 
/**
* Returns size of file element
*
* @since 1.0
* @access public
* @return int
*/
function getSize()
{
return $this->getAttribute('size');
} //end func getSize
 
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return bool
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
// {{{ setValue()
 
/**
* Sets value for file element.
*
* Actually this does nothing. The function is defined here to override
* HTML_Quickform_input's behaviour of setting the 'value' attribute. As
* no sane user-agent uses <input type="file">'s value for anything
* (because of security implications) we implement file's value as a
* read-only property with a special meaning.
*
* @param mixed Value for file element
* @since 3.0
* @access public
*/
function setValue($value)
{
return null;
} //end func setValue
// }}}
// {{{ getValue()
 
/**
* Returns information about the uploaded file
*
* @since 3.0
* @access public
* @return array
*/
function getValue()
{
return $this->_value;
} // end func getValue
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string Name of event
* @param mixed event arguments
* @param object calling object
* @since 1.0
* @access public
* @return bool
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
if ($caller->getAttribute('method') == 'get') {
return PEAR::raiseError('Cannot add a file upload field to a GET method form');
}
$this->_value = $this->_findValue();
$caller->updateAttributes(array('enctype' => 'multipart/form-data'));
$caller->setMaxFileSize();
break;
case 'addElement':
$this->onQuickFormEvent('createElement', $arg, $caller);
return $this->onQuickFormEvent('updateValue', null, $caller);
break;
case 'createElement':
$className = get_class($this);
$this->$className($arg[0], $arg[1], $arg[2]);
break;
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ moveUploadedFile()
 
/**
* Moves an uploaded file into the destination
*
* @param string Destination directory path
* @param string New file name
* @access public
*/
function moveUploadedFile($dest, $fileName = '')
{
if ($dest != '' && substr($dest, -1) != '/') {
$dest .= '/';
}
$fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
if (move_uploaded_file($this->_value['tmp_name'], $dest . $fileName)) {
return true;
} else {
return false;
}
} // end func moveUploadedFile
// }}}
// {{{ isUploadedFile()
 
/**
* Checks if the element contains an uploaded file
*
* @access public
* @return bool true if file has been uploaded, false otherwise
*/
function isUploadedFile()
{
return $this->_ruleIsUploadedFile($this->_value);
} // end func isUploadedFile
 
// }}}
// {{{ _ruleIsUploadedFile()
 
/**
* Checks if the given element contains an uploaded file
*
* @param array Uploaded file info (from $_FILES)
* @access private
* @return bool true if file has been uploaded, false otherwise
*/
function _ruleIsUploadedFile($elementValue)
{
if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
(!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
return is_uploaded_file($elementValue['tmp_name']);
} else {
return false;
}
} // end func _ruleIsUploadedFile
// }}}
// {{{ _ruleCheckMaxFileSize()
 
/**
* Checks that the file does not exceed the max file size
*
* @param array Uploaded file info (from $_FILES)
* @param int Max file size
* @access private
* @return bool true if filesize is lower than maxsize, false otherwise
*/
function _ruleCheckMaxFileSize($elementValue, $maxSize)
{
if (!empty($elementValue['error']) &&
(UPLOAD_ERR_FORM_SIZE == $elementValue['error'] || UPLOAD_ERR_INI_SIZE == $elementValue['error'])) {
return false;
}
if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
return true;
}
return ($maxSize >= @filesize($elementValue['tmp_name']));
} // end func _ruleCheckMaxFileSize
 
// }}}
// {{{ _ruleCheckMimeType()
 
/**
* Checks if the given element contains an uploaded file of the right mime type
*
* @param array Uploaded file info (from $_FILES)
* @param mixed Mime Type (can be an array of allowed types)
* @access private
* @return bool true if mimetype is correct, false otherwise
*/
function _ruleCheckMimeType($elementValue, $mimeType)
{
if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
return true;
}
if (is_array($mimeType)) {
return in_array($elementValue['type'], $mimeType);
}
return $elementValue['type'] == $mimeType;
} // end func _ruleCheckMimeType
 
// }}}
// {{{ _ruleCheckFileName()
 
/**
* Checks if the given element contains an uploaded file of the filename regex
*
* @param array Uploaded file info (from $_FILES)
* @param string Regular expression
* @access private
* @return bool true if name matches regex, false otherwise
*/
function _ruleCheckFileName($elementValue, $regex)
{
if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
return true;
}
return preg_match($regex, $elementValue['name']);
} // end func _ruleCheckFileName
// }}}
// {{{ _findValue()
 
/**
* Tries to find the element value from the values array
*
* Needs to be redefined here as $_FILES is populated differently from
* other arrays when element name is of the form foo[bar]
*
* @access private
* @return mixed
*/
function _findValue()
{
if (empty($_FILES)) {
return null;
}
$elementName = $this->getName();
if (isset($_FILES[$elementName])) {
return $_FILES[$elementName];
} elseif (false !== ($pos = strpos($elementName, '['))) {
$base = substr($elementName, 0, $pos);
$idx = "['" . str_replace(array(']', '['), array('', "']['"), substr($elementName, $pos + 1, -1)) . "']";
$props = array('name', 'type', 'size', 'tmp_name', 'error');
$code = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
" return null;\n" .
"} else {\n" .
" \$value = array();\n";
foreach ($props as $prop) {
$code .= " \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
}
return eval($code . " return \$value;\n}\n");
} else {
return null;
}
}
 
// }}}
} // end class HTML_QuickForm_file
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/select.php
New file
0,0 → 1,604
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: select.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/element.php');
 
/**
* Class to dynamically create an HTML SELECT
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_select extends HTML_QuickForm_element {
// {{{ properties
 
/**
* Contains the select options
*
* @var array
* @since 1.0
* @access private
*/
var $_options = array();
/**
* Default values of the SELECT
*
* @var string
* @since 1.0
* @access private
*/
var $_values = null;
 
// }}}
// {{{ constructor
/**
* Class constructor
*
* @param string Select name attribute
* @param mixed Label(s) for the select
* @param mixed Data to be used to populate options
* @param mixed Either a typical HTML attribute string or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_select($elementName=null, $elementLabel=null, $options=null, $attributes=null)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_type = 'select';
if (isset($options)) {
$this->load($options);
}
} //end constructor
// }}}
// {{{ apiVersion()
 
/**
* Returns the current API version
*
* @since 1.0
* @access public
* @return double
*/
function apiVersion()
{
return 2.3;
} //end func apiVersion
 
// }}}
// {{{ setSelected()
 
/**
* Sets the default values of the select box
*
* @param mixed $values Array or comma delimited string of selected values
* @since 1.0
* @access public
* @return void
*/
function setSelected($values)
{
if (is_string($values) && $this->getMultiple()) {
$values = split("[ ]?,[ ]?", $values);
}
if (is_array($values)) {
$this->_values = array_values($values);
} else {
$this->_values = array($values);
}
} //end func setSelected
// }}}
// {{{ getSelected()
 
/**
* Returns an array of the selected values
*
* @since 1.0
* @access public
* @return array of selected values
*/
function getSelected()
{
return $this->_values;
} // end func getSelected
 
// }}}
// {{{ setName()
 
/**
* Sets the input field name
*
* @param string $name Input field name attribute
* @since 1.0
* @access public
* @return void
*/
function setName($name)
{
$this->updateAttributes(array('name' => $name));
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @since 1.0
* @access public
* @return string
*/
function getName()
{
return $this->getAttribute('name');
} //end func getName
 
// }}}
// {{{ getPrivateName()
 
/**
* Returns the element name (possibly with brackets appended)
*
* @since 1.0
* @access public
* @return string
*/
function getPrivateName()
{
if ($this->getAttribute('multiple')) {
return $this->getName() . '[]';
} else {
return $this->getName();
}
} //end func getPrivateName
 
// }}}
// {{{ setValue()
 
/**
* Sets the value of the form element
*
* @param mixed $values Array or comma delimited string of selected values
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
$this->setSelected($value);
} // end func setValue
 
// }}}
// {{{ getValue()
 
/**
* Returns an array of the selected values
*
* @since 1.0
* @access public
* @return array of selected values
*/
function getValue()
{
return $this->_values;
} // end func getValue
 
// }}}
// {{{ setSize()
 
/**
* Sets the select field size, only applies to 'multiple' selects
*
* @param int $size Size of select field
* @since 1.0
* @access public
* @return void
*/
function setSize($size)
{
$this->updateAttributes(array('size' => $size));
} //end func setSize
// }}}
// {{{ getSize()
 
/**
* Returns the select field size
*
* @since 1.0
* @access public
* @return int
*/
function getSize()
{
return $this->getAttribute('size');
} //end func getSize
 
// }}}
// {{{ setMultiple()
 
/**
* Sets the select mutiple attribute
*
* @param bool $multiple Whether the select supports multi-selections
* @since 1.2
* @access public
* @return void
*/
function setMultiple($multiple)
{
if ($multiple) {
$this->updateAttributes(array('multiple' => 'multiple'));
} else {
$this->removeAttribute('multiple');
}
} //end func setMultiple
// }}}
// {{{ getMultiple()
 
/**
* Returns the select mutiple attribute
*
* @since 1.2
* @access public
* @return bool true if multiple select, false otherwise
*/
function getMultiple()
{
return (bool)$this->getAttribute('multiple');
} //end func getMultiple
 
// }}}
// {{{ addOption()
 
/**
* Adds a new OPTION to the SELECT
*
* @param string $text Display text for the OPTION
* @param string $value Value for the OPTION
* @param mixed $attributes Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function addOption($text, $value, $attributes=null)
{
if (null === $attributes) {
$attributes = array('value' => $value);
} else {
$attributes = $this->_parseAttributes($attributes);
if (isset($attributes['selected'])) {
// the 'selected' attribute will be set in toHtml()
$this->_removeAttr('selected', $attributes);
if (is_null($this->_values)) {
$this->_values = array($value);
} elseif (!in_array($value, $this->_values)) {
$this->_values[] = $value;
}
}
$this->_updateAttrArray($attributes, array('value' => $value));
}
$this->_options[] = array('text' => $text, 'attr' => $attributes);
} // end func addOption
// }}}
// {{{ loadArray()
 
/**
* Loads the options from an associative array
*
* @param array $arr Associative array of options
* @param mixed $values (optional) Array or comma delimited string of selected values
* @since 1.0
* @access public
* @return PEAR_Error on error or true
* @throws PEAR_Error
*/
function loadArray($arr, $values=null)
{
if (!is_array($arr)) {
return PEAR::raiseError('Argument 1 of HTML_Select::loadArray is not a valid array');
}
if (isset($values)) {
$this->setSelected($values);
}
foreach ($arr as $key => $val) {
// Warning: new API since release 2.3
$this->addOption($val, $key);
}
return true;
} // end func loadArray
 
// }}}
// {{{ loadDbResult()
 
/**
* Loads the options from DB_result object
*
* If no column names are specified the first two columns of the result are
* used as the text and value columns respectively
* @param object $result DB_result object
* @param string $textCol (optional) Name of column to display as the OPTION text
* @param string $valueCol (optional) Name of column to use as the OPTION value
* @param mixed $values (optional) Array or comma delimited string of selected values
* @since 1.0
* @access public
* @return PEAR_Error on error or true
* @throws PEAR_Error
*/
function loadDbResult(&$result, $textCol=null, $valueCol=null, $values=null)
{
if (!is_object($result) || !is_a($result, 'db_result')) {
return PEAR::raiseError('Argument 1 of HTML_Select::loadDbResult is not a valid DB_result');
}
if (isset($values)) {
$this->setValue($values);
}
$fetchMode = ($textCol && $valueCol) ? DB_FETCHMODE_ASSOC : DB_FETCHMODE_DEFAULT;
while (is_array($row = $result->fetchRow($fetchMode)) ) {
if ($fetchMode == DB_FETCHMODE_ASSOC) {
$this->addOption($row[$textCol], $row[$valueCol]);
} else {
$this->addOption($row[0], $row[1]);
}
}
return true;
} // end func loadDbResult
// }}}
// {{{ loadQuery()
 
/**
* Queries a database and loads the options from the results
*
* @param mixed $conn Either an existing DB connection or a valid dsn
* @param string $sql SQL query string
* @param string $textCol (optional) Name of column to display as the OPTION text
* @param string $valueCol (optional) Name of column to use as the OPTION value
* @param mixed $values (optional) Array or comma delimited string of selected values
* @since 1.1
* @access public
* @return void
* @throws PEAR_Error
*/
function loadQuery(&$conn, $sql, $textCol=null, $valueCol=null, $values=null)
{
if (is_string($conn)) {
require_once('DB.php');
$dbConn = &DB::connect($conn, true);
if (DB::isError($dbConn)) {
return $dbConn;
}
} elseif (is_subclass_of($conn, "db_common")) {
$dbConn = &$conn;
} else {
return PEAR::raiseError('Argument 1 of HTML_Select::loadQuery is not a valid type');
}
$result = $dbConn->query($sql);
if (DB::isError($result)) {
return $result;
}
$this->loadDbResult($result, $textCol, $valueCol, $values);
$result->free();
if (is_string($conn)) {
$dbConn->disconnect();
}
return true;
} // end func loadQuery
 
// }}}
// {{{ load()
 
/**
* Loads options from different types of data sources
*
* This method is a simulated overloaded method. The arguments, other than the
* first are optional and only mean something depending on the type of the first argument.
* If the first argument is an array then all arguments are passed in order to loadArray.
* If the first argument is a db_result then all arguments are passed in order to loadDbResult.
* If the first argument is a string or a DB connection then all arguments are
* passed in order to loadQuery.
* @param mixed $options Options source currently supports assoc array or DB_result
* @param mixed $param1 (optional) See function detail
* @param mixed $param2 (optional) See function detail
* @param mixed $param3 (optional) See function detail
* @param mixed $param4 (optional) See function detail
* @since 1.1
* @access public
* @return PEAR_Error on error or true
* @throws PEAR_Error
*/
function load(&$options, $param1=null, $param2=null, $param3=null, $param4=null)
{
switch (true) {
case is_array($options):
return $this->loadArray($options, $param1);
break;
case (is_a($options, 'db_result')):
return $this->loadDbResult($options, $param1, $param2, $param3);
break;
case (is_string($options) && !empty($options) ):
return $this->loadQuery($options, $param1, $param2, $param3, $param4);
break;
}
} // end func load
// }}}
// {{{ toHtml()
 
/**
* Returns the SELECT in HTML
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
if ($this->_flagFrozen) {
return $this->getFrozenHtml();
} else {
$tabs = $this->_getTabs();
$strHtml = '';
 
if ($this->getComment() != '') {
$strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->\n";
}
 
if (!$this->getMultiple()) {
$attrString = $this->_getAttrString($this->_attributes);
} else {
$myName = $this->getName();
$this->setName($myName . '[]');
$attrString = $this->_getAttrString($this->_attributes);
$this->setName($myName);
}
$strHtml .= $tabs . '<select' . $attrString . ">\n";
 
foreach ($this->_options as $option) {
if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
$this->_updateAttrArray($option['attr'], array('selected' => 'selected'));
}
$strHtml .= $tabs . "\t<option" . $this->_getAttrString($option['attr']) . '>' .
$option['text'] . "</option>\n";
}
 
return $strHtml . $tabs . '</select>';
}
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @since 1.0
* @access public
* @return string
*/
function getFrozenHtml()
{
$value = array();
if (is_array($this->_values)) {
foreach ($this->_values as $key => $val) {
for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
if ((string)$val == (string)$this->_options[$i]['attr']['value']) {
$value[$key] = $this->_options[$i]['text'];
break;
}
}
}
}
$html = empty($value)? '&nbsp;': join('<br />', $value);
if ($this->_persistantFreeze) {
$name = $this->getPrivateName();
// Only use id attribute if doing single hidden input
if (1 == count($value)) {
$id = $this->getAttribute('id');
$idAttr = isset($id)? array('id' => $id): array();
} else {
$idAttr = array();
}
foreach ($value as $key => $item) {
$html .= '<input' . $this->_getAttrString(array(
'type' => 'hidden',
'name' => $name,
'value' => $this->_values[$key]
) + $idAttr) . ' />';
}
}
return $html;
} //end func getFrozenHtml
 
// }}}
// {{{ exportValue()
 
/**
* We check the options and return only the values that _could_ have been
* selected. We also return a scalar value if select is not "multiple"
*/
function exportValue(&$submitValues, $assoc = false)
{
$value = $this->_findValue($submitValues);
if (is_null($value)) {
$value = $this->getValue();
} elseif(!is_array($value)) {
$value = array($value);
}
if (is_array($value) && !empty($this->_options)) {
$cleanValue = null;
foreach ($value as $v) {
for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
if ($v == $this->_options[$i]['attr']['value']) {
$cleanValue[] = $v;
break;
}
}
}
} else {
$cleanValue = $value;
}
if (is_array($cleanValue) && !$this->getMultiple()) {
return $this->_prepareValue($cleanValue[0], $assoc);
} else {
return $this->_prepareValue($cleanValue, $assoc);
}
}
// }}}
// {{{ onQuickFormEvent()
 
function onQuickFormEvent($event, $arg, &$caller)
{
if ('updateValue' == $event) {
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_submitValues);
// Fix for bug #4465
// XXX: should we push this to element::onQuickFormEvent()?
if (null === $value && !$caller->isSubmitted()) {
$value = $this->_findValue($caller->_defaultValues);
}
}
if (null !== $value) {
$this->setValue($value);
}
return true;
} else {
return parent::onQuickFormEvent($event, $arg, $caller);
}
}
 
// }}}
} //end class HTML_QuickForm_select
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/ITDynamic.php
New file
0,0 → 1,287
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Alexey Borzov <borz_off@cs.msu.su> |
// +----------------------------------------------------------------------+
//
// $Id: ITDynamic.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/Renderer.php';
 
/**
* A concrete renderer for HTML_QuickForm, using Integrated Templates.
*
* This is a "dynamic" renderer, which means that concrete form look
* is defined at runtime. This also means that you can define
* <b>one</b> template file for <b>all</b> your forms. That template
* should contain a block for every element 'look' appearing in your
* forms and also some special blocks (consult the examples). If a
* special block is not set for an element, the renderer falls back to
* a default one.
*
* @author Alexey Borzov <borz_off@cs.msu.su>
* @access public
*/
class HTML_QuickForm_Renderer_ITDynamic extends HTML_QuickForm_Renderer
{
/**
* A template class (HTML_Template_ITX or HTML_Template_Sigma) instance
* @var object
*/
var $_tpl = null;
 
/**
* The errors that were not shown near concrete fields go here
* @var array
*/
var $_errors = array();
 
/**
* Show the block with required note?
* @var bool
*/
var $_showRequired = false;
 
/**
* A separator for group elements
* @var mixed
*/
var $_groupSeparator = null;
 
/**
* The current element index inside a group
* @var integer
*/
var $_groupElementIdx = 0;
 
/**
* Blocks to use for different elements
* @var array
*/
var $_elementBlocks = array();
 
/**
* Block to use for headers
* @var string
*/
var $_headerBlock = null;
 
 
/**
* Constructor
*
* @param object An HTML_Template_ITX/HTML_Template_Sigma object to use
*/
function HTML_QuickForm_Renderer_ITDynamic(&$tpl)
{
$this->HTML_QuickForm_Renderer();
$this->_tpl =& $tpl;
$this->_tpl->setCurrentBlock('qf_main_loop');
}
 
 
function finishForm(&$form)
{
// display errors above form
if (!empty($this->_errors) && $this->_tpl->blockExists('qf_error_loop')) {
foreach ($this->_errors as $error) {
$this->_tpl->setVariable('qf_error', $error);
$this->_tpl->parse('qf_error_loop');
}
}
// show required note
if ($this->_showRequired) {
$this->_tpl->setVariable('qf_required_note', $form->getRequiredNote());
}
// assign form attributes
$this->_tpl->setVariable('qf_attributes', $form->getAttributes(true));
// assign javascript validation rules
$this->_tpl->setVariable('qf_javascript', $form->getValidationScript());
}
 
function renderHeader(&$header)
{
$blockName = $this->_matchBlock($header);
if ('qf_header' == $blockName && isset($this->_headerBlock)) {
$blockName = $this->_headerBlock;
}
$this->_tpl->setVariable('qf_header', $header->toHtml());
$this->_tpl->parse($blockName);
$this->_tpl->parse('qf_main_loop');
}
 
 
function renderElement(&$element, $required, $error)
{
$blockName = $this->_matchBlock($element);
// are we inside a group?
if ('qf_main_loop' != $this->_tpl->currentBlock) {
if (0 != $this->_groupElementIdx && $this->_tpl->placeholderExists('qf_separator', $blockName)) {
if (is_array($this->_groupSeparator)) {
$this->_tpl->setVariable('qf_separator', $this->_groupSeparator[($this->_groupElementIdx - 1) % count($this->_groupSeparator)]);
} else {
$this->_tpl->setVariable('qf_separator', (string)$this->_groupSeparator);
}
}
$this->_groupElementIdx++;
 
} elseif(!empty($error)) {
// show the error message or keep it for later use
if ($this->_tpl->blockExists($blockName . '_error')) {
$this->_tpl->setVariable('qf_error', $error);
} else {
$this->_errors[] = $error;
}
}
// show an '*' near the required element
if ($required) {
$this->_showRequired = true;
if ($this->_tpl->blockExists($blockName . '_required')) {
$this->_tpl->touchBlock($blockName . '_required');
}
}
// Prepare multiple labels
$labels = $element->getLabel();
if (is_array($labels)) {
$mainLabel = array_shift($labels);
} else {
$mainLabel = $labels;
}
// render the element itself with its main label
$this->_tpl->setVariable('qf_element', $element->toHtml());
if ($this->_tpl->placeholderExists('qf_label', $blockName)) {
$this->_tpl->setVariable('qf_label', $mainLabel);
}
// render extra labels, if any
if (is_array($labels)) {
foreach($labels as $key => $label) {
$key = is_int($key)? $key + 2: $key;
if ($this->_tpl->blockExists($blockName . '_label_' . $key)) {
$this->_tpl->setVariable('qf_label_' . $key, $label);
}
}
}
$this->_tpl->parse($blockName);
$this->_tpl->parseCurrentBlock();
}
 
function renderHidden(&$element)
{
$this->_tpl->setVariable('qf_hidden', $element->toHtml());
$this->_tpl->parse('qf_hidden_loop');
}
 
 
function startGroup(&$group, $required, $error)
{
$blockName = $this->_matchBlock($group);
$this->_tpl->setCurrentBlock($blockName . '_loop');
$this->_groupElementIdx = 0;
$this->_groupSeparator = is_null($group->_separator)? '&nbsp;': $group->_separator;
// show an '*' near the required element
if ($required) {
$this->_showRequired = true;
if ($this->_tpl->blockExists($blockName . '_required')) {
$this->_tpl->touchBlock($blockName . '_required');
}
}
// show the error message or keep it for later use
if (!empty($error)) {
if ($this->_tpl->blockExists($blockName . '_error')) {
$this->_tpl->setVariable('qf_error', $error);
} else {
$this->_errors[] = $error;
}
}
$this->_tpl->setVariable('qf_group_label', $group->getLabel());
}
 
 
function finishGroup(&$group)
{
$this->_tpl->parse($this->_matchBlock($group));
$this->_tpl->setCurrentBlock('qf_main_loop');
$this->_tpl->parseCurrentBlock();
}
 
 
/**
* Returns the name of a block to use for element rendering
*
* If a name was not explicitly set via setElementBlock(), it tries
* the names '{prefix}_{element type}' and '{prefix}_{element}', where
* prefix is either 'qf' or the name of the current group's block
*
* @param object An HTML_QuickForm_element object
* @access private
* @return string block name
*/
function _matchBlock(&$element)
{
$name = $element->getName();
$type = $element->getType();
if (isset($this->_elementBlocks[$name]) && $this->_tpl->blockExists($this->_elementBlocks[$name])) {
if (('group' == $type) || ($this->_elementBlocks[$name] . '_loop' != $this->_tpl->currentBlock)) {
return $this->_elementBlocks[$name];
}
}
if ('group' != $type && 'qf_main_loop' != $this->_tpl->currentBlock) {
$prefix = substr($this->_tpl->currentBlock, 0, -5); // omit '_loop' postfix
} else {
$prefix = 'qf';
}
if ($this->_tpl->blockExists($prefix . '_' . $type)) {
return $prefix . '_' . $type;
} elseif ($this->_tpl->blockExists($prefix . '_' . $name)) {
return $prefix . '_' . $name;
} else {
return $prefix . '_element';
}
}
 
 
/**
* Sets the block to use for element rendering
*
* @param mixed element name or array ('element name' => 'block name')
* @param string block name if $elementName is not an array
* @access public
* @return void
*/
function setElementBlock($elementName, $blockName = null)
{
if (is_array($elementName)) {
$this->_elementBlocks = array_merge($this->_elementBlocks, $elementName);
} else {
$this->_elementBlocks[$elementName] = $blockName;
}
}
 
 
/**
* Sets the name of a block to use for header rendering
*
* @param string block name
* @access public
* @return void
*/
function setHeaderBlock($blockName)
{
$this->_headerBlock = $blockName;
}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/QuickHtml.php
New file
0,0 → 1,203
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Jason Rust <jrust@rustyparts.com> |
// +----------------------------------------------------------------------+
//
// $Id: QuickHtml.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Renderer/Default.php');
 
/**
* A renderer that makes it quick and easy to create customized forms.
*
* This renderer has three main distinctives: an easy way to create
* custom-looking forms, the ability to separate the creation of form
* elements from their display, and being able to use QuickForm in
* widget-based template systems. See the online docs for more info.
* For a usage example see: docs/renderers/QuickHtml_example.php
*
* @access public
* @package QuickForm
*/
class HTML_QuickForm_Renderer_QuickHtml extends HTML_QuickForm_Renderer_Default {
// {{{ properties
 
/**
* The array of rendered elements
* @var array
*/
var $renderedElements = array();
 
// }}}
// {{{ constructor
/**
* Constructor
*
* @access public
* @return void
*/
function HTML_QuickForm_Renderer_QuickHtml()
{
$this->HTML_QuickForm_Renderer_Default();
// The default templates aren't used for this renderer
$this->clearAllTemplates();
} // end constructor
 
// }}}
// {{{ toHtml()
 
/**
* returns the HTML generated for the form
*
* @param string $data (optional) Any extra data to put before the end of the form
*
* @access public
* @return string
*/
function toHtml($data = '')
{
// Render any elements that haven't been rendered explicitly by elementToHtml()
foreach (array_keys($this->renderedElements) as $key) {
if (!$this->renderedElements[$key]['rendered']) {
$this->renderedElements[$key]['rendered'] = true;
$data .= $this->renderedElements[$key]['html'] . "\n";
}
}
 
// Insert the extra data and form elements at the end of the form
$this->_html = str_replace('</form>', $data . "\n</form>", $this->_html);
return $this->_html;
} // end func toHtml
 
// }}}
// {{{ elementToHtml()
 
/**
* Gets the html for an element and marks it as rendered.
*
* @param string $elementName The element name
* @param string $elementValue (optional) The value of the element. This is only useful
* for elements that have the same name (i.e. radio and checkbox), but
* different values
*
* @access public
* @return string The html for the QuickForm element
*/
function elementToHtml($elementName, $elementValue = null)
{
$elementKey = null;
// Find the key for the element
foreach ($this->renderedElements as $key => $data) {
if ($data['name'] == $elementName &&
// See if the value must match as well
(is_null($elementValue) ||
$data['value'] == $elementValue)) {
$elementKey = $key;
break;
}
}
 
if (is_null($elementKey)) {
$msg = is_null($elementValue) ? "Element $elementName does not exist." :
"Element $elementName with value of $elementValue does not exist.";
return PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, $msg, 'HTML_QuickForm_Error', true);
} else {
if ($this->renderedElements[$elementKey]['rendered']) {
$msg = is_null($elementValue) ? "Element $elementName has already been rendered." :
"Element $elementName with value of $elementValue has already been rendered.";
return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, $msg, 'HTML_QuickForm_Error', true);
} else {
$this->renderedElements[$elementKey]['rendered'] = true;
return $this->renderedElements[$elementKey]['html'];
}
}
} // end func elementToHtml
 
// }}}
// {{{ renderElement()
 
/**
* Gets the html for an element and adds it to the array by calling
* parent::renderElement()
*
* @param object An HTML_QuickForm_element object
* @param bool Whether an element is required
* @param string An error message associated with an element
*
* @access public
* @return mixed HTML string of element if $immediateRender is set, else we just add the
* html to the global _html string
*/
function renderElement(&$element, $required, $error)
{
$this->_html = '';
parent::renderElement($element, $required, $error);
if (!$this->_inGroup) {
$this->renderedElements[] = array(
'name' => $element->getName(),
'value' => $element->getValue(),
'html' => $this->_html,
'rendered' => false);
}
$this->_html = '';
} // end func renderElement
 
// }}}
// {{{ renderHidden()
 
/**
* Gets the html for a hidden element and adds it to the array.
*
* @param object An HTML_QuickForm_hidden object being visited
* @access public
* @return void
*/
function renderHidden(&$element)
{
$this->renderedElements[] = array(
'name' => $element->getName(),
'value' => $element->getValue(),
'html' => $element->toHtml(),
'rendered' => false);
} // end func renderHidden
// }}}
// {{{ finishGroup()
 
/**
* Gets the html for the group element and adds it to the array by calling
* parent::finishGroup()
*
* @param object An HTML_QuickForm_group object being visited
* @access public
* @return void
*/
function finishGroup(&$group)
{
$this->_html = '';
parent::finishGroup($group);
$this->renderedElements[] = array(
'name' => $group->getName(),
'value' => $group->getValue(),
'html' => $this->_html,
'rendered' => false);
$this->_html = '';
} // end func finishGroup
 
// }}}
} // end class HTML_QuickForm_Renderer_QuickHtml
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/Default.php
New file
0,0 → 1,474
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Alexey Borzov <borz_off@cs.msu.su> |
// | Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Default.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Renderer.php');
 
/**
* A concrete renderer for HTML_QuickForm,
* based on QuickForm 2.x built-in one
*
* @access public
*/
class HTML_QuickForm_Renderer_Default extends HTML_QuickForm_Renderer
{
/**
* The HTML of the form
* @var string
* @access private
*/
var $_html;
 
/**
* Header Template string
* @var string
* @access private
*/
var $_headerTemplate =
"\n\t<tr>\n\t\t<td style=\"white-space: nowrap; background-color: #CCCCCC;\" align=\"left\" valign=\"top\" colspan=\"2\"><b>{header}</b></td>\n\t</tr>";
 
/**
* Element template string
* @var string
* @access private
*/
var $_elementTemplate =
"\n\t<tr>\n\t\t<td align=\"right\" valign=\"top\"><!-- BEGIN required --><span style=\"color: #ff0000\">*</span><!-- END required --><b>{label}</b></td>\n\t\t<td valign=\"top\" align=\"left\"><!-- BEGIN error --><span style=\"color: #ff0000\">{error}</span><br /><!-- END error -->\t{element}</td>\n\t</tr>";
 
/**
* Form template string
* @var string
* @access private
*/
var $_formTemplate =
"\n<form{attributes}>\n<div>\n{hidden}<table border=\"0\">\n{content}\n</table>\n</div>\n</form>";
 
/**
* Required Note template string
* @var string
* @access private
*/
var $_requiredNoteTemplate =
"\n\t<tr>\n\t\t<td></td>\n\t<td align=\"left\" valign=\"top\">{requiredNote}</td>\n\t</tr>";
 
/**
* Array containing the templates for customised elements
* @var array
* @access private
*/
var $_templates = array();
 
/**
* Array containing the templates for group wraps.
*
* These templates are wrapped around group elements and groups' own
* templates wrap around them. This is set by setGroupTemplate().
*
* @var array
* @access private
*/
var $_groupWraps = array();
 
/**
* Array containing the templates for elements within groups
* @var array
* @access private
*/
var $_groupTemplates = array();
 
/**
* True if we are inside a group
* @var bool
* @access private
*/
var $_inGroup = false;
 
/**
* Array with HTML generated for group elements
* @var array
* @access private
*/
var $_groupElements = array();
 
/**
* Template for an element inside a group
* @var string
* @access private
*/
var $_groupElementTemplate = '';
 
/**
* HTML that wraps around the group elements
* @var string
* @access private
*/
var $_groupWrap = '';
 
/**
* HTML for the current group
* @var string
* @access private
*/
var $_groupTemplate = '';
/**
* Collected HTML of the hidden fields
* @var string
* @access private
*/
var $_hiddenHtml = '';
 
/**
* Constructor
*
* @access public
*/
function HTML_QuickForm_Renderer_Default()
{
$this->HTML_QuickForm_Renderer();
} // end constructor
 
/**
* returns the HTML generated for the form
*
* @access public
* @return string
*/
function toHtml()
{
// _hiddenHtml is cleared in finishForm(), so this only matters when
// finishForm() was not called (e.g. group::toHtml(), bug #3511)
return $this->_hiddenHtml . $this->_html;
} // end func toHtml
/**
* Called when visiting a form, before processing any form elements
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
*/
function startForm(&$form)
{
$this->_html = '';
$this->_hiddenHtml = '';
} // end func startForm
 
/**
* Called when visiting a form, after processing all form elements
* Adds required note, form attributes, validation javascript and form content.
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
*/
function finishForm(&$form)
{
// add a required note, if one is needed
if (!empty($form->_required) && !$form->_freezeAll) {
$this->_html .= str_replace('{requiredNote}', $form->getRequiredNote(), $this->_requiredNoteTemplate);
}
// add form attributes and content
$html = str_replace('{attributes}', $form->getAttributes(true), $this->_formTemplate);
if (strpos($this->_formTemplate, '{hidden}')) {
$html = str_replace('{hidden}', $this->_hiddenHtml, $html);
} else {
$this->_html .= $this->_hiddenHtml;
}
$this->_hiddenHtml = '';
$this->_html = str_replace('{content}', $this->_html, $html);
// add a validation script
if ('' != ($script = $form->getValidationScript())) {
$this->_html = $script . "\n" . $this->_html;
}
} // end func finishForm
/**
* Called when visiting a header element
*
* @param object An HTML_QuickForm_header element being visited
* @access public
* @return void
*/
function renderHeader(&$header)
{
$name = $header->getName();
if (!empty($name) && isset($this->_templates[$name])) {
$this->_html .= str_replace('{header}', $header->toHtml(), $this->_templates[$name]);
} else {
$this->_html .= str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
}
} // end func renderHeader
 
/**
* Helper method for renderElement
*
* @param string Element name
* @param mixed Element label (if using an array of labels, you should set the appropriate template)
* @param bool Whether an element is required
* @param string Error message associated with the element
* @access private
* @see renderElement()
* @return string Html for element
*/
function _prepareTemplate($name, $label, $required, $error)
{
if (is_array($label)) {
$nameLabel = array_shift($label);
} else {
$nameLabel = $label;
}
if (isset($this->_templates[$name])) {
$html = str_replace('{label}', $nameLabel, $this->_templates[$name]);
} else {
$html = str_replace('{label}', $nameLabel, $this->_elementTemplate);
}
if ($required) {
$html = str_replace('<!-- BEGIN required -->', '', $html);
$html = str_replace('<!-- END required -->', '', $html);
} else {
$html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->(\s|\S)*<!-- END required -->([ \t\n\r]*)?/i", '', $html);
}
if (isset($error)) {
$html = str_replace('{error}', $error, $html);
$html = str_replace('<!-- BEGIN error -->', '', $html);
$html = str_replace('<!-- END error -->', '', $html);
} else {
$html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN error -->(\s|\S)*<!-- END error -->([ \t\n\r]*)?/i", '', $html);
}
if (is_array($label)) {
foreach($label as $key => $text) {
$key = is_int($key)? $key + 2: $key;
$html = str_replace("{label_{$key}}", $text, $html);
$html = str_replace("<!-- BEGIN label_{$key} -->", '', $html);
$html = str_replace("<!-- END label_{$key} -->", '', $html);
}
}
if (strpos($html, '{label_')) {
$html = preg_replace('/\s*<!-- BEGIN label_(\S+) -->.*<!-- END label_\1 -->\s*/i', '', $html);
}
return $html;
} // end func _prepareTemplate
 
/**
* Renders an element Html
* Called when visiting an element
*
* @param object An HTML_QuickForm_element object being visited
* @param bool Whether an element is required
* @param string An error message associated with an element
* @access public
* @return void
*/
function renderElement(&$element, $required, $error)
{
if (!$this->_inGroup) {
$html = $this->_prepareTemplate($element->getName(), $element->getLabel(), $required, $error);
$this->_html .= str_replace('{element}', $element->toHtml(), $html);
 
} elseif (!empty($this->_groupElementTemplate)) {
$html = str_replace('{label}', $element->getLabel(), $this->_groupElementTemplate);
if ($required) {
$html = str_replace('<!-- BEGIN required -->', '', $html);
$html = str_replace('<!-- END required -->', '', $html);
} else {
$html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->(\s|\S)*<!-- END required -->([ \t\n\r]*)?/i", '', $html);
}
$this->_groupElements[] = str_replace('{element}', $element->toHtml(), $html);
 
} else {
$this->_groupElements[] = $element->toHtml();
}
} // end func renderElement
/**
* Renders an hidden element
* Called when visiting a hidden element
*
* @param object An HTML_QuickForm_hidden object being visited
* @access public
* @return void
*/
function renderHidden(&$element)
{
$this->_hiddenHtml .= $element->toHtml() . "\n";
} // end func renderHidden
 
/**
* Called when visiting a raw HTML/text pseudo-element
*
* @param object An HTML_QuickForm_html element being visited
* @access public
* @return void
*/
function renderHtml(&$data)
{
$this->_html .= $data->toHtml();
} // end func renderHtml
 
/**
* Called when visiting a group, before processing any group elements
*
* @param object An HTML_QuickForm_group object being visited
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
*/
function startGroup(&$group, $required, $error)
{
$name = $group->getName();
$this->_groupTemplate = $this->_prepareTemplate($name, $group->getLabel(), $required, $error);
$this->_groupElementTemplate = empty($this->_groupTemplates[$name])? '': $this->_groupTemplates[$name];
$this->_groupWrap = empty($this->_groupWraps[$name])? '': $this->_groupWraps[$name];
$this->_groupElements = array();
$this->_inGroup = true;
} // end func startGroup
 
/**
* Called when visiting a group, after processing all group elements
*
* @param object An HTML_QuickForm_group object being visited
* @access public
* @return void
*/
function finishGroup(&$group)
{
$separator = $group->_separator;
if (is_array($separator)) {
$count = count($separator);
$html = '';
for ($i = 0; $i < count($this->_groupElements); $i++) {
$html .= (0 == $i? '': $separator[($i - 1) % $count]) . $this->_groupElements[$i];
}
} else {
if (is_null($separator)) {
$separator = '&nbsp;';
}
$html = implode((string)$separator, $this->_groupElements);
}
if (!empty($this->_groupWrap)) {
$html = str_replace('{content}', $html, $this->_groupWrap);
}
$this->_html .= str_replace('{element}', $html, $this->_groupTemplate);
$this->_inGroup = false;
} // end func finishGroup
 
/**
* Sets element template
*
* @param string The HTML surrounding an element
* @param string (optional) Name of the element to apply template for
* @access public
* @return void
*/
function setElementTemplate($html, $element = null)
{
if (is_null($element)) {
$this->_elementTemplate = $html;
} else {
$this->_templates[$element] = $html;
}
} // end func setElementTemplate
 
 
/**
* Sets template for a group wrapper
*
* This template is contained within a group-as-element template
* set via setTemplate() and contains group's element templates, set
* via setGroupElementTemplate()
*
* @param string The HTML surrounding group elements
* @param string Name of the group to apply template for
* @access public
* @return void
*/
function setGroupTemplate($html, $group)
{
$this->_groupWraps[$group] = $html;
} // end func setGroupTemplate
 
/**
* Sets element template for elements within a group
*
* @param string The HTML surrounding an element
* @param string Name of the group to apply template for
* @access public
* @return void
*/
function setGroupElementTemplate($html, $group)
{
$this->_groupTemplates[$group] = $html;
} // end func setGroupElementTemplate
 
/**
* Sets header template
*
* @param string The HTML surrounding the header
* @access public
* @return void
*/
function setHeaderTemplate($html)
{
$this->_headerTemplate = $html;
} // end func setHeaderTemplate
 
/**
* Sets form template
*
* @param string The HTML surrounding the form tags
* @access public
* @return void
*/
function setFormTemplate($html)
{
$this->_formTemplate = $html;
} // end func setFormTemplate
 
/**
* Sets the note indicating required fields template
*
* @param string The HTML surrounding the required note
* @access public
* @return void
*/
function setRequiredNoteTemplate($html)
{
$this->_requiredNoteTemplate = $html;
} // end func setRequiredNoteTemplate
 
/**
* Clears all the HTML out of the templates that surround notes, elements, etc.
* Useful when you want to use addData() to create a completely custom form look
*
* @access public
* @return void
*/
function clearAllTemplates()
{
$this->setElementTemplate('{element}');
$this->setFormTemplate("\n\t<form{attributes}>{content}\n\t</form>\n");
$this->setRequiredNoteTemplate('');
$this->_templates = array();
} // end func clearAllTemplates
} // end class HTML_QuickForm_Renderer_Default
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/ITStatic.php
New file
0,0 → 1,490
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: ITStatic.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Renderer.php');
 
/**
* A static renderer for HTML_QuickForm compatible
* with HTML_Template_IT and HTML_Template_Sigma.
*
* As opposed to the dynamic renderer, this renderer needs
* every elements and labels in the form to be specified by
* placeholders at the position you want them to be displayed.
*
* @author Bertrand Mansion <bmansion@mamasam.com>
* @access public
*/
class HTML_QuickForm_Renderer_ITStatic extends HTML_QuickForm_Renderer
{
/**
* An HTML_Template_IT or some other API compatible Template instance
* @var object
*/
var $_tpl = null;
 
/**
* Rendered form name
* @var string
*/
var $_formName = 'form';
 
/**
* The errors that were not shown near concrete fields go here
* @var array
*/
var $_errors = array();
 
/**
* Show the block with required note?
* @var bool
*/
var $_showRequired = false;
 
/**
* Which group are we currently parsing ?
* @var string
*/
var $_inGroup;
 
/**
* Index of the element in its group
* @var int
*/
var $_elementIndex = 0;
 
/**
* If elements have been added with the same name
* @var array
*/
var $_duplicateElements = array();
 
/**
* How to handle the required tag for required fields
* @var string
*/
var $_required = '{label}<font size="1" color="red">*</font>';
 
/**
* How to handle error messages in form validation
* @var string
*/
var $_error = '<font color="red">{error}</font><br />{html}';
 
/**
* Collected HTML for hidden elements, if needed
* @var string
*/
var $_hidden = '';
 
/**
* Constructor
*
* @param object An HTML_Template_IT or other compatible Template object to use
*/
function HTML_QuickForm_Renderer_ITStatic(&$tpl)
{
$this->HTML_QuickForm_Renderer();
$this->_tpl =& $tpl;
} // end constructor
 
/**
* Called when visiting a form, before processing any form elements
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
*/
function startForm(&$form)
{
$this->_formName = $form->getAttribute('id');
 
if (count($form->_duplicateIndex) > 0) {
// Take care of duplicate elements
foreach ($form->_duplicateIndex as $elementName => $indexes) {
$this->_duplicateElements[$elementName] = 0;
}
}
} // end func startForm
 
/**
* Called when visiting a form, after processing all form elements
*
* @param object An HTML_QuickForm object being visited
* @access public
* @return void
*/
function finishForm(&$form)
{
// display errors above form
if (!empty($this->_errors) && $this->_tpl->blockExists($this->_formName.'_error_loop')) {
foreach ($this->_errors as $error) {
$this->_tpl->setVariable($this->_formName.'_error', $error);
$this->_tpl->parse($this->_formName.'_error_loop');
}
}
// show required note
if ($this->_showRequired) {
$this->_tpl->setVariable($this->_formName.'_required_note', $form->getRequiredNote());
}
// add hidden elements, if collected
if (!empty($this->_hidden)) {
$this->_tpl->setVariable($this->_formName . '_hidden', $this->_hidden);
}
// assign form attributes
$this->_tpl->setVariable($this->_formName.'_attributes', $form->getAttributes(true));
// assign javascript validation rules
$this->_tpl->setVariable($this->_formName.'_javascript', $form->getValidationScript());
} // end func finishForm
 
/**
* Called when visiting a header element
*
* @param object An HTML_QuickForm_header element being visited
* @access public
* @return void
*/
function renderHeader(&$header)
{
$name = $header->getName();
$varName = $this->_formName.'_header';
 
// Find placeHolder
if (!empty($name) && $this->_tpl->placeHolderExists($this->_formName.'_header_'.$name)) {
$varName = $this->_formName.'_header_'.$name;
}
$this->_tpl->setVariable($varName, $header->toHtml());
} // end func renderHeader
 
/**
* Called when visiting an element
*
* @param object An HTML_QuickForm_element object being visited
* @param bool Whether an element is required
* @param string An error message associated with an element
* @access public
* @return void
*/
function renderElement(&$element, $required, $error)
{
$name = $element->getName();
 
// are we inside a group?
if (!empty($this->_inGroup)) {
$varName = $this->_formName.'_'.str_replace(array('[', ']'), '_', $name);
if (substr($varName, -2) == '__') {
// element name is of type : group[]
$varName = $this->_inGroup.'_'.$this->_elementIndex.'_';
$this->_elementIndex++;
}
if ($varName != $this->_inGroup) {
$varName .= '_' == substr($varName, -1)? '': '_';
// element name is of type : group[name]
$label = $element->getLabel();
$html = $element->toHtml();
 
if ($required && !$element->isFrozen()) {
$this->_renderRequired($label, $html);
$this->_showRequired = true;
}
if (!empty($label)) {
if (is_array($label)) {
foreach ($label as $key => $value) {
$this->_tpl->setVariable($varName.'label_'.$key, $value);
}
} else {
$this->_tpl->setVariable($varName.'label', $label);
}
}
$this->_tpl->setVariable($varName.'html', $html);
}
 
} else {
 
$name = str_replace(array('[', ']'), array('_', ''), $name);
 
if (isset($this->_duplicateElements[$name])) {
// Element is a duplicate
$varName = $this->_formName.'_'.$name.'_'.$this->_duplicateElements[$name];
$this->_duplicateElements[$name]++;
} else {
$varName = $this->_formName.'_'.$name;
}
 
$label = $element->getLabel();
$html = $element->toHtml();
 
if ($required) {
$this->_showRequired = true;
$this->_renderRequired($label, $html);
}
if (!empty($error)) {
$this->_renderError($label, $html, $error);
}
if (is_array($label)) {
foreach ($label as $key => $value) {
$this->_tpl->setVariable($varName.'_label_'.$key, $value);
}
} else {
$this->_tpl->setVariable($varName.'_label', $label);
}
$this->_tpl->setVariable($varName.'_html', $html);
}
} // end func renderElement
 
/**
* Called when visiting a hidden element
*
* @param object An HTML_QuickForm_hidden object being visited
* @access public
* @return void
*/
function renderHidden(&$element)
{
if ($this->_tpl->placeholderExists($this->_formName . '_hidden')) {
$this->_hidden .= $element->toHtml();
} else {
$name = $element->getName();
$name = str_replace(array('[', ']'), array('_', ''), $name);
$this->_tpl->setVariable($this->_formName.'_'.$name.'_html', $element->toHtml());
}
} // end func renderHidden
 
/**
* Called when visiting a group, before processing any group elements
*
* @param object An HTML_QuickForm_group object being visited
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
*/
function startGroup(&$group, $required, $error)
{
$name = $group->getName();
$varName = $this->_formName.'_'.$name;
 
$this->_elementIndex = 0;
 
$html = $this->_tpl->placeholderExists($varName.'_html') ? $group->toHtml() : '';
$label = $group->getLabel();
 
if ($required) {
$this->_renderRequired($label, $html);
}
if (!empty($error)) {
$this->_renderError($label, $html, $error);
}
if (!empty($html)) {
$this->_tpl->setVariable($varName.'_html', $html);
} else {
// Uses error blocks to set the special groups layout error
// <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
if (!empty($error)) {
if ($this->_tpl->placeholderExists($varName.'_error')) {
if ($this->_tpl->blockExists($this->_formName . '_error_block')) {
$this->_tpl->setVariable($this->_formName . '_error', $error);
$error = $this->_getTplBlock($this->_formName . '_error_block');
} elseif (strpos($this->_error, '{html}') !== false || strpos($this->_error, '{label}') !== false) {
$error = str_replace('{error}', $error, $this->_error);
}
}
$this->_tpl->setVariable($varName . '_error', $error);
array_pop($this->_errors);
}
}
if (is_array($label)) {
foreach ($label as $key => $value) {
$this->_tpl->setVariable($varName.'_label_'.$key, $value);
}
} else {
$this->_tpl->setVariable($varName.'_label', $label);
}
$this->_inGroup = $varName;
} // end func startGroup
 
/**
* Called when visiting a group, after processing all group elements
*
* @param object An HTML_QuickForm_group object being visited
* @access public
* @return void
*/
function finishGroup(&$group)
{
$this->_inGroup = '';
} // end func finishGroup
 
/**
* Sets the way required elements are rendered
*
* You can use {label} or {html} placeholders to let the renderer know where
* where the element label or the element html are positionned according to the
* required tag. They will be replaced accordingly with the right value.
* For example:
* <font color="red">*</font>{label}
* will put a red star in front of the label if the element is required.
*
* @param string The required element template
* @access public
* @return void
*/
function setRequiredTemplate($template)
{
$this->_required = $template;
} // end func setRequiredTemplate
 
/**
* Sets the way elements with validation errors are rendered
*
* You can use {label} or {html} placeholders to let the renderer know where
* where the element label or the element html are positionned according to the
* error message. They will be replaced accordingly with the right value.
* The error message will replace the {error} place holder.
* For example:
* <font color="red">{error}</font><br />{html}
* will put the error message in red on top of the element html.
*
* If you want all error messages to be output in the main error block, do not specify
* {html} nor {label}.
*
* Groups can have special layouts. With this kind of groups, the renderer will need
* to know where to place the error message. In this case, use error blocks like:
* <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
* where you want the error message to appear in the form.
*
* @param string The element error template
* @access public
* @return void
*/
function setErrorTemplate($template)
{
$this->_error = $template;
} // end func setErrorTemplate
 
/**
* Called when an element is required
*
* This method will add the required tag to the element label and/or the element html
* such as defined with the method setRequiredTemplate
*
* @param string The element label
* @param string The element html rendering
* @see setRequiredTemplate()
* @access private
* @return void
*/
function _renderRequired(&$label, &$html)
{
if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_required_block')) {
if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
$this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
if (is_array($label)) {
$label[0] = $this->_getTplBlock($tplBlock);
} else {
$label = $this->_getTplBlock($tplBlock);
}
}
if (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
$this->_tpl->setVariable($this->_formName . '_html', $html);
$html = $this->_getTplBlock($tplBlock);
}
} else {
if (!empty($label) && strpos($this->_required, '{label}') !== false) {
if (is_array($label)) {
$label[0] = str_replace('{label}', $label[0], $this->_required);
} else {
$label = str_replace('{label}', $label, $this->_required);
}
}
if (!empty($html) && strpos($this->_required, '{html}') !== false) {
$html = str_replace('{html}', $html, $this->_required);
}
}
} // end func _renderRequired
 
/**
* Called when an element has a validation error
*
* This method will add the error message to the element label or the element html
* such as defined with the method setErrorTemplate. If the error placeholder is not found
* in the template, the error will be displayed in the form error block.
*
* @param string The element label
* @param string The element html rendering
* @param string The element error
* @see setErrorTemplate()
* @access private
* @return void
*/
function _renderError(&$label, &$html, $error)
{
if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_error_block')) {
$this->_tpl->setVariable($this->_formName . '_error', $error);
if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
$this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
if (is_array($label)) {
$label[0] = $this->_getTplBlock($tplBlock);
} else {
$label = $this->_getTplBlock($tplBlock);
}
} elseif (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
$this->_tpl->setVariable($this->_formName . '_html', $html);
$html = $this->_getTplBlock($tplBlock);
}
// clean up after ourselves
$this->_tpl->setVariable($this->_formName . '_error', null);
} elseif (!empty($label) && strpos($this->_error, '{label}') !== false) {
if (is_array($label)) {
$label[0] = str_replace(array('{label}', '{error}'), array($label[0], $error), $this->_error);
} else {
$label = str_replace(array('{label}', '{error}'), array($label, $error), $this->_error);
}
} elseif (!empty($html) && strpos($this->_error, '{html}') !== false) {
$html = str_replace(array('{html}', '{error}'), array($html, $error), $this->_error);
} else {
$this->_errors[] = $error;
}
}// end func _renderError
 
 
/**
* Returns the block's contents
*
* The method is needed because ITX and Sigma implement clearing
* the block contents on get() a bit differently
*
* @param string Block name
* @return string Block contents
*/
function _getTplBlock($block)
{
$this->_tpl->parse($block);
if (is_a($this->_tpl, 'html_template_sigma')) {
$ret = $this->_tpl->get($block, true);
} else {
$oldClear = $this->_tpl->clearCache;
$this->_tpl->clearCache = true;
$ret = $this->_tpl->get($block);
$this->_tpl->clearCache = $oldClear;
}
return $ret;
}
} // end class HTML_QuickForm_Renderer_ITStatic
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/Object.php
New file
0,0 → 1,432
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Ron McClain <ron@humaniq.com> |
// +----------------------------------------------------------------------+
//
// $Id: Object.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Renderer.php');
 
/**
* A concrete renderer for HTML_QuickForm, makes an object from form contents
*
* Based on HTML_Quickform_Renderer_Array code
*
* @access public
*/
class HTML_QuickForm_Renderer_Object extends HTML_QuickForm_Renderer
{
/**
* The object being generated
* @var object $_obj
*/
var $_obj= null;
 
/**
* Number of sections in the form (i.e. number of headers in it)
* @var integer $_sectionCount
*/
var $_sectionCount;
 
/**
* Current section number
* @var integer $_currentSection
*/
var $_currentSection;
 
/**
* Object representing current group
* @var object $_currentGroup
*/
var $_currentGroup = null;
 
/**
* Class of Element Objects
* @var object $_elementType
*/
var $_elementType = 'QuickFormElement';
 
/**
* Additional style information for different elements
* @var array $_elementStyles
*/
var $_elementStyles = array();
 
/**
* true: collect all hidden elements into string; false: process them as usual form elements
* @var bool $_collectHidden
*/
var $_collectHidden = false;
 
 
/**
* Constructor
*
* @param collecthidden bool true: collect all hidden elements
* @access public
*/
function HTML_QuickForm_Renderer_Object($collecthidden = false)
{
$this->HTML_QuickForm_Renderer();
$this->_collectHidden = $collecthidden;
$this->_obj = new QuickformForm;
}
 
/**
* Return the rendered Object
* @access public
*/
function toObject()
{
return $this->_obj;
}
 
/**
* Set the class of the form elements. Defaults to QuickformElement.
* @param type string Name of element class
* @access public
*/
function setElementType($type)
{
$this->_elementType = $type;
}
 
function startForm(&$form)
{
$this->_obj->frozen = $form->isFrozen();
$this->_obj->javascript = $form->getValidationScript();
$this->_obj->attributes = $form->getAttributes(true);
$this->_obj->requirednote = $form->getRequiredNote();
$this->_obj->errors = new StdClass;
 
if($this->_collectHidden) {
$this->_obj->hidden = '';
}
$this->_elementIdx = 1;
$this->_currentSection = null;
$this->_sectionCount = 0;
} // end func startForm
 
function renderHeader(&$header)
{
$hobj = new StdClass;
$hobj->header = $header->toHtml();
$this->_obj->sections[$this->_sectionCount] = $hobj;
$this->_currentSection = $this->_sectionCount++;
}
 
function renderElement(&$element, $required, $error)
{
$elObj = $this->_elementToObject($element, $required, $error);
if(!empty($error)) {
$name = $elObj->name;
$this->_obj->errors->$name = $error;
}
$this->_storeObject($elObj);
} // end func renderElement
 
function renderHidden(&$element)
{
if($this->_collectHidden) {
$this->_obj->hidden .= $element->toHtml() . "\n";
} else {
$this->renderElement($element, false, null);
}
} //end func renderHidden
 
function startGroup(&$group, $required, $error)
{
$this->_currentGroup = $this->_elementToObject($group, $required, $error);
if(!empty($error)) {
$name = $this->_currentGroup->name;
$this->_obj->errors->$name = $error;
}
} // end func startGroup
 
function finishGroup(&$group)
{
$this->_storeObject($this->_currentGroup);
$this->_currentGroup = null;
} // end func finishGroup
 
/**
* Creates an object representing an element
*
* @access private
* @param element object An HTML_QuickForm_element object
* @param required bool Whether an element is required
* @param error string Error associated with the element
* @return object
*/
function _elementToObject(&$element, $required, $error)
{
if($this->_elementType) {
$ret = new $this->_elementType;
}
$ret->name = $element->getName();
$ret->value = $element->getValue();
$ret->type = $element->getType();
$ret->frozen = $element->isFrozen();
$labels = $element->getLabel();
if (is_array($labels)) {
$ret->label = array_shift($labels);
foreach ($labels as $key => $label) {
$key = is_int($key)? $key + 2: $key;
$ret->{'label_' . $key} = $label;
}
} else {
$ret->label = $labels;
}
$ret->required = $required;
$ret->error = $error;
 
if(isset($this->_elementStyles[$ret->name])) {
$ret->style = $this->_elementStyles[$ret->name];
$ret->styleTemplate = "styles/". $ret->style .".html";
}
if($ret->type == 'group') {
$ret->separator = $element->_separator;
$ret->elements = array();
} else {
$ret->html = $element->toHtml();
}
return $ret;
}
 
/**
* Stores an object representation of an element in the form array
*
* @access private
* @param elObj object Object representation of an element
* @return void
*/
function _storeObject($elObj)
{
$name = $elObj->name;
if(is_object($this->_currentGroup) && $elObj->type != 'group') {
$this->_currentGroup->elements[] = $elObj;
} elseif (isset($this->_currentSection)) {
$this->_obj->sections[$this->_currentSection]->elements[] = $elObj;
} else {
$this->_obj->elements[] = $elObj;
}
}
 
function setElementStyle($elementName, $styleName = null)
{
if(is_array($elementName)) {
$this->_elementStyles = array_merge($this->_elementStyles, $elementName);
} else {
$this->_elementStyles[$elementName] = $styleName;
}
}
 
} // end class HTML_QuickForm_Renderer_Object
 
 
 
/**
* Convenience class for the form object passed to outputObject()
*
* Eg.
* {form.outputJavaScript():h}
* {form.outputHeader():h}
* <table>
* <tr>
* <td>{form.name.label:h}</td><td>{form.name.html:h}</td>
* </tr>
* </table>
* </form>
*/
class QuickformForm
{
/**
* Whether the form has been frozen
* @var boolean $frozen
*/
var $frozen;
 
/**
* Javascript for client-side validation
* @var string $javascript
*/
var $javascript;
 
/**
* Attributes for form tag
* @var string $attributes
*/
var $attributes;
 
/**
* Note about required elements
* @var string $requirednote
*/
var $requirednote;
 
/**
* Collected html of all hidden variables
* @var string $hidden
*/
var $hidden;
 
/**
* Set if there were validation errors.
* StdClass object with element names for keys and their
* error messages as values
* @var object $errors
*/
var $errors;
 
/**
* Array of QuickformElementObject elements. If there are headers in the form
* this will be empty and the elements will be in the
* separate sections
* @var array $elements
*/
var $elements;
 
/**
* Array of sections contained in the document
* @var array $sections
*/
var $sections;
 
/**
* Output &lt;form&gt; header
* {form.outputHeader():h}
* @return string &lt;form attributes&gt;
*/
function outputHeader()
{
return "<form " . $this->attributes . ">\n";
}
 
/**
* Output form javascript
* {form.outputJavaScript():h}
* @return string Javascript
*/
function outputJavaScript()
{
return $this->javascript;
}
} // end class QuickformForm
 
 
/**
* Convenience class describing a form element.
* The properties defined here will be available from
* your flexy templates by referencing
* {form.zip.label:h}, {form.zip.html:h}, etc.
*/
class QuickformElement
{
/**
* Element name
* @var string $name
*/
var $name;
 
/**
* Element value
* @var mixed $value
*/
var $value;
 
/**
* Type of element
* @var string $type
*/
var $type;
 
/**
* Whether the element is frozen
* @var boolean $frozen
*/
var $frozen;
 
/**
* Label for the element
* @var string $label
*/
var $label;
 
/**
* Whether element is required
* @var boolean $required
*/
var $required;
 
/**
* Error associated with the element
* @var string $error
*/
var $error;
 
/**
* Some information about element style
* @var string $style
*/
var $style;
 
/**
* HTML for the element
* @var string $html
*/
var $html;
 
/**
* If element is a group, the group separator
* @var mixed $separator
*/
var $separator;
 
/**
* If element is a group, an array of subelements
* @var array $elements
*/
var $elements;
 
function isType($type)
{
return ($this->type == $type);
}
 
function notFrozen()
{
return !$this->frozen;
}
 
function isButton()
{
return ($this->type == "submit" || $this->type == "reset");
}
 
 
/**
* XXX: why does it use Flexy when all other stuff here does not depend on it?
*/
function outputStyle()
{
ob_start();
HTML_Template_Flexy::staticQuickTemplate('styles/' . $this->style . '.html', $this);
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
} // end class QuickformElement
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/Array.php
New file
0,0 → 1,319
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Alexey Borzov <borz_off@cs.msu.su> |
// | Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// | Thomas Schulz <ths@4bconsult.de> |
// +----------------------------------------------------------------------+
//
// $Id: Array.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/Renderer.php';
 
/**
* A concrete renderer for HTML_QuickForm, makes an array of form contents
*
* Based on old toArray() code.
*
* The form array structure is the following:
* array(
* 'frozen' => 'whether the form is frozen',
* 'javascript' => 'javascript for client-side validation',
* 'attributes' => 'attributes for <form> tag',
* 'requirednote => 'note about the required elements',
* // if we set the option to collect hidden elements
* 'hidden' => 'collected html of all hidden elements',
* // if there were some validation errors:
* 'errors' => array(
* '1st element name' => 'Error for the 1st element',
* ...
* 'nth element name' => 'Error for the nth element'
* ),
* // if there are no headers in the form:
* 'elements' => array(
* element_1,
* ...
* element_N
* )
* // if there are headers in the form:
* 'sections' => array(
* array(
* 'header' => 'Header text for the first header',
* 'name' => 'Header name for the first header',
* 'elements' => array(
* element_1,
* ...
* element_K1
* )
* ),
* ...
* array(
* 'header' => 'Header text for the Mth header',
* 'name' => 'Header name for the Mth header',
* 'elements' => array(
* element_1,
* ...
* element_KM
* )
* )
* )
* );
*
* where element_i is an array of the form:
* array(
* 'name' => 'element name',
* 'value' => 'element value',
* 'type' => 'type of the element',
* 'frozen' => 'whether element is frozen',
* 'label' => 'label for the element',
* 'required' => 'whether element is required',
* 'error' => 'error associated with the element',
* 'style' => 'some information about element style (e.g. for Smarty)',
* // if element is not a group
* 'html' => 'HTML for the element'
* // if element is a group
* 'separator' => 'separator for group elements',
* 'elements' => array(
* element_1,
* ...
* element_N
* )
* );
*
* @access public
*/
class HTML_QuickForm_Renderer_Array extends HTML_QuickForm_Renderer
{
/**
* An array being generated
* @var array
*/
var $_ary;
 
/**
* Number of sections in the form (i.e. number of headers in it)
* @var integer
*/
var $_sectionCount;
 
/**
* Current section number
* @var integer
*/
var $_currentSection;
 
/**
* Array representing current group
* @var array
*/
var $_currentGroup = null;
 
/**
* Additional style information for different elements
* @var array
*/
var $_elementStyles = array();
 
/**
* true: collect all hidden elements into string; false: process them as usual form elements
* @var bool
*/
var $_collectHidden = false;
 
/**
* true: render an array of labels to many labels, $key 0 named 'label', the rest "label_$key"
* false: leave labels as defined
* @var bool
*/
var $staticLabels = false;
 
/**
* Constructor
*
* @param bool true: collect all hidden elements into string; false: process them as usual form elements
* @param bool true: render an array of labels to many labels, $key 0 to 'label' and the oterh to "label_$key"
* @access public
*/
function HTML_QuickForm_Renderer_Array($collectHidden = false, $staticLabels = false)
{
$this->HTML_QuickForm_Renderer();
$this->_collectHidden = $collectHidden;
$this->_staticLabels = $staticLabels;
} // end constructor
 
 
/**
* Returns the resultant array
*
* @access public
* @return array
*/
function toArray()
{
return $this->_ary;
}
 
 
function startForm(&$form)
{
$this->_ary = array(
'frozen' => $form->isFrozen(),
'javascript' => $form->getValidationScript(),
'attributes' => $form->getAttributes(true),
'requirednote' => $form->getRequiredNote(),
'errors' => array()
);
if ($this->_collectHidden) {
$this->_ary['hidden'] = '';
}
$this->_elementIdx = 1;
$this->_currentSection = null;
$this->_sectionCount = 0;
} // end func startForm
 
 
function renderHeader(&$header)
{
$this->_ary['sections'][$this->_sectionCount] = array(
'header' => $header->toHtml(),
'name' => $header->getName()
);
$this->_currentSection = $this->_sectionCount++;
} // end func renderHeader
 
 
function renderElement(&$element, $required, $error)
{
$elAry = $this->_elementToArray($element, $required, $error);
if (!empty($error)) {
$this->_ary['errors'][$elAry['name']] = $error;
}
$this->_storeArray($elAry);
} // end func renderElement
 
 
function renderHidden(&$element)
{
if ($this->_collectHidden) {
$this->_ary['hidden'] .= $element->toHtml() . "\n";
} else {
$this->renderElement($element, false, null);
}
} // end func renderHidden
 
 
function startGroup(&$group, $required, $error)
{
$this->_currentGroup = $this->_elementToArray($group, $required, $error);
if (!empty($error)) {
$this->_ary['errors'][$this->_currentGroup['name']] = $error;
}
} // end func startGroup
 
 
function finishGroup(&$group)
{
$this->_storeArray($this->_currentGroup);
$this->_currentGroup = null;
} // end func finishGroup
 
 
/**
* Creates an array representing an element
*
* @access private
* @param object An HTML_QuickForm_element object
* @param bool Whether an element is required
* @param string Error associated with the element
* @return array
*/
function _elementToArray(&$element, $required, $error)
{
$ret = array(
'name' => $element->getName(),
'value' => $element->getValue(),
'type' => $element->getType(),
'frozen' => $element->isFrozen(),
'required' => $required,
'error' => $error
);
// render label(s)
$labels = $element->getLabel();
if (is_array($labels) && $this->_staticLabels) {
foreach($labels as $key => $label) {
$key = is_int($key)? $key + 1: $key;
if (1 === $key) {
$ret['label'] = $label;
} else {
$ret['label_' . $key] = $label;
}
}
} else {
$ret['label'] = $labels;
}
 
// set the style for the element
if (isset($this->_elementStyles[$ret['name']])) {
$ret['style'] = $this->_elementStyles[$ret['name']];
}
if ('group' == $ret['type']) {
$ret['separator'] = $element->_separator;
$ret['elements'] = array();
} else {
$ret['html'] = $element->toHtml();
}
return $ret;
}
 
 
/**
* Stores an array representation of an element in the form array
*
* @access private
* @param array Array representation of an element
* @return void
*/
function _storeArray($elAry)
{
// where should we put this element...
if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
$this->_currentGroup['elements'][] = $elAry;
} elseif (isset($this->_currentSection)) {
$this->_ary['sections'][$this->_currentSection]['elements'][] = $elAry;
} else {
$this->_ary['elements'][] = $elAry;
}
}
 
 
/**
* Sets a style to use for element rendering
*
* @param mixed element name or array ('element name' => 'style name')
* @param string style name if $elementName is not an array
* @access public
* @return void
*/
function setElementStyle($elementName, $styleName = null)
{
if (is_array($elementName)) {
$this->_elementStyles = array_merge($this->_elementStyles, $elementName);
} else {
$this->_elementStyles[$elementName] = $styleName;
}
}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/ArraySmarty.php
New file
0,0 → 1,376
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Alexey Borzov <borz_off@cs.msu.su> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// | Thomas Schulz <ths@4bconsult.de> |
// +----------------------------------------------------------------------+
//
// $Id: ArraySmarty.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/Renderer/Array.php';
 
/**
* A static renderer for HTML_QuickForm, makes an array of form content
* useful for an Smarty template
*
* Based on old toArray() code and ITStatic renderer.
*
* The form array structure is the following:
* Array (
* [frozen] => whether the complete form is frozen'
* [javascript] => javascript for client-side validation
* [attributes] => attributes for <form> tag
* [hidden] => html of all hidden elements
* [requirednote] => note about the required elements
* [errors] => Array
* (
* [1st_element_name] => Error for the 1st element
* ...
* [nth_element_name] => Error for the nth element
* )
*
* [header] => Array
* (
* [1st_header_name] => Header text for the 1st header
* ...
* [nth_header_name] => Header text for the nth header
* )
*
* [1st_element_name] => Array for the 1st element
* ...
* [nth_element_name] => Array for the nth element
*
* // where an element array has the form:
* (
* [name] => element name
* [value] => element value,
* [type] => type of the element
* [frozen] => whether element is frozen
* [label] => label for the element
* [required] => whether element is required
* // if element is not a group:
* [html] => HTML for the element
* // if element is a group:
* [separator] => separator for group elements
* [1st_gitem_name] => Array for the 1st element in group
* ...
* [nth_gitem_name] => Array for the nth element in group
* )
* )
*
* @access public
*/
class HTML_QuickForm_Renderer_ArraySmarty extends HTML_QuickForm_Renderer_Array
{
/**
* The Smarty template engine instance
* @var object
*/
var $_tpl = null;
 
/**
* Current element index
* @var integer
*/
var $_elementIdx = 0;
 
/**
* The current element index inside a group
* @var integer
*/
var $_groupElementIdx = 0;
 
/**
* How to handle the required tag for required fields
* @var string
* @see setRequiredTemplate()
*/
var $_required = '';
 
/**
* How to handle error messages in form validation
* @var string
* @see setErrorTemplate()
*/
var $_error = '';
 
/**
* Constructor
*
* @param object reference to the Smarty template engine instance
* @param bool true: render an array of labels to many labels, $key 0 to 'label' and the oterh to "label_$key"
* @access public
*/
function HTML_QuickForm_Renderer_ArraySmarty(&$tpl, $staticLabels = false)
{
$this->HTML_QuickForm_Renderer_Array(true, $staticLabels);
$this->_tpl =& $tpl;
} // end constructor
 
/**
* Called when visiting a header element
*
* @param object An HTML_QuickForm_header element being visited
* @access public
* @return void
*/
function renderHeader(&$header)
{
if ($name = $header->getName()) {
$this->_ary['header'][$name] = $header->toHtml();
} else {
$this->_ary['header'][$this->_sectionCount] = $header->toHtml();
}
$this->_currentSection = $this->_sectionCount++;
} // end func renderHeader
 
/**
* Called when visiting a group, before processing any group elements
*
* @param object An HTML_QuickForm_group object being visited
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
*/
function startGroup(&$group, $required, $error)
{
parent::startGroup($group, $required, $error);
$this->_groupElementIdx = 1;
} // end func startGroup
 
/**
* Creates an array representing an element containing
* the key for storing this
*
* @access private
* @param object An HTML_QuickForm_element object
* @param bool Whether an element is required
* @param string Error associated with the element
* @return array
*/
function _elementToArray(&$element, $required, $error)
{
$ret = parent::_elementToArray($element, $required, $error);
 
if ('group' == $ret['type']) {
$ret['html'] = $element->toHtml();
// we don't need the elements, see the array structure
unset($ret['elements']);
}
if (($required || $error) && !empty($this->_required)){
$this->_renderRequired($ret['label'], $ret['html'], $required, $error);
}
if ($error && !empty($this->_error)) {
$this->_renderError($ret['label'], $ret['html'], $error);
$ret['error'] = $error;
}
// create keys for elements grouped by native group or name
if (strstr($ret['name'], '[') or $this->_currentGroup) {
preg_match('/([^]]*)\\[([^]]*)\\]/', $ret['name'], $matches);
if (isset($matches[1])) {
$sKeysSub = substr_replace($ret['name'], '', 0, strlen($matches[1]));
$sKeysSub = str_replace(
array('[' , ']', '[\'\']'),
array('[\'', '\']', '[]' ),
$sKeysSub
);
$sKeys = '[\'' . $matches[1] . '\']' . $sKeysSub;
} else {
$sKeys = '[\'' . $ret['name'] . '\']';
}
// special handling for elements in native groups
if ($this->_currentGroup) {
// skip unnamed group items unless radios: no name -> no static access
// identification: have the same key string as the parent group
if ($this->_currentGroup['keys'] == $sKeys and 'radio' != $ret['type']) {
return false;
}
// reduce string of keys by remove leading group keys
if (0 === strpos($sKeys, $this->_currentGroup['keys'])) {
$sKeys = substr_replace($sKeys, '', 0, strlen($this->_currentGroup['keys']));
}
}
// element without a name
} elseif ($ret['name'] == '') {
$sKeys = '[\'element_' . $this->_elementIdx . '\']';
// other elements
} else {
$sKeys = '[\'' . $ret['name'] . '\']';
}
// for radios: add extra key from value
if ('radio' == $ret['type'] and substr($sKeys, -2) != '[]') {
$sKeys .= '[\'' . $ret['value'] . '\']';
}
$this->_elementIdx++;
$ret['keys'] = $sKeys;
return $ret;
} // end func _elementToArray
 
/**
* Stores an array representation of an element in the form array
*
* @access private
* @param array Array representation of an element
* @return void
*/
function _storeArray($elAry)
{
if ($elAry) {
$sKeys = $elAry['keys'];
unset($elAry['keys']);
// where should we put this element...
if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
$toEval = '$this->_currentGroup' . $sKeys . ' = $elAry;';
} else {
$toEval = '$this->_ary' . $sKeys . ' = $elAry;';
}
eval($toEval);
}
return;
}
 
/**
* Called when an element is required
*
* This method will add the required tag to the element label and/or the element html
* such as defined with the method setRequiredTemplate.
*
* @param string The element label
* @param string The element html rendering
* @param boolean The element required
* @param string The element error
* @see setRequiredTemplate()
* @access private
* @return void
*/
function _renderRequired(&$label, &$html, &$required, &$error)
{
$this->_tpl->assign(array(
'label' => $label,
'html' => $html,
'required' => $required,
'error' => $error
));
if (!empty($label) && strpos($this->_required, $this->_tpl->left_delimiter . '$label') !== false) {
$label = $this->_tplFetch($this->_required);
}
if (!empty($html) && strpos($this->_required, $this->_tpl->left_delimiter . '$html') !== false) {
$html = $this->_tplFetch($this->_required);
}
$this->_tpl->clear_assign(array('label', 'html', 'required'));
} // end func _renderRequired
 
/**
* Called when an element has a validation error
*
* This method will add the error message to the element label or the element html
* such as defined with the method setErrorTemplate. If the error placeholder is not found
* in the template, the error will be displayed in the form error block.
*
* @param string The element label
* @param string The element html rendering
* @param string The element error
* @see setErrorTemplate()
* @access private
* @return void
*/
function _renderError(&$label, &$html, &$error)
{
$this->_tpl->assign(array('label' => '', 'html' => '', 'error' => $error));
$error = $this->_tplFetch($this->_error);
$this->_tpl->assign(array('label' => $label, 'html' => $html));
 
if (!empty($label) && strpos($this->_error, $this->_tpl->left_delimiter . '$label') !== false) {
$label = $this->_tplFetch($this->_error);
} elseif (!empty($html) && strpos($this->_error, $this->_tpl->left_delimiter . '$html') !== false) {
$html = $this->_tplFetch($this->_error);
}
$this->_tpl->clear_assign(array('label', 'html', 'error'));
} // end func _renderError
 
/**
* Process an template sourced in a string with Smarty
*
* Smarty has no core function to render a template given as a string.
* So we use the smarty eval plugin function to do this.
*
* @param string The template source
* @access private
* @return void
*/
function _tplFetch($tplSource)
{
if (!function_exists('smarty_function_eval')) {
require SMARTY_DIR . '/plugins/function.eval.php';
}
return smarty_function_eval(array('var' => $tplSource), $this->_tpl);
}// end func _tplFetch
 
/**
* Sets the way required elements are rendered
*
* You can use {$label} or {$html} placeholders to let the renderer know where
* where the element label or the element html are positionned according to the
* required tag. They will be replaced accordingly with the right value. You
* can use the full smarty syntax here, especially a custom modifier for I18N.
* For example:
* {if $required}<span style="color: red;">*</span>{/if}{$label|translate}
* will put a red star in front of the label if the element is required and
* translate the label.
*
*
* @param string The required element template
* @access public
* @return void
*/
function setRequiredTemplate($template)
{
$this->_required = $template;
} // end func setRequiredTemplate
 
/**
* Sets the way elements with validation errors are rendered
*
* You can use {$label} or {$html} placeholders to let the renderer know where
* where the element label or the element html are positionned according to the
* error message. They will be replaced accordingly with the right value.
* The error message will replace the {$error} placeholder.
* For example:
* {if $error}<span style="color: red;">{$error}</span>{/if}<br />{$html}
* will put the error message in red on top of the element html.
*
* If you want all error messages to be output in the main error block, use
* the {$form.errors} part of the rendered array that collects all raw error
* messages.
*
* If you want to place all error messages manually, do not specify {$html}
* nor {$label}.
*
* Groups can have special layouts. With this kind of groups, you have to
* place the formated error message manually. In this case, use {$form.group.error}
* where you want the formated error message to appear in the form.
*
* @param string The element error template
* @access public
* @return void
*/
function setErrorTemplate($template)
{
$this->_error = $template;
} // end func setErrorTemplate
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Renderer/ObjectFlexy.php
New file
0,0 → 1,261
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Ron McClain <ron@humaniq.com> |
// +----------------------------------------------------------------------+
//
// $Id: ObjectFlexy.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/Renderer/Object.php");
 
/**
* QuickForm renderer for Flexy template engine, static version.
*
* A static renderer for HTML_Quickform. Makes a QuickFormFlexyObject
* from the form content suitable for use with a Flexy template
*
* Usage:
* $form =& new HTML_QuickForm('form', 'POST');
* $template =& new HTML_Template_Flexy();
* $renderer =& new HTML_QuickForm_Renderer_ObjectFlexy(&$template);
* $renderer->setHtmlTemplate("html.html");
* $renderer->setLabelTemplate("label.html");
* $form->accept($renderer);
* $view = new StdClass;
* $view->form = $renderer->toObject();
* $template->compile("mytemplate.html");
*
* Based on the code for HTML_QuickForm_Renderer_ArraySmarty
*
* @see QuickFormFlexyObject
* @access public
*/
class HTML_QuickForm_Renderer_ObjectFlexy extends HTML_QuickForm_Renderer_Object
{
/**
* HTML_Template_Flexy instance
* @var object $_flexy
*/
var $_flexy;
 
/**
* Current element index
* @var integer $_elementIdx
*/
var $_elementIdx;
 
/**
* The current element index inside a group
* @var integer $_groupElementIdx
*/
var $_groupElementIdx = 0;
 
/**
* Name of template file for form html
* @var string $_html
* @see setRequiredTemplate()
*/
var $_html = '';
 
/**
* Name of template file for form labels
* @var string $label
* @see setErrorTemplate()
*/
var $label = '';
 
/**
* Class of the element objects, so you can add your own
* element methods
* @var string $_elementType
*/
var $_elementType = 'QuickformFlexyElement';
 
/**
* Constructor
*
* @param $flexy object HTML_Template_Flexy instance
* @public
*/
function HTML_QuickForm_Renderer_ObjectFlexy(&$flexy)
{
$this->HTML_QuickForm_Renderer_Object(true);
$this->_obj = new QuickformFlexyForm();
$this->_flexy =& $flexy;
} // end constructor
 
function renderHeader(&$header)
{
if($name = $header->getName()) {
$this->_obj->header->$name = $header->toHtml();
} else {
$this->_obj->header[$this->_sectionCount] = $header->toHtml();
}
$this->_currentSection = $this->_sectionCount++;
} // end func renderHeader
 
function startGroup(&$group, $required, $error)
{
parent::startGroup($group, $required, $error);
$this->_groupElementIdx = 1;
} //end func startGroup
 
/**
* Creates an object representing an element containing
* the key for storing this
*
* @access private
* @param element object An HTML_QuickForm_element object
* @param required bool Whether an element is required
* @param error string Error associated with the element
* @return object
*/
function _elementToObject(&$element, $required, $error)
{
$ret = parent::_elementToObject($element, $required, $error);
if($ret->type == 'group') {
$ret->html = $element->toHtml();
unset($ret->elements);
}
if(!empty($this->_label)) {
$this->_renderLabel($ret);
}
 
if(!empty($this->_html)) {
$this->_renderHtml($ret);
$ret->error = $error;
}
 
// Create an element key from the name
if (false !== ($pos = strpos($ret->name, '[')) || is_object($this->_currentGroup)) {
if (!$pos) {
$keys = '->{\'' . $ret->name . '\'}';
} else {
$keys = '->{\'' . str_replace(array('[', ']'), array('\'}->{\'', ''), $ret->name) . '\'}';
}
// special handling for elements in native groups
if (is_object($this->_currentGroup)) {
// skip unnamed group items unless radios: no name -> no static access
// identification: have the same key string as the parent group
if ($this->_currentGroup->keys == $keys && 'radio' != $ret->type) {
return false;
}
// reduce string of keys by remove leading group keys
if (0 === strpos($keys, $this->_currentGroup->keys)) {
$keys = substr_replace($keys, '', 0, strlen($this->_currentGroup->keys));
}
}
} elseif (0 == strlen($ret->name)) {
$keys = '->{\'element_' . $this->_elementIdx . '\'}';
} else {
$keys = '->{\'' . $ret->name . '\'}';
}
// for radios: add extra key from value
if ('radio' == $ret->type && '[]' != substr($keys, -2)) {
$keys .= '->{\'' . $ret->value . '\'}';
}
$ret->keys = $keys;
$this->_elementIdx++;
return $ret;
}
 
/**
* Stores an object representation of an element in the
* QuickformFormObject instance
*
* @access private
* @param elObj object Object representation of an element
* @return void
*/
function _storeObject($elObj)
{
if ($elObj) {
$keys = $elObj->keys;
unset($elObj->keys);
if(is_object($this->_currentGroup) && ('group' != $elObj->type)) {
$code = '$this->_currentGroup' . $keys . ' = $elObj;';
} else {
$code = '$this->_obj' . $keys . ' = $elObj;';
}
eval($code);
}
}
 
/**
* Set the filename of the template to render html elements.
* In your template, {html} is replaced by the unmodified html.
* If the element is required, {required} will be true.
* Eg.
* {if:error}
* <font color="red" size="1">{error:h}</font><br />
* {end:}
* {html:h}
*
* @access public
* @param template string Filename of template
* @return void
*/
function setHtmlTemplate($template)
{
$this->_html = $template;
}
 
/**
* Set the filename of the template to render form labels
* In your template, {label} is replaced by the unmodified label.
* {error} will be set to the error, if any. {required} will
* be true if this is a required field
* Eg.
* {if:required}
* <font color="orange" size="1">*</font>
* {end:}
* {label:h}
*
* @access public
* @param template string Filename of template
* @return void
*/
function setLabelTemplate($template)
{
$this->_label = $template;
}
 
function _renderLabel(&$ret)
{
$this->_flexy->compile($this->_label);
$ret->label = $this->_flexy->bufferedOutputObject($ret);
}
 
function _renderHtml(&$ret)
{
$this->_flexy->compile($this->_html);
$ret->html = $this->_flexy->bufferedOutputObject($ret);
}
} // end class HTML_QuickForm_Renderer_ObjectFlexy
 
/**
* Adds nothing to QuickformForm, left for backwards compatibility
*/
class QuickformFlexyForm extends QuickformForm
{
}
 
/**
* Adds nothing to QuickformElement, left for backwards compatibility
*/
class QuickformFlexyElement extends QuickformElement
{
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/advcheckbox.php
New file
0,0 → 1,283
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: advcheckbox.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/checkbox.php');
 
/**
* HTML class for an advanced checkbox type field
*
* Basically this fixes a problem that HTML has had
* where checkboxes can only pass a single value (the
* value of the checkbox when checked). A value for when
* the checkbox is not checked cannot be passed, and
* furthermore the checkbox variable doesn't even exist if
* the checkbox was submitted unchecked.
*
* It works by creating a hidden field with the passed-in name
* and creating the checkbox with no name, but with a javascript
* onclick which sets the value of the hidden field.
*
* @author Jason Rust <jrust@php.net>
* @since 2.0
* @access public
*/
class HTML_QuickForm_advcheckbox extends HTML_QuickForm_checkbox
{
// {{{ properties
 
/**
* The values passed by the hidden elment
*
* @var array
* @access private
*/
var $_values = null;
 
/**
* The default value
*
* @var boolean
* @access private
*/
var $_currentValue = null;
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label
* @param string $text (optional)Text to put after the checkbox
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @param mixed $values (optional)Values to pass if checked or not checked
*
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_advcheckbox($elementName=null, $elementLabel=null, $text=null, $attributes=null, $values=null)
{
$this->HTML_QuickForm_checkbox($elementName, $elementLabel, $text, $attributes);
$this->setValues($values);
} //end constructor
// }}}
// {{{ getPrivateName()
 
/**
* Gets the pribate name for the element
*
* @param string $elementName The element name to make private
*
* @access public
* @return string
*/
function getPrivateName($elementName)
{
return '__'.$elementName;
}
 
// }}}
// {{{ getOnclickJs()
 
/**
* Create the javascript for the onclick event which will
* set the value of the hidden field
*
* @param string $elementName The element name
*
* @access public
* @return string
*/
function getOnclickJs($elementName)
{
$onclickJs = 'if (this.checked) { this.form[\''.$elementName.'\'].value=\''.addcslashes($this->_values[1], '\'').'\'; }';
$onclickJs .= 'else { this.form[\''.$elementName.'\'].value=\''.addcslashes($this->_values[0], '\'').'\'; }';
return $onclickJs;
}
 
// }}}
// {{{ setValues()
 
/**
* Sets the values used by the hidden element
*
* @param mixed $values The values, either a string or an array
*
* @access public
* @return void
*/
function setValues($values)
{
if (empty($values)) {
// give it default checkbox behavior
$this->_values = array('', 1);
} elseif (is_scalar($values)) {
// if it's string, then assume the value to
// be passed is for when the element is checked
$this->_values = array('', $values);
} else {
$this->_values = $values;
}
$this->setChecked($this->_currentValue == $this->_values[1]);
}
 
// }}}
// {{{ setValue()
 
/**
* Sets the element's value
*
* @param mixed Element's value
* @access public
*/
function setValue($value)
{
$this->setChecked(isset($this->_values[1]) && $value == $this->_values[1]);
$this->_currentValue = $value;
}
 
// }}}
// {{{ getValue()
 
/**
* Returns the element's value
*
* @access public
* @return mixed
*/
function getValue()
{
if (is_array($this->_values)) {
return $this->_values[$this->getChecked()? 1: 0];
} else {
return null;
}
}
 
// }}}
// {{{ toHtml()
 
/**
* Returns the checkbox element in HTML
* and the additional hidden element in HTML
*
* @access public
* @return string
*/
function toHtml()
{
if ($this->_flagFrozen) {
return parent::toHtml();
} else {
$oldName = $this->getName();
$oldJs = $this->getAttribute('onclick');
$this->updateAttributes(array(
'name' => $this->getPrivateName($oldName),
'onclick' => $this->getOnclickJs($oldName) . ' ' . $oldJs
));
$html = parent::toHtml() . '<input' .
$this->_getAttrString(array(
'type' => 'hidden',
'name' => $oldName,
'value' => $this->getValue()
)) . ' />';
// revert the name and JS, in case this method will be called once more
$this->updateAttributes(array(
'name' => $oldName,
'onclick' => $oldJs
));
return $html;
}
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Unlike checkbox, this has to append a hidden input in both
* checked and non-checked states
*/
function getFrozenHtml()
{
return ($this->getChecked()? '<tt>[x]</tt>': '<tt>[ ]</tt>') .
$this->_getPersistantData();
}
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
// constant values override both default and submitted ones
// default values are overriden by submitted
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_submitValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
}
if (null !== $value) {
$this->setValue($value);
}
break;
default:
parent::onQuickFormEvent($event, $arg, $caller);
}
return true;
} // end func onQuickFormLoad
 
// }}}
// {{{ exportValue()
 
/**
* This element has a value even if it is not checked, thus we override
* checkbox's behaviour here
*/
function exportValue(&$submitValues, $assoc)
{
$value = $this->_findValue($submitValues);
if (null === $value) {
$value = $this->getValue();
} elseif (is_array($this->_values) && ($value != $this->_values[0]) && ($value != $this->_values[1])) {
$value = null;
}
return $this->_prepareValue($value, $assoc);
}
// }}}
} //end class HTML_QuickForm_advcheckbox
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Required.php
New file
0,0 → 1,52
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Required.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Rule.php');
 
/**
* Required elements validation
* @version 1.0
*/
class HTML_QuickForm_Rule_Required extends HTML_QuickForm_Rule
{
/**
* Checks if an element is empty
*
* @param string $value Value to check
* @param mixed $options Not used yet
* @access public
* @return boolean true if value is not empty
*/
function validate($value, $options = null)
{
if ((string)$value == '') {
return false;
}
return true;
} // end func validate
 
 
function getValidationScript($options = null)
{
return array('', "{jsVar} == ''");
} // end func getValidationScript
 
} // end class HTML_QuickForm_Rule_Required
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Compare.php
New file
0,0 → 1,95
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Alexey Borzov <avb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: Compare.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/Rule.php';
 
/**
* Rule to compare two form fields
*
* The most common usage for this is to ensure that the password
* confirmation field matches the password field
*
* @access public
* @package HTML_QuickForm
* @version $Revision: 1.2 $
*/
class HTML_QuickForm_Rule_Compare extends HTML_QuickForm_Rule
{
/**
* Possible operators to use
* @var array
* @access private
*/
var $_operators = array(
'eq' => '==',
'neq' => '!=',
'gt' => '>',
'gte' => '>=',
'lt' => '<',
'lte' => '<='
);
 
 
/**
* Returns the operator to use for comparing the values
*
* @access private
* @param string operator name
* @return string operator to use for validation
*/
function _findOperator($name)
{
if (empty($name)) {
return '==';
} elseif (isset($this->_operators[$name])) {
return $this->_operators[$name];
} elseif (in_array($name, $this->_operators)) {
return $name;
} else {
return '==';
}
}
 
 
function validate($values, $operator = null)
{
$operator = $this->_findOperator($operator);
if ('==' != $operator && '!=' != $operator) {
$compareFn = create_function('$a, $b', 'return floatval($a) ' . $operator . ' floatval($b);');
} else {
$compareFn = create_function('$a, $b', 'return $a ' . $operator . ' $b;');
}
return $compareFn($values[0], $values[1]);
}
 
 
function getValidationScript($operator = null)
{
$operator = $this->_findOperator($operator);
if ('==' != $operator && '!=' != $operator) {
$check = "!(Number({jsVar}[0]) {$operator} Number({jsVar}[1]))";
} else {
$check = "!({jsVar}[0] {$operator} {jsVar}[1])";
}
return array('', "'' != {jsVar}[0] && {$check}");
}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Email.php
New file
0,0 → 1,61
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Email.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Rule.php');
 
/**
* Email validation rule
* @version 1.0
*/
class HTML_QuickForm_Rule_Email extends HTML_QuickForm_Rule
{
var $regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/';
 
/**
* Validates an email address
*
* @param string $email Email address
* @param boolean $checkDomain True if dns check should be performed
* @access public
* @return boolean true if email is valid
*/
function validate($email, $checkDomain = false)
{
if (preg_match($this->regex, $email)) {
if ($checkDomain && function_exists('checkdnsrr')) {
$tokens = explode('@', $email);
if (checkdnsrr($tokens[1], 'MX') || checkdnsrr($tokens[1], 'A')) {
return true;
}
return false;
}
return true;
}
return false;
} // end func validate
 
 
function getValidationScript($options = null)
{
return array(" var regex = " . $this->regex . ";\n", "{jsVar} != '' && !regex.test({jsVar})");
} // end func getValidationScript
 
} // end class HTML_QuickForm_Rule_Email
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Regex.php
New file
0,0 → 1,89
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Regex.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Rule.php');
 
/**
* Validates values using regular expressions
* @version 1.0
*/
class HTML_QuickForm_Rule_Regex extends HTML_QuickForm_Rule
{
/**
* Array of regular expressions
*
* Array is in the format:
* $_data['rulename'] = 'pattern';
*
* @var array
* @access private
*/
var $_data = array(
'lettersonly' => '/^[a-zA-Z]+$/',
'alphanumeric' => '/^[a-zA-Z0-9]+$/',
'numeric' => '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/',
'nopunctuation' => '/^[^().\/\*\^\?#!@$%+=,\"\'><~\[\]{}]+$/',
'nonzero' => '/^-?[1-9][0-9]*/'
);
 
/**
* Validates a value using a regular expression
*
* @param string $value Value to be checked
* @param string $regex Regular expression
* @access public
* @return boolean true if value is valid
*/
function validate($value, $regex = null)
{
if (isset($this->_data[$this->name])) {
if (!preg_match($this->_data[$this->name], $value)) {
return false;
}
} else {
if (!preg_match($regex, $value)) {
return false;
}
}
return true;
} // end func validate
 
/**
* Adds new regular expressions to the list
*
* @param string $name Name of rule
* @param string $pattern Regular expression pattern
* @access public
*/
function addData($name, $pattern)
{
$this->_data[$name] = $pattern;
} // end func addData
 
 
function getValidationScript($options = null)
{
$regex = isset($this->_data[$this->name]) ? $this->_data[$this->name] : $options;
 
return array(" var regex = " . $regex . ";\n", "{jsVar} != '' && !regex.test({jsVar})");
} // end func getValidationScript
 
} // end class HTML_QuickForm_Rule_Regex
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Callback.php
New file
0,0 → 1,113
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Callback.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Rule.php');
 
/**
* Validates values using callback functions or methods
* @version 1.0
*/
class HTML_QuickForm_Rule_Callback extends HTML_QuickForm_Rule
{
/**
* Array of callbacks
*
* Array is in the format:
* $_data['rulename'] = array('functionname', 'classname');
* If the callback is not a method, then the class name is not set.
*
* @var array
* @access private
*/
var $_data = array();
 
/**
* Whether to use BC mode for specific rules
*
* Previous versions of QF passed element's name as a first parameter
* to validation functions, but not to validation methods. This behaviour
* is emulated if you are using 'function' as rule type when registering.
*
* @var array
* @access private
*/
var $_BCMode = array();
 
/**
* Validates a value using a callback
*
* @param string $value Value to be checked
* @param mixed $options Options for callback
* @access public
* @return boolean true if value is valid
*/
function validate($value, $options = null)
{
if (isset($this->_data[$this->name])) {
$callback = $this->_data[$this->name];
if (isset($callback[1])) {
return call_user_func(array($callback[1], $callback[0]), $value, $options);
} elseif ($this->_BCMode[$this->name]) {
return $callback[0]('', $value, $options);
} else {
return $callback[0]($value, $options);
}
} elseif (is_callable($options)) {
return call_user_func($options, $value);
} else {
return true;
}
} // end func validate
 
/**
* Adds new callbacks to the callbacks list
*
* @param string $name Name of rule
* @param string $callback Name of function or method
* @param string $class Name of class containing the method
* @param bool $BCMode Backwards compatibility mode
* @access public
*/
function addData($name, $callback, $class = null, $BCMode = false)
{
if (!empty($class)) {
$this->_data[$name] = array($callback, $class);
} else {
$this->_data[$name] = array($callback);
}
$this->_BCMode[$name] = $BCMode;
} // end func addData
 
 
function getValidationScript($options = null)
{
if (isset($this->_data[$this->name])) {
$callback = $this->_data[$this->name][0];
$params = ($this->_BCMode[$this->name]? "'', {jsVar}": '{jsVar}') .
(isset($options)? ", '{$options}'": '');
} else {
$callback = is_array($options)? $options[1]: $options;
$params = '{jsVar}';
}
return array('', "{jsVar} != '' && !{$callback}({$params})");
} // end func getValidationScript
 
} // end class HTML_QuickForm_Rule_Callback
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/Rule/Range.php
New file
0,0 → 1,64
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: Range.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/Rule.php');
 
/**
* Validates values using range comparison
* @version 1.0
*/
class HTML_QuickForm_Rule_Range extends HTML_QuickForm_Rule
{
/**
* Validates a value using a range comparison
*
* @param string $value Value to be checked
* @param mixed $options Int for length, array for range
* @access public
* @return boolean true if value is valid
*/
function validate($value, $options)
{
$length = strlen($value);
switch ($this->name) {
case 'minlength': return ($length >= $options);
case 'maxlength': return ($length <= $options);
default: return ($length >= $options[0] && $length <= $options[1]);
}
} // end func validate
 
 
function getValidationScript($options = null)
{
switch ($this->name) {
case 'minlength':
$test = '{jsVar}.length < '.$options;
break;
case 'maxlength':
$test = '{jsVar}.length > '.$options;
break;
default:
$test = '({jsVar}.length < '.$options[0].' || {jsVar}.length > '.$options[1].')';
}
return array('', "{jsVar} != '' && {$test}");
} // end func getValidationScript
 
} // end class HTML_QuickForm_Rule_Range
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/image.php
New file
0,0 → 1,119
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: image.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a image type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_image extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Element name attribute
* @param string $src (optional)Image source
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_image($elementName=null, $src='', $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
$this->setType('image');
$this->setSource($src);
} // end class constructor
 
// }}}
// {{{ setSource()
 
/**
* Sets source for image element
*
* @param string $src source for image element
* @since 1.0
* @access public
* @return void
*/
function setSource($src)
{
$this->updateAttributes(array('src' => $src));
} // end func setSource
 
// }}}
// {{{ setBorder()
 
/**
* Sets border size for image element
*
* @param string $border border for image element
* @since 1.0
* @access public
* @return void
*/
function setBorder($border)
{
$this->updateAttributes(array('border' => $border));
} // end func setBorder
 
// }}}
// {{{ setAlign()
 
/**
* Sets alignment for image element
*
* @param string $align alignment for image element
* @since 1.0
* @access public
* @return void
*/
function setAlign($align)
{
$this->updateAttributes(array('align' => $align));
} // end func setAlign
 
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
 
} // end class HTML_QuickForm_image
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/reset.php
New file
0,0 → 1,72
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: reset.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a reset type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.1
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_reset extends HTML_QuickForm_input
{
// {{{ constructor
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $value (optional)Input field value
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_reset($elementName=null, $value=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
$this->setValue($value);
$this->setType('reset');
} //end constructor
 
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
 
} //end class HTML_QuickForm_reset
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/text.php
New file
0,0 → 1,91
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: text.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a text field
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_text extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_text($elementName=null, $elementLabel=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->setType('text');
} //end constructor
// }}}
// {{{ setSize()
 
/**
* Sets size of text field
*
* @param string $size Size of text field
* @since 1.3
* @access public
* @return void
*/
function setSize($size)
{
$this->updateAttributes(array('size'=>$size));
} //end func setSize
 
// }}}
// {{{ setMaxlength()
 
/**
* Sets maxlength of text field
*
* @param string $maxlength Maximum length of text field
* @since 1.3
* @access public
* @return void
*/
function setMaxlength($maxlength)
{
$this->updateAttributes(array('maxlength'=>$maxlength));
} //end func setMaxlength
 
// }}}
} //end class HTML_QuickForm_text
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/checkbox.php
New file
0,0 → 1,268
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: checkbox.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a checkbox type field
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.1
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_checkbox extends HTML_QuickForm_input
{
// {{{ properties
 
/**
* Checkbox display text
* @var string
* @since 1.1
* @access private
*/
var $_text = '';
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field value
* @param string $text (optional)Checkbox display text
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_checkbox($elementName=null, $elementLabel=null, $text='', $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_text = $text;
$this->setType('checkbox');
$this->updateAttributes(array('value'=>1));
$this->_generateId();
} //end constructor
// }}}
// {{{ setChecked()
 
/**
* Sets whether a checkbox is checked
*
* @param bool $checked Whether the field is checked or not
* @since 1.0
* @access public
* @return void
*/
function setChecked($checked)
{
if (!$checked) {
$this->removeAttribute('checked');
} else {
$this->updateAttributes(array('checked'=>'checked'));
}
} //end func setChecked
 
// }}}
// {{{ getChecked()
 
/**
* Returns whether a checkbox is checked
*
* @since 1.0
* @access public
* @return bool
*/
function getChecked()
{
return (bool)$this->getAttribute('checked');
} //end func getChecked
// }}}
// {{{ toHtml()
 
/**
* Returns the checkbox element in HTML
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
if (0 == strlen($this->_text)) {
$label = '';
} elseif ($this->_flagFrozen) {
$label = $this->_text;
} else {
$label = '<label for="' . $this->getAttribute('id') . '">' . $this->_text . '</label>';
}
return HTML_QuickForm_input::toHtml() . $label;
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @since 1.0
* @access public
* @return string
*/
function getFrozenHtml()
{
if ($this->getChecked()) {
return '<tt>[x]</tt>' .
$this->_getPersistantData();
} else {
return '<tt>[ ]</tt>';
}
} //end func getFrozenHtml
 
// }}}
// {{{ setText()
 
/**
* Sets the checkbox text
*
* @param string $text
* @since 1.1
* @access public
* @return void
*/
function setText($text)
{
$this->_text = $text;
} //end func setText
 
// }}}
// {{{ getText()
 
/**
* Returns the checkbox text
*
* @since 1.1
* @access public
* @return string
*/
function getText()
{
return $this->_text;
} //end func getText
 
// }}}
// {{{ setValue()
 
/**
* Sets the value of the form element
*
* @param string $value Default value of the form element
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
return $this->setChecked($value);
} // end func setValue
 
// }}}
// {{{ getValue()
 
/**
* Returns the value of the form element
*
* @since 1.0
* @access public
* @return bool
*/
function getValue()
{
return $this->getChecked();
} // end func getValue
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
// constant values override both default and submitted ones
// default values are overriden by submitted
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
// if no boxes were checked, then there is no value in the array
// yet we don't want to display default value in this case
if ($caller->isSubmitted()) {
$value = $this->_findValue($caller->_submitValues);
} else {
$value = $this->_findValue($caller->_defaultValues);
}
}
if (null !== $value) {
$this->setChecked($value);
}
break;
case 'setGroupValue':
$this->setChecked($arg);
break;
default:
parent::onQuickFormEvent($event, $arg, $caller);
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ exportValue()
 
/**
* Return true if the checkbox is checked, null if it is not checked (getValue() returns false)
*/
function exportValue(&$submitValues, $assoc = false)
{
$value = $this->_findValue($submitValues);
if (null === $value) {
$value = $this->getChecked()? true: null;
}
return $this->_prepareValue($value, $assoc);
}
// }}}
} //end class HTML_QuickForm_checkbox
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/hierselect.php
New file
0,0 → 1,565
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 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: Herim Vasquez <vasquezh@iro.umontreal.ca> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// | Alexey Borzov <avb@php.net>
// +----------------------------------------------------------------------+
//
// $Id: hierselect.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/group.php');
require_once('HTML/QuickForm/select.php');
 
/**
* Class to dynamically create two or more HTML Select elements
* The first select changes the content of the second select and so on.
* This element is considered as a group. Selects will be named
* groupName[0], groupName[1], groupName[2]...
*
* @author Herim Vasquez <vasquezh@iro.umontreal.ca>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_hierselect extends HTML_QuickForm_group
{
// {{{ properties
 
/**
* Options for all the select elements
*
* Format is a bit more complex as we need to know which options
* are related to the ones in the previous select:
*
* Ex:
* // first select
* $select1[0] = 'Pop';
* $select1[1] = 'Classical';
* $select1[2] = 'Funeral doom';
*
* // second select
* $select2[0][0] = 'Red Hot Chil Peppers';
* $select2[0][1] = 'The Pixies';
* $select2[1][0] = 'Wagner';
* $select2[1][1] = 'Strauss';
* $select2[2][0] = 'Pantheist';
* $select2[2][1] = 'Skepticism';
*
* // If only need two selects
* // - and using the depracated functions
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setMainOptions($select1);
* $sel->setSecOptions($select2);
*
* // - and using the new setOptions function
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setOptions(array($select1, $select2));
*
* // If you have a third select with prices for the cds
* $select3[0][0][0] = '15.00$';
* $select3[0][0][1] = '17.00$';
* etc
*
* // You can now use
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setOptions(array($select1, $select2, $select3));
*
* @var array
* @access private
*/
var $_options = array();
/**
* Number of select elements on this group
*
* @var int
* @access private
*/
var $_nbElements = 0;
 
/**
* The javascript used to set and change the options
*
* @var string
* @access private
*/
var $_js = '';
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label in form
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array. Date format is passed along the attributes.
* @param mixed $separator (optional)Use a string for one separator,
* use an array to alternate the separators.
* @access public
* @return void
*/
function HTML_QuickForm_hierselect($elementName=null, $elementLabel=null, $attributes=null, $separator=null)
{
$this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
if (isset($separator)) {
$this->_separator = $separator;
}
$this->_type = 'hierselect';
$this->_appendName = true;
} //end constructor
 
// }}}
// {{{ setOptions()
 
/**
* Initialize the array structure containing the options for each select element.
* Call the functions that actually do the magic.
*
* @param array $options Array of options defining each element
*
* @access public
* @return void
*/
function setOptions($options)
{
$this->_options = $options;
 
if (empty($this->_elements)) {
$this->_nbElements = count($this->_options);
$this->_createElements();
} else {
// setDefaults has probably been called before this function
// check if all elements have been created
$totalNbElements = count($this->_options);
for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
$this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
$this->_nbElements++;
}
}
$this->_setOptions();
} // end func setMainOptions
 
// }}}
// {{{ setMainOptions()
/**
* Sets the options for the first select element. Deprecated. setOptions() should be used.
*
* @param array $array Options for the first select element
*
* @access public
* @return void
*/
function setMainOptions($array)
{
$this->_options[0] = $array;
 
if (empty($this->_elements)) {
$this->_nbElements = 2;
$this->_createElements();
}
} // end func setMainOptions
// }}}
// {{{ setSecOptions()
/**
* Sets the options for the second select element. Deprecated. setOptions() should be used.
* The main _options array is initialized and the _setOptions function is called.
*
* @param array $array Options for the second select element
*
* @access public
* @return void
*/
function setSecOptions($array)
{
$this->_options[1] = $array;
 
if (empty($this->_elements)) {
$this->_nbElements = 2;
$this->_createElements();
} else {
// setDefaults has probably been called before this function
// check if all elements have been created
$totalNbElements = 2;
for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
$this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
$this->_nbElements++;
}
}
$this->_setOptions();
} // end func setSecOptions
// }}}
// {{{ _setOptions()
/**
* Sets the options for each select element
*
* @access private
* @return void
*/
function _setOptions()
{
$toLoad = '';
foreach (array_keys($this->_elements) AS $key) {
$array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;");
if (is_array($array)) {
$select =& $this->_elements[$key];
$select->_options = array();
$select->loadArray($array);
 
$value = is_array($v = $select->getValue()) ? $v[0] : key($array);
$toLoad .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $value) . '\']';
}
}
} // end func _setOptions
// }}}
// {{{ setValue()
 
/**
* Sets values for group's elements
*
* @param array $value An array of 2 or more values, for the first,
* the second, the third etc. select
*
* @access public
* @return void
*/
function setValue($value)
{
$this->_nbElements = count($value);
parent::setValue($value);
$this->_setOptions();
} // end func setValue
// }}}
// {{{ _createElements()
 
/**
* Creates all the elements for the group
*
* @access private
* @return void
*/
function _createElements()
{
for ($i = 0; $i < $this->_nbElements; $i++) {
$this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
}
} // end func _createElements
 
// }}}
// {{{ toHtml()
 
function toHtml()
{
$this->_js = '';
if (!$this->_flagFrozen) {
// set the onchange attribute for each element except last
$keys = array_keys($this->_elements);
$onChange = array();
for ($i = 0; $i < count($keys) - 1; $i++) {
$select =& $this->_elements[$keys[$i]];
$onChange[$i] = $select->getAttribute('onchange');
$select->updateAttributes(
array('onchange' => '_hs_swapOptions(this.form, \'' . $this->_escapeString($this->getName()) . '\', ' . $keys[$i] . ');' . $onChange[$i])
);
}
// create the js function to call
if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) {
$this->_js .= <<<JAVASCRIPT
function _hs_findOptions(ary, keys)
{
var key = keys.shift();
if (!key in ary) {
return {};
} else if (0 == keys.length) {
return ary[key];
} else {
return _hs_findOptions(ary[key], keys);
}
}
 
function _hs_findSelect(form, groupName, selectIndex)
{
if (groupName+'['+ selectIndex +']' in form) {
return form[groupName+'['+ selectIndex +']'];
} else {
return form[groupName+'['+ selectIndex +'][]'];
}
}
 
function _hs_replaceOptions(ctl, optionList)
{
var j = 0;
ctl.options.length = 0;
for (i in optionList) {
ctl.options[j++] = new Option(optionList[i], i, false, false);
}
}
 
function _hs_setValue(ctl, value)
{
var testValue = {};
if (value instanceof Array) {
for (var i = 0; i < value.length; i++) {
testValue[value[i]] = true;
}
} else {
testValue[value] = true;
}
for (var i = 0; i < ctl.options.length; i++) {
if (ctl.options[i].value in testValue) {
ctl.options[i].selected = true;
}
}
}
 
function _hs_swapOptions(form, groupName, selectIndex)
{
var hsValue = [];
for (var i = 0; i <= selectIndex; i++) {
hsValue[i] = _hs_findSelect(form, groupName, i).value;
}
 
_hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1),
_hs_findOptions(_hs_options[groupName][selectIndex], hsValue));
if (selectIndex + 1 < _hs_options[groupName].length) {
_hs_swapOptions(form, groupName, selectIndex + 1);
}
}
 
function _hs_onReset(form, groupNames)
{
for (var i = 0; i < groupNames.length; i++) {
try {
for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) {
_hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]);
if (j < _hs_options[groupNames[i]].length) {
_hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1),
_hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1)));
}
}
} catch (e) {
if (!(e instanceof TypeError)) {
throw e;
}
}
}
}
 
function _hs_setupOnReset(form, groupNames)
{
setTimeout(function() { _hs_onReset(form, groupNames); }, 25);
}
 
function _hs_onReload()
{
var ctl;
for (var i = 0; i < document.forms.length; i++) {
for (var j in _hs_defaults) {
if (ctl = _hs_findSelect(document.forms[i], j, 0)) {
for (var k = 0; k < _hs_defaults[j].length; k++) {
_hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]);
}
}
}
}
 
if (_hs_prevOnload) {
_hs_prevOnload();
}
}
 
var _hs_prevOnload = null;
if (window.onload) {
_hs_prevOnload = window.onload;
}
window.onload = _hs_onReload;
 
var _hs_options = {};
var _hs_defaults = {};
 
JAVASCRIPT;
define('HTML_QUICKFORM_HIERSELECT_EXISTS', true);
}
// option lists
$jsParts = array();
for ($i = 1; $i < $this->_nbElements; $i++) {
$jsParts[] = $this->_convertArrayToJavascript($this->_options[$i]);
}
$this->_js .= "\n_hs_options['" . $this->_escapeString($this->getName()) . "'] = [\n" .
implode(",\n", $jsParts) .
"\n];\n";
// default value; if we don't actually have any values yet just use
// the first option (for single selects) or empty array (for multiple)
$values = array();
foreach (array_keys($this->_elements) as $key) {
if (is_array($v = $this->_elements[$key]->getValue())) {
$values[] = count($v) > 1? $v: $v[0];
} else {
// XXX: accessing the supposedly private _options array
$values[] = $this->_elements[$key]->getMultiple() || empty($this->_elements[$key]->_options[0])?
array():
$this->_elements[$key]->_options[0]['attr']['value'];
}
}
$this->_js .= "_hs_defaults['" . $this->_escapeString($this->getName()) . "'] = " .
$this->_convertArrayToJavascript($values, false) . ";\n";
}
include_once('HTML/QuickForm/Renderer/Default.php');
$renderer =& new HTML_QuickForm_Renderer_Default();
$renderer->setElementTemplate('{element}');
parent::accept($renderer);
 
if (!empty($onChange)) {
$keys = array_keys($this->_elements);
for ($i = 0; $i < count($keys) - 1; $i++) {
$this->_elements[$keys[$i]]->updateAttributes(array('onchange' => $onChange[$i]));
}
}
return (empty($this->_js)? '': "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>") .
$renderer->toHtml();
} // end func toHtml
 
// }}}
// {{{ accept()
 
function accept(&$renderer, $required = false, $error = null)
{
$renderer->renderElement($this, $required, $error);
} // end func accept
 
// }}}
// {{{ onQuickFormEvent()
 
function onQuickFormEvent($event, $arg, &$caller)
{
if ('updateValue' == $event) {
// we need to call setValue() so that the secondary option
// matches the main option
return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller);
} else {
$ret = parent::onQuickFormEvent($event, $arg, $caller);
// add onreset handler to form to properly reset hierselect (see bug #2970)
if ('addElement' == $event) {
$onReset = $caller->getAttribute('onreset');
if (strlen($onReset)) {
if (strpos($onReset, '_hs_setupOnReset')) {
$caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "', ", $onReset)));
} else {
$caller->updateAttributes(array('onreset' => "var temp = function() { {$onReset} } ; if (!temp()) { return false; } ; if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } "));
}
} else {
$caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } "));
}
}
return $ret;
}
} // end func onQuickFormEvent
 
// }}}
// {{{ _convertArrayToJavascript()
 
/**
* Converts PHP array to its Javascript analog
*
* @access private
* @param array PHP array to convert
* @param bool Generate Javascript object literal (default, works like PHP's associative array) or array literal
* @return string Javascript representation of the value
*/
function _convertArrayToJavascript($array, $assoc = true)
{
if (!is_array($array)) {
return $this->_convertScalarToJavascript($array);
} else {
$items = array();
foreach ($array as $key => $val) {
$item = $assoc? "'" . $this->_escapeString($key) . "': ": '';
if (is_array($val)) {
$item .= $this->_convertArrayToJavascript($val, $assoc);
} else {
$item .= $this->_convertScalarToJavascript($val);
}
$items[] = $item;
}
}
$js = implode(', ', $items);
return $assoc? '{ ' . $js . ' }': '[' . $js . ']';
}
// }}}
// {{{ _convertScalarToJavascript()
 
/**
* Converts PHP's scalar value to its Javascript analog
*
* @access private
* @param mixed PHP value to convert
* @return string Javascript representation of the value
*/
function _convertScalarToJavascript($val)
{
if (is_bool($val)) {
return $val ? 'true' : 'false';
} elseif (is_int($val) || is_double($val)) {
return $val;
} elseif (is_string($val)) {
return "'" . $this->_escapeString($val) . "'";
} elseif (is_null($val)) {
return 'null';
} else {
// don't bother
return '{}';
}
}
 
// }}}
// {{{ _escapeString()
 
/**
* Quotes the string so that it can be used in Javascript string constants
*
* @access private
* @param string
* @return string
*/
function _escapeString($str)
{
return strtr($str,array(
"\r" => '\r',
"\n" => '\n',
"\t" => '\t',
"'" => "\\'",
'"' => '\"',
'\\' => '\\\\'
));
}
 
// }}}
} // end class HTML_QuickForm_hierselect
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/static.php
New file
0,0 → 1,193
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: static.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/element.php");
 
/**
* HTML class for static data
*
* @author Wojciech Gdela <eltehaem@poczta.onet.pl>
* @access public
*/
class HTML_QuickForm_static extends HTML_QuickForm_element {
// {{{ properties
 
/**
* Display text
* @var string
* @access private
*/
var $_text = null;
 
// }}}
// {{{ constructor
/**
* Class constructor
*
* @param string $elementLabel (optional)Label
* @param string $text (optional)Display text
* @access public
* @return void
*/
function HTML_QuickForm_static($elementName=null, $elementLabel=null, $text=null)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel);
$this->_persistantFreeze = false;
$this->_type = 'static';
$this->_text = $text;
} //end constructor
// }}}
// {{{ setName()
 
/**
* Sets the element name
*
* @param string $name Element name
* @access public
* @return void
*/
function setName($name)
{
$this->updateAttributes(array('name'=>$name));
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @access public
* @return string
*/
function getName()
{
return $this->getAttribute('name');
} //end func getName
 
// }}}
// {{{ setText()
 
/**
* Sets the text
*
* @param string $text
* @access public
* @return void
*/
function setText($text)
{
$this->_text = $text;
} // end func setText
 
// }}}
// {{{ setValue()
 
/**
* Sets the text (uses the standard setValue call to emulate a form element.
*
* @param string $text
* @access public
* @return void
*/
function setValue($text)
{
$this->setText($text);
} // end func setValue
 
// }}}
// {{{ toHtml()
 
/**
* Returns the static text element in HTML
*
* @access public
* @return string
*/
function toHtml()
{
return $this->_getTabs() . $this->_text;
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @access public
* @return string
*/
function getFrozenHtml()
{
return $this->toHtml();
} //end func getFrozenHtml
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
* @throws
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
// do NOT use submitted values for static elements
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
if (null !== $value) {
$this->setValue($value);
}
break;
default:
parent::onQuickFormEvent($event, $arg, $caller);
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ exportValue()
 
/**
* We override this here because we don't want any values from static elements
*/
function exportValue(&$submitValues, $assoc = false)
{
return null;
}
// }}}
} //end class HTML_QuickForm_static
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/header.php
New file
0,0 → 1,65
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Alexey Borzov <borz_off@cs.msu.su> |
// +----------------------------------------------------------------------+
//
// $Id: header.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/static.php';
 
/**
* A pseudo-element used for adding headers to form
*
* @author Alexey Borzov <borz_off@cs.msu.su>
* @access public
*/
class HTML_QuickForm_header extends HTML_QuickForm_static
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName Header name
* @param string $text Header text
* @access public
* @return void
*/
function HTML_QuickForm_header($elementName = null, $text = null)
{
$this->HTML_QuickForm_static($elementName, null, $text);
$this->_type = 'header';
}
 
// }}}
// {{{ accept()
 
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @access public
* @return void
*/
function accept(&$renderer)
{
$renderer->renderHeader($this);
} // end func accept
 
// }}}
 
} //end class HTML_QuickForm_header
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/element.php
New file
0,0 → 1,479
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: element.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/Common.php');
 
/**
* Base class for form elements
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.3
* @since PHP4.04pl1
* @access public
* @abstract
*/
class HTML_QuickForm_element extends HTML_Common
{
// {{{ properties
 
/**
* Label of the field
* @var string
* @since 1.3
* @access private
*/
var $_label = '';
 
/**
* Form element type
* @var string
* @since 1.0
* @access private
*/
var $_type = '';
 
/**
* Flag to tell if element is frozen
* @var boolean
* @since 1.0
* @access private
*/
var $_flagFrozen = false;
 
/**
* Does the element support persistant data when frozen
* @var boolean
* @since 1.3
* @access private
*/
var $_persistantFreeze = false;
// }}}
// {{{ constructor
/**
* Class constructor
*
* @param string Name of the element
* @param mixed Label(s) for the element
* @param mixed Associative array of tag attributes or HTML attributes name="value" pairs
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_element($elementName=null, $elementLabel=null, $attributes=null)
{
HTML_Common::HTML_Common($attributes);
if (isset($elementName)) {
$this->setName($elementName);
}
if (isset($elementLabel)) {
$this->setLabel($elementLabel);
}
} //end constructor
// }}}
// {{{ apiVersion()
 
/**
* Returns the current API version
*
* @since 1.0
* @access public
* @return float
*/
function apiVersion()
{
return 2.0;
} // end func apiVersion
 
// }}}
// {{{ getType()
 
/**
* Returns element type
*
* @since 1.0
* @access public
* @return string
*/
function getType()
{
return $this->_type;
} // end func getType
 
// }}}
// {{{ setName()
 
/**
* Sets the input field name
*
* @param string $name Input field name attribute
* @since 1.0
* @access public
* @return void
*/
function setName($name)
{
// interface method
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @since 1.0
* @access public
* @return string
*/
function getName()
{
// interface method
} //end func getName
// }}}
// {{{ setValue()
 
/**
* Sets the value of the form element
*
* @param string $value Default value of the form element
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
// interface
} // end func setValue
 
// }}}
// {{{ getValue()
 
/**
* Returns the value of the form element
*
* @since 1.0
* @access public
* @return mixed
*/
function getValue()
{
// interface
return null;
} // end func getValue
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
$this->_flagFrozen = true;
} //end func freeze
 
// }}}
// {{{ unfreeze()
 
/**
* Unfreezes the element so that it becomes editable
*
* @access public
* @return void
* @since 3.2.4
*/
function unfreeze()
{
$this->_flagFrozen = false;
}
 
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @since 1.0
* @access public
* @return string
*/
function getFrozenHtml()
{
$value = $this->getValue();
return ('' != $value? htmlspecialchars($value): '&nbsp;') .
$this->_getPersistantData();
} //end func getFrozenHtml
// }}}
// {{{ _getPersistantData()
 
/**
* Used by getFrozenHtml() to pass the element's value if _persistantFreeze is on
*
* @access private
* @return string
*/
function _getPersistantData()
{
if (!$this->_persistantFreeze) {
return '';
} else {
$id = $this->getAttribute('id');
return '<input' . $this->_getAttrString(array(
'type' => 'hidden',
'name' => $this->getName(),
'value' => $this->getValue()
) + (isset($id)? array('id' => $id): array())) . ' />';
}
}
 
// }}}
// {{{ isFrozen()
 
/**
* Returns whether or not the element is frozen
*
* @since 1.3
* @access public
* @return bool
*/
function isFrozen()
{
return $this->_flagFrozen;
} // end func isFrozen
 
// }}}
// {{{ setPersistantFreeze()
 
/**
* Sets wether an element value should be kept in an hidden field
* when the element is frozen or not
*
* @param bool $persistant True if persistant value
* @since 2.0
* @access public
* @return void
*/
function setPersistantFreeze($persistant=false)
{
$this->_persistantFreeze = $persistant;
} //end func setPersistantFreeze
 
// }}}
// {{{ setLabel()
 
/**
* Sets display text for the element
*
* @param string $label Display text for the element
* @since 1.3
* @access public
* @return void
*/
function setLabel($label)
{
$this->_label = $label;
} //end func setLabel
 
// }}}
// {{{ getLabel()
 
/**
* Returns display text for the element
*
* @since 1.3
* @access public
* @return string
*/
function getLabel()
{
return $this->_label;
} //end func getLabel
 
// }}}
// {{{ _findValue()
 
/**
* Tries to find the element value from the values array
*
* @since 2.7
* @access private
* @return mixed
*/
function _findValue(&$values)
{
if (empty($values)) {
return null;
}
$elementName = $this->getName();
if (isset($values[$elementName])) {
return $values[$elementName];
} elseif (strpos($elementName, '[')) {
$myVar = "['" . str_replace(array(']', '['), array('', "']['"), $elementName) . "']";
return eval("return (isset(\$values$myVar)) ? \$values$myVar : null;");
} else {
return null;
}
} //end func _findValue
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'createElement':
$className = get_class($this);
$this->$className($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]);
break;
case 'addElement':
$this->onQuickFormEvent('createElement', $arg, $caller);
$this->onQuickFormEvent('updateValue', null, $caller);
break;
case 'updateValue':
// constant values override both default and submitted ones
// default values are overriden by submitted
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_submitValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
}
if (null !== $value) {
$this->setValue($value);
}
break;
case 'setGroupValue':
$this->setValue($arg);
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ accept()
 
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @param bool Whether an element is required
* @param string An error message associated with an element
* @access public
* @return void
*/
function accept(&$renderer, $required=false, $error=null)
{
$renderer->renderElement($this, $required, $error);
} // end func accept
 
// }}}
// {{{ _generateId()
 
/**
* Automatically generates and assigns an 'id' attribute for the element.
*
* Currently used to ensure that labels work on radio buttons and
* checkboxes. Per idea of Alexander Radivanovich.
*
* @access private
* @return void
*/
function _generateId()
{
static $idx = 1;
 
if (!$this->getAttribute('id')) {
$this->updateAttributes(array('id' => 'qf_' . substr(md5(microtime() . $idx++), 0, 6)));
}
} // end func _generateId
 
// }}}
// {{{ exportValue()
 
/**
* Returns a 'safe' element's value
*
* @param array array of submitted values to search
* @param bool whether to return the value as associative array
* @access public
* @return mixed
*/
function exportValue(&$submitValues, $assoc = false)
{
$value = $this->_findValue($submitValues);
if (null === $value) {
$value = $this->getValue();
}
return $this->_prepareValue($value, $assoc);
}
// }}}
// {{{ _prepareValue()
 
/**
* Used by exportValue() to prepare the value for returning
*
* @param mixed the value found in exportValue()
* @param bool whether to return the value as associative array
* @access private
* @return mixed
*/
function _prepareValue($value, $assoc)
{
if (null === $value) {
return null;
} elseif (!$assoc) {
return $value;
} else {
$name = $this->getName();
if (!strpos($name, '[')) {
return array($name => $value);
} else {
$valueAry = array();
$myIndex = "['" . str_replace(array(']', '['), array('', "']['"), $name) . "']";
eval("\$valueAry$myIndex = \$value;");
return $valueAry;
}
}
}
// }}}
} // end class HTML_QuickForm_element
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/hidden.php
New file
0,0 → 1,87
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: hidden.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a hidden type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_hidden extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $value (optional)Input field value
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_hidden($elementName=null, $value='', $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
$this->setType('hidden');
$this->setValue($value);
} //end constructor
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
// {{{ accept()
 
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @access public
* @return void
*/
function accept(&$renderer)
{
$renderer->renderHidden($this);
} // end func accept
 
// }}}
 
} //end class HTML_QuickForm_hidden
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/hiddenselect.php
New file
0,0 → 1,107
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: hiddenselect.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/select.php');
 
/**
* This class takes the same arguments as a select element, but instead
* of creating a select ring it creates hidden elements for all values
* already selected with setDefault or setConstant. This is useful if
* you have a select ring that you don't want visible, but you need all
* selected values to be passed.
*
* @author Isaac Shepard <ishepard@bsiweb.com>
*
* @version 1.0
* @since 2.1
* @access public
*/
class HTML_QuickForm_hiddenselect extends HTML_QuickForm_select
{
// {{{ constructor
/**
* Class constructor
*
* @param string Select name attribute
* @param mixed Label(s) for the select (not used)
* @param mixed Data to be used to populate options
* @param mixed Either a typical HTML attribute string or an associative array (not used)
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_hiddenselect($elementName=null, $elementLabel=null, $options=null, $attributes=null)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_type = 'hiddenselect';
if (isset($options)) {
$this->load($options);
}
} //end constructor
// }}}
// {{{ toHtml()
 
/**
* Returns the SELECT in HTML
*
* @since 1.0
* @access public
* @return string
* @throws
*/
function toHtml()
{
$tabs = $this->_getTabs();
$name = $this->getPrivateName();
$strHtml = '';
 
foreach ($this->_values as $key => $val) {
for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
if ($val == $this->_options[$i]['attr']['value']) {
$strHtml .= $tabs . '<input' . $this->_getAttrString(array(
'type' => 'hidden',
'name' => $name,
'value' => $val
)) . " />\n" ;
}
}
}
 
return $strHtml;
} //end func toHtml
// }}}
// {{{ accept()
 
/**
* This is essentially a hidden element and should be rendered as one
*/
function accept(&$renderer)
{
$renderer->renderHidden($this);
}
 
// }}}
} //end class HTML_QuickForm_hiddenselect
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/group.php
New file
0,0 → 1,579
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: group.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/element.php");
 
/**
* HTML class for a form element group
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_group extends HTML_QuickForm_element
{
// {{{ properties
/**
* Name of the element
* @var string
* @since 1.0
* @access private
*/
var $_name = '';
 
/**
* Array of grouped elements
* @var array
* @since 1.0
* @access private
*/
var $_elements = array();
 
/**
* String to separate elements
* @var mixed
* @since 2.5
* @access private
*/
var $_separator = null;
 
/**
* Required elements in this group
* @var array
* @since 2.5
* @access private
*/
var $_required = array();
 
/**
* Whether to change elements' names to $groupName[$elementName] or leave them as is
* @var bool
* @since 3.0
* @access private
*/
var $_appendName = true;
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Group name
* @param array $elementLabel (optional)Group label
* @param array $elements (optional)Group elements
* @param mixed $separator (optional)Use a string for one separator,
* use an array to alternate the separators.
* @param bool $appendName (optional)whether to change elements' names to
* the form $groupName[$elementName] or leave
* them as is.
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_group($elementName=null, $elementLabel=null, $elements=null, $separator=null, $appendName = true)
{
$this->HTML_QuickForm_element($elementName, $elementLabel);
$this->_type = 'group';
if (isset($elements) && is_array($elements)) {
$this->setElements($elements);
}
if (isset($separator)) {
$this->_separator = $separator;
}
if (isset($appendName)) {
$this->_appendName = $appendName;
}
} //end constructor
// }}}
// {{{ setName()
 
/**
* Sets the group name
*
* @param string $name Group name
* @since 1.0
* @access public
* @return void
*/
function setName($name)
{
$this->_name = $name;
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the group name
*
* @since 1.0
* @access public
* @return string
*/
function getName()
{
return $this->_name;
} //end func getName
 
// }}}
// {{{ setValue()
 
/**
* Sets values for group's elements
*
* @param mixed Values for group's elements
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
$this->_createElementsIfNotExist();
foreach (array_keys($this->_elements) as $key) {
if (!$this->_appendName) {
$v = $this->_elements[$key]->_findValue($value);
if (null !== $v) {
$this->_elements[$key]->onQuickFormEvent('setGroupValue', $v, $this);
}
 
} else {
$elementName = $this->_elements[$key]->getName();
$index = strlen($elementName) ? $elementName : $key;
if (is_array($value)) {
if (isset($value[$index])) {
$this->_elements[$key]->onQuickFormEvent('setGroupValue', $value[$index], $this);
}
} elseif (isset($value)) {
$this->_elements[$key]->onQuickFormEvent('setGroupValue', $value, $this);
}
}
}
} //end func setValue
// }}}
// {{{ getValue()
 
/**
* Returns the value of the group
*
* @since 1.0
* @access public
* @return mixed
*/
function getValue()
{
$value = null;
foreach (array_keys($this->_elements) as $key) {
$element =& $this->_elements[$key];
switch ($element->getType()) {
case 'radio':
$v = $element->getChecked()? $element->getValue(): null;
break;
case 'checkbox':
$v = $element->getChecked()? true: null;
break;
default:
$v = $element->getValue();
}
if (null !== $v) {
$elementName = $element->getName();
if (is_null($elementName)) {
$value = $v;
} else {
if (!is_array($value)) {
$value = is_null($value)? array(): array($value);
}
if ('' === $elementName) {
$value[] = $v;
} else {
$value[$elementName] = $v;
}
}
}
}
return $value;
} // end func getValue
 
// }}}
// {{{ setElements()
 
/**
* Sets the grouped elements
*
* @param array $elements Array of elements
* @since 1.1
* @access public
* @return void
*/
function setElements($elements)
{
$this->_elements = array_values($elements);
if ($this->_flagFrozen) {
$this->freeze();
}
} // end func setElements
 
// }}}
// {{{ getElements()
 
/**
* Gets the grouped elements
*
* @since 2.4
* @access public
* @return array
*/
function &getElements()
{
$this->_createElementsIfNotExist();
return $this->_elements;
} // end func getElements
 
// }}}
// {{{ getGroupType()
 
/**
* Gets the group type based on its elements
* Will return 'mixed' if elements contained in the group
* are of different types.
*
* @access public
* @return string group elements type
*/
function getGroupType()
{
$this->_createElementsIfNotExist();
$prevType = '';
foreach (array_keys($this->_elements) as $key) {
$type = $this->_elements[$key]->getType();
if ($type != $prevType && $prevType != '') {
return 'mixed';
}
$prevType = $type;
}
return $type;
} // end func getGroupType
 
// }}}
// {{{ toHtml()
 
/**
* Returns Html for the group
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
include_once('HTML/QuickForm/Renderer/Default.php');
$renderer =& new HTML_QuickForm_Renderer_Default();
$renderer->setElementTemplate('{element}');
$this->accept($renderer);
return $renderer->toHtml();
} //end func toHtml
// }}}
// {{{ getElementName()
 
/**
* Returns the element name inside the group such as found in the html form
*
* @param mixed $index Element name or element index in the group
* @since 3.0
* @access public
* @return mixed string with element name, false if not found
*/
function getElementName($index)
{
$this->_createElementsIfNotExist();
$elementName = false;
if (is_int($index) && isset($this->_elements[$index])) {
$elementName = $this->_elements[$index]->getName();
if (isset($elementName) && $elementName == '') {
$elementName = $index;
}
if ($this->_appendName) {
if (is_null($elementName)) {
$elementName = $this->getName();
} else {
$elementName = $this->getName().'['.$elementName.']';
}
}
 
} elseif (is_string($index)) {
foreach (array_keys($this->_elements) as $key) {
$elementName = $this->_elements[$key]->getName();
if ($index == $elementName) {
if ($this->_appendName) {
$elementName = $this->getName().'['.$elementName.']';
}
break;
} elseif ($this->_appendName && $this->getName().'['.$elementName.']' == $index) {
break;
}
}
}
return $elementName;
} //end func getElementName
 
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @since 1.3
* @access public
* @return string
*/
function getFrozenHtml()
{
$flags = array();
$this->_createElementsIfNotExist();
foreach (array_keys($this->_elements) as $key) {
if (false === ($flags[$key] = $this->_elements[$key]->isFrozen())) {
$this->_elements[$key]->freeze();
}
}
$html = $this->toHtml();
foreach (array_keys($this->_elements) as $key) {
if (!$flags[$key]) {
$this->_elements[$key]->unfreeze();
}
}
return $html;
} //end func getFrozenHtml
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
$this->_createElementsIfNotExist();
foreach (array_keys($this->_elements) as $key) {
if ($this->_appendName) {
$elementName = $this->_elements[$key]->getName();
if (is_null($elementName)) {
$this->_elements[$key]->setName($this->getName());
} elseif ('' === $elementName) {
$this->_elements[$key]->setName($this->getName() . '[' . $key . ']');
} else {
$this->_elements[$key]->setName($this->getName() . '[' . $elementName . ']');
}
}
$this->_elements[$key]->onQuickFormEvent('updateValue', $arg, $caller);
if ($this->_appendName) {
$this->_elements[$key]->setName($elementName);
}
}
break;
 
default:
parent::onQuickFormEvent($event, $arg, $caller);
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ accept()
 
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
*/
function accept(&$renderer, $required = false, $error = null)
{
$this->_createElementsIfNotExist();
$renderer->startGroup($this, $required, $error);
$name = $this->getName();
foreach (array_keys($this->_elements) as $key) {
$element =& $this->_elements[$key];
if ($this->_appendName) {
$elementName = $element->getName();
if (isset($elementName)) {
$element->setName($name . '['. (strlen($elementName)? $elementName: $key) .']');
} else {
$element->setName($name);
}
}
 
$required = !$element->isFrozen() && in_array($element->getName(), $this->_required);
 
$element->accept($renderer, $required);
 
// restore the element's name
if ($this->_appendName) {
$element->setName($elementName);
}
}
$renderer->finishGroup($this);
} // end func accept
 
// }}}
// {{{ exportValue()
 
/**
* As usual, to get the group's value we access its elements and call
* their exportValue() methods
*/
function exportValue(&$submitValues, $assoc = false)
{
$value = null;
foreach (array_keys($this->_elements) as $key) {
$elementName = $this->_elements[$key]->getName();
if ($this->_appendName) {
if (is_null($elementName)) {
$this->_elements[$key]->setName($this->getName());
} elseif ('' === $elementName) {
$this->_elements[$key]->setName($this->getName() . '[' . $key . ']');
} else {
$this->_elements[$key]->setName($this->getName() . '[' . $elementName . ']');
}
}
$v = $this->_elements[$key]->exportValue($submitValues, $assoc);
if ($this->_appendName) {
$this->_elements[$key]->setName($elementName);
}
if (null !== $v) {
// Make $value an array, we will use it like one
if (null === $value) {
$value = array();
}
if ($assoc) {
// just like HTML_QuickForm::exportValues()
$value = HTML_QuickForm::arrayMerge($value, $v);
} else {
// just like getValue(), but should work OK every time here
if (is_null($elementName)) {
$value = $v;
} elseif ('' === $elementName) {
$value[] = $v;
} else {
$value[$elementName] = $v;
}
}
}
}
// do not pass the value through _prepareValue, we took care of this already
return $value;
}
 
// }}}
// {{{ _createElements()
 
/**
* Creates the group's elements.
*
* This should be overriden by child classes that need to create their
* elements. The method will be called automatically when needed, calling
* it from the constructor is discouraged as the constructor is usually
* called _twice_ on element creation, first time with _no_ parameters.
*
* @access private
* @abstract
*/
function _createElements()
{
// abstract
}
 
// }}}
// {{{ _createElementsIfNotExist()
 
/**
* A wrapper around _createElements()
*
* This method calls _createElements() if the group's _elements array
* is empty. It also performs some updates, e.g. freezes the created
* elements if the group is already frozen.
*
* @access private
*/
function _createElementsIfNotExist()
{
if (empty($this->_elements)) {
$this->_createElements();
if ($this->_flagFrozen) {
$this->freeze();
}
}
}
 
// }}}
// {{{ freeze()
 
function freeze()
{
parent::freeze();
foreach (array_keys($this->_elements) as $key) {
$this->_elements[$key]->freeze();
}
}
 
// }}}
// {{{ unfreeze()
 
function unfreeze()
{
parent::unfreeze();
foreach (array_keys($this->_elements) as $key) {
$this->_elements[$key]->unfreeze();
}
}
 
// }}}
// {{{ setPersistantFreeze()
 
function setPersistantFreeze($persistant = false)
{
parent::setPersistantFreeze($persistant);
foreach (array_keys($this->_elements) as $key) {
$this->_elements[$key]->setPersistantFreeze($persistant);
}
}
 
// }}}
} //end class HTML_QuickForm_group
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/link.php
New file
0,0 → 1,192
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
 
require_once 'HTML/QuickForm/static.php';
 
/**
* HTML class for a link type field
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_link extends HTML_QuickForm_static
{
// {{{ properties
 
/**
* Link display text
* @var string
* @since 1.0
* @access private
*/
var $_text = "";
 
// }}}
// {{{ constructor
/**
* Class constructor
*
* @param string $elementLabel (optional)Link label
* @param string $href (optional)Link href
* @param string $text (optional)Link display text
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
* @throws
*/
function HTML_QuickForm_link($elementName=null, $elementLabel=null, $href=null, $text=null, $attributes=null)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = false;
$this->_type = 'link';
$this->setHref($href);
$this->_text = $text;
} //end constructor
// }}}
// {{{ setName()
 
/**
* Sets the input field name
*
* @param string $name Input field name attribute
* @since 1.0
* @access public
* @return void
* @throws
*/
function setName($name)
{
$this->updateAttributes(array('name'=>$name));
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @since 1.0
* @access public
* @return string
* @throws
*/
function getName()
{
return $this->getAttribute('name');
} //end func getName
 
// }}}
// {{{ setValue()
 
/**
* Sets value for textarea element
*
* @param string $value Value for password element
* @since 1.0
* @access public
* @return void
* @throws
*/
function setValue($value)
{
return;
} //end func setValue
// }}}
// {{{ getValue()
 
/**
* Returns the value of the form element
*
* @since 1.0
* @access public
* @return void
* @throws
*/
function getValue()
{
return;
} // end func getValue
 
// }}}
// {{{ setHref()
 
/**
* Sets the links href
*
* @param string $href
* @since 1.0
* @access public
* @return void
* @throws
*/
function setHref($href)
{
$this->updateAttributes(array('href'=>$href));
} // end func setHref
 
// }}}
// {{{ toHtml()
 
/**
* Returns the textarea element in HTML
*
* @since 1.0
* @access public
* @return string
* @throws
*/
function toHtml()
{
$tabs = $this->_getTabs();
$html = "$tabs<a".$this->_getAttrString($this->_attributes).">";
$html .= $this->_text;
$html .= "</a>";
return $html;
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags (in this case, value is changed to a mask)
*
* @since 1.0
* @access public
* @return string
* @throws
*/
function getFrozenHtml()
{
return;
} //end func getFrozenHtml
 
// }}}
 
} //end class HTML_QuickForm_textarea
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/radio.php
New file
0,0 → 1,244
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: radio.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once('HTML/QuickForm/input.php');
 
/**
* HTML class for a radio type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.1
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_radio extends HTML_QuickForm_input
{
// {{{ properties
 
/**
* Radio display text
* @var string
* @since 1.1
* @access private
*/
var $_text = '';
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string Input field name attribute
* @param mixed Label(s) for a field
* @param string Text to display near the radio
* @param string Input field value
* @param mixed Either a typical HTML attribute string or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_radio($elementName=null, $elementLabel=null, $text=null, $value=null, $attributes=null)
{
$this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
if (isset($value)) {
$this->setValue($value);
}
$this->_persistantFreeze = true;
$this->setType('radio');
$this->_text = $text;
$this->_generateId();
} //end constructor
// }}}
// {{{ setChecked()
 
/**
* Sets whether radio button is checked
*
* @param bool $checked Whether the field is checked or not
* @since 1.0
* @access public
* @return void
*/
function setChecked($checked)
{
if (!$checked) {
$this->removeAttribute('checked');
} else {
$this->updateAttributes(array('checked'=>'checked'));
}
} //end func setChecked
 
// }}}
// {{{ getChecked()
 
/**
* Returns whether radio button is checked
*
* @since 1.0
* @access public
* @return string
*/
function getChecked()
{
return $this->getAttribute('checked');
} //end func getChecked
// }}}
// {{{ toHtml()
 
/**
* Returns the radio element in HTML
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
if (0 == strlen($this->_text)) {
$label = '';
} elseif ($this->_flagFrozen) {
$label = $this->_text;
} else {
$label = '<label for="' . $this->getAttribute('id') . '">' . $this->_text . '</label>';
}
return HTML_QuickForm_input::toHtml() . $label;
} //end func toHtml
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags
*
* @since 1.0
* @access public
* @return string
*/
function getFrozenHtml()
{
if ($this->getChecked()) {
return '<tt>(x)</tt>' .
$this->_getPersistantData();
} else {
return '<tt>( )</tt>';
}
} //end func getFrozenHtml
 
// }}}
// {{{ setText()
 
/**
* Sets the radio text
*
* @param string $text Text to display near the radio button
* @since 1.1
* @access public
* @return void
*/
function setText($text)
{
$this->_text = $text;
} //end func setText
 
// }}}
// {{{ getText()
 
/**
* Returns the radio text
*
* @since 1.1
* @access public
* @return string
*/
function getText()
{
return $this->_text;
} //end func getText
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
*/
function onQuickFormEvent($event, $arg, &$caller)
{
switch ($event) {
case 'updateValue':
// constant values override both default and submitted ones
// default values are overriden by submitted
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_submitValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
}
if ($value == $this->getValue()) {
$this->setChecked(true);
} else {
$this->setChecked(false);
}
break;
case 'setGroupValue':
if ($arg == $this->getValue()) {
$this->setChecked(true);
} else {
$this->setChecked(false);
}
break;
default:
parent::onQuickFormEvent($event, $arg, $caller);
}
return true;
} // end func onQuickFormLoad
 
// }}}
// {{{ exportValue()
 
/**
* Returns the value attribute if the radio is checked, null if it is not
*/
function exportValue(&$submitValues, $assoc = false)
{
$value = $this->_findValue($submitValues);
if (null === $value) {
$value = $this->getChecked()? $this->getValue(): null;
} elseif ($value != $this->getValue()) {
$value = null;
}
return $this->_prepareValue($value, $assoc);
}
// }}}
} //end class HTML_QuickForm_radio
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/input.php
New file
0,0 → 1,202
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: input.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/element.php");
 
/**
* Base class for input form elements
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
* @abstract
*/
class HTML_QuickForm_input extends HTML_QuickForm_element
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string Input field name attribute
* @param mixed Label(s) for the input field
* @param mixed Either a typical HTML attribute string or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_input($elementName=null, $elementLabel=null, $attributes=null)
{
$this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
} //end constructor
 
// }}}
// {{{ setType()
 
/**
* Sets the element type
*
* @param string $type Element type
* @since 1.0
* @access public
* @return void
*/
function setType($type)
{
$this->_type = $type;
$this->updateAttributes(array('type'=>$type));
} // end func setType
// }}}
// {{{ setName()
 
/**
* Sets the input field name
*
* @param string $name Input field name attribute
* @since 1.0
* @access public
* @return void
*/
function setName($name)
{
$this->updateAttributes(array('name'=>$name));
} //end func setName
// }}}
// {{{ getName()
 
/**
* Returns the element name
*
* @since 1.0
* @access public
* @return string
*/
function getName()
{
return $this->getAttribute('name');
} //end func getName
// }}}
// {{{ setValue()
 
/**
* Sets the value of the form element
*
* @param string $value Default value of the form element
* @since 1.0
* @access public
* @return void
*/
function setValue($value)
{
$this->updateAttributes(array('value'=>$value));
} // end func setValue
 
// }}}
// {{{ getValue()
 
/**
* Returns the value of the form element
*
* @since 1.0
* @access public
* @return string
*/
function getValue()
{
return $this->getAttribute('value');
} // end func getValue
// }}}
// {{{ toHtml()
 
/**
* Returns the input field in HTML
*
* @since 1.0
* @access public
* @return string
*/
function toHtml()
{
if ($this->_flagFrozen) {
return $this->getFrozenHtml();
} else {
return $this->_getTabs() . '<input' . $this->_getAttrString($this->_attributes) . ' />';
}
} //end func toHtml
 
// }}}
// {{{ onQuickFormEvent()
 
/**
* Called by HTML_QuickForm whenever form event is made on this element
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @since 1.0
* @access public
* @return void
* @throws
*/
function onQuickFormEvent($event, $arg, &$caller)
{
// do not use submit values for button-type elements
$type = $this->getType();
if (('updateValue' != $event) ||
('submit' != $type && 'reset' != $type && 'image' != $type && 'button' != $type)) {
parent::onQuickFormEvent($event, $arg, $caller);
} else {
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
if (null !== $value) {
$this->setValue($value);
}
}
return true;
} // end func onQuickFormEvent
 
// }}}
// {{{ exportValue()
 
/**
* We don't need values from button-type elements (except submit) and files
*/
function exportValue(&$submitValues, $assoc = false)
{
$type = $this->getType();
if ('reset' == $type || 'image' == $type || 'button' == $type || 'file' == $type) {
return null;
} else {
return parent::exportValue($submitValues, $assoc);
}
}
// }}}
} // end class HTML_QuickForm_element
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/RuleRegistry.php
New file
0,0 → 1,333
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Alexey Borzov <borz_off@cs.msu.su> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: RuleRegistry.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
/**
* Registers rule objects and uses them for validation
*
*/
class HTML_QuickForm_RuleRegistry
{
/**
* Array containing references to used rules
* @var array
* @access private
*/
var $_rules = array();
 
 
/**
* Returns a singleton of HTML_QuickForm_RuleRegistry
*
* Usually, only one RuleRegistry object is needed, this is the reason
* why it is recommended to use this method to get the validation object.
*
* @access public
* @static
* @return object Reference to the HTML_QuickForm_RuleRegistry singleton
*/
function &singleton()
{
static $obj;
if (!isset($obj)) {
$obj = new HTML_QuickForm_RuleRegistry();
}
return $obj;
} // end func singleton
 
/**
* Registers a new validation rule
*
* In order to use a custom rule in your form, you need to register it
* first. For regular expressions, one can directly use the 'regex' type
* rule in addRule(), this is faster than registering the rule.
*
* Functions and methods can be registered. Use the 'function' type.
* When registering a method, specify the class name as second parameter.
*
* You can also register an HTML_QuickForm_Rule subclass with its own
* validate() method.
*
* @param string $ruleName Name of validation rule
* @param string $type Either: 'regex', 'function' or null
* @param string $data1 Name of function, regular expression or
* HTML_QuickForm_Rule object class name
* @param string $data2 Object parent of above function or HTML_QuickForm_Rule file path
* @access public
* @return void
*/
function registerRule($ruleName, $type, $data1, $data2 = null)
{
$type = strtolower($type);
if ($type == 'regex') {
// Regular expression
$rule =& $this->getRule('regex');
$rule->addData($ruleName, $data1);
$GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = $GLOBALS['_HTML_QuickForm_registered_rules']['regex'];
 
} elseif ($type == 'function' || $type == 'callback') {
// Callback function
$rule =& $this->getRule('callback');
$rule->addData($ruleName, $data1, $data2, 'function' == $type);
$GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = $GLOBALS['_HTML_QuickForm_registered_rules']['callback'];
 
} elseif (is_object($data1)) {
// An instance of HTML_QuickForm_Rule
$this->_rules[strtolower(get_class($data1))] = $data1;
$GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = array(strtolower(get_class($data1)), null);
 
} else {
// Rule class name
$GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = array(strtolower($data1), $data2);
}
} // end func registerRule
 
/**
* Returns a reference to the requested rule object
*
* @param string $ruleName Name of the requested rule
* @access public
* @return object
*/
function &getRule($ruleName)
{
list($class, $path) = $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName];
 
if (!isset($this->_rules[$class])) {
if (!empty($path)) {
include_once($path);
}
$this->_rules[$class] =& new $class();
}
$this->_rules[$class]->setName($ruleName);
return $this->_rules[$class];
} // end func getRule
 
/**
* Performs validation on the given values
*
* @param string $ruleName Name of the rule to be used
* @param mixed $values Can be a scalar or an array of values
* to be validated
* @param mixed $options Options used by the rule
* @param mixed $multiple Whether to validate an array of values altogether
* @access public
* @return mixed true if no error found, int of valid values (when an array of values is given) or false if error
*/
function validate($ruleName, $values, $options = null, $multiple = false)
{
$rule =& $this->getRule($ruleName);
 
if (is_array($values) && !$multiple) {
$result = 0;
foreach ($values as $value) {
if ($rule->validate($value, $options) === true) {
$result++;
}
}
return ($result == 0) ? false : $result;
} else {
return $rule->validate($values, $options);
}
} // end func validate
 
/**
* Returns the validation test in javascript code
*
* @param mixed Element(s) the rule applies to
* @param string Element name, in case $element is not array
* @param array Rule data
* @access public
* @return string JavaScript for the rule
*/
function getValidationScript(&$element, $elementName, $ruleData)
{
$reset = (isset($ruleData['reset'])) ? $ruleData['reset'] : false;
$rule =& $this->getRule($ruleData['type']);
if (!is_array($element)) {
list($jsValue, $jsReset) = $this->_getJsValue($element, $elementName, $reset, null);
} else {
$jsValue = " value = new Array();\n";
$jsReset = '';
for ($i = 0; $i < count($element); $i++) {
list($tmp_value, $tmp_reset) = $this->_getJsValue($element[$i], $element[$i]->getName(), $reset, $i);
$jsValue .= "\n" . $tmp_value;
$jsReset .= $tmp_reset;
}
}
$jsField = isset($ruleData['group'])? $ruleData['group']: $elementName;
list ($jsPrefix, $jsCheck) = $rule->getValidationScript($ruleData['format']);
if (!isset($ruleData['howmany'])) {
$js = $jsValue . "\n" . $jsPrefix .
" if (" . str_replace('{jsVar}', 'value', $jsCheck) . " && !errFlag['{$jsField}']) {\n" .
" errFlag['{$jsField}'] = true;\n" .
" _qfMsg = _qfMsg + '\\n - {$ruleData['message']}';\n" .
$jsReset .
" }\n";
} else {
$js = $jsValue . "\n" . $jsPrefix .
" var res = 0;\n" .
" for (var i = 0; i < value.length; i++) {\n" .
" if (!(" . str_replace('{jsVar}', 'value[i]', $jsCheck) . ")) {\n" .
" res++;\n" .
" }\n" .
" }\n" .
" if (res < {$ruleData['howmany']} && !errFlag['{$jsField}']) {\n" .
" errFlag['{$jsField}'] = true;\n" .
" _qfMsg = _qfMsg + '\\n - {$ruleData['message']}';\n" .
$jsReset .
" }\n";
}
return $js;
} // end func getValidationScript
 
 
/**
* Returns JavaScript to get and to reset the element's value
*
* @access private
* @param object HTML_QuickForm_element element being processed
* @param string element's name
* @param bool whether to generate JavaScript to reset the value
* @param integer value's index in the array (only used for multielement rules)
* @return array first item is value javascript, second is reset
*/
function _getJsValue(&$element, $elementName, $reset = false, $index = null)
{
$jsIndex = isset($index)? '[' . $index . ']': '';
$tmp_reset = $reset? " var field = frm.elements['$elementName'];\n": '';
if (is_a($element, 'html_quickform_group')) {
$value = " _qfGroups['{$elementName}'] = {";
$elements =& $element->getElements();
for ($i = 0, $count = count($elements); $i < $count; $i++) {
$append = ($elements[$i]->getType() == 'select' && $elements[$i]->getMultiple())? '[]': '';
$value .= "'" . $element->getElementName($i) . $append . "': true" .
($i < $count - 1? ', ': '');
}
$value .=
"};\n" .
" value{$jsIndex} = new Array();\n" .
" var valueIdx = 0;\n" .
" for (var i = 0; i < frm.elements.length; i++) {\n" .
" var _element = frm.elements[i];\n" .
" if (_element.name in _qfGroups['{$elementName}']) {\n" .
" switch (_element.type) {\n" .
" case 'checkbox':\n" .
" case 'radio':\n" .
" if (_element.checked) {\n" .
" value{$jsIndex}[valueIdx++] = _element.value;\n" .
" }\n" .
" break;\n" .
" case 'select-one':\n" .
" if (-1 != _element.selectedIndex) {\n" .
" value{$jsIndex}[valueIdx++] = _element.options[_element.selectedIndex].value;\n" .
" }\n" .
" break;\n" .
" case 'select-multiple':\n" .
" var tmpVal = new Array();\n" .
" var tmpIdx = 0;\n" .
" for (var j = 0; j < _element.options.length; j++) {\n" .
" if (_element.options[j].selected) {\n" .
" tmpVal[tmpIdx++] = _element.options[j].value;\n" .
" }\n" .
" }\n" .
" if (tmpIdx > 0) {\n" .
" value{$jsIndex}[valueIdx++] = tmpVal;\n" .
" }\n" .
" break;\n" .
" default:\n" .
" value{$jsIndex}[valueIdx++] = _element.value;\n" .
" }\n" .
" }\n" .
" }\n";
if ($reset) {
$tmp_reset =
" for (var i = 0; i < frm.elements.length; i++) {\n" .
" var _element = frm.elements[i];\n" .
" if (_element.name in _qfGroups['{$elementName}']) {\n" .
" switch (_element.type) {\n" .
" case 'checkbox':\n" .
" case 'radio':\n" .
" _element.checked = _element.defaultChecked;\n" .
" break;\n" .
" case 'select-one':\n" .
" case 'select-multiple:\n" .
" for (var j = 0; j < _element.options.length; j++) {\n" .
" _element.options[j].selected = _element.options[j].defaultSelected;\n" .
" }\n" .
" break;\n" .
" default:\n" .
" _element.value = _element.defaultValue;\n" .
" }\n" .
" }\n" .
" }\n";
}
 
} elseif ($element->getType() == 'select') {
if ($element->getMultiple()) {
$elementName .= '[]';
$value =
" value{$jsIndex} = new Array();\n" .
" var valueIdx = 0;\n" .
" for (var i = 0; i < frm.elements['{$elementName}'].options.length; i++) {\n" .
" if (frm.elements['{$elementName}'].options[i].selected) {\n" .
" value{$jsIndex}[valueIdx++] = frm.elements['{$elementName}'].options[i].value;\n" .
" }\n" .
" }\n";
} else {
$value = " value{$jsIndex} = frm.elements['{$elementName}'].selectedIndex == -1? '': frm.elements['{$elementName}'].options[frm.elements['{$elementName}'].selectedIndex].value;\n";
}
if ($reset) {
$tmp_reset .=
" for (var i = 0; i < field.options.length; i++) {\n" .
" field.options[i].selected = field.options[i].defaultSelected;\n" .
" }\n";
}
 
} elseif ($element->getType() == 'checkbox' && !is_a($element, 'html_quickform_advcheckbox')) {
$value = " if (frm.elements['$elementName'].checked) {\n" .
" value{$jsIndex} = '1';\n" .
" } else {\n" .
" value{$jsIndex} = '';\n" .
" }";
$tmp_reset .= ($reset) ? " field.checked = field.defaultChecked;\n" : '';
 
} elseif ($element->getType() == 'radio') {
$value = " value{$jsIndex} = '';\n" .
" for (var i = 0; i < frm.elements['$elementName'].length; i++) {\n" .
" if (frm.elements['$elementName'][i].checked) {\n" .
" value{$jsIndex} = frm.elements['$elementName'][i].value;\n" .
" }\n" .
" }";
if ($reset) {
$tmp_reset .= " for (var i = 0; i < field.length; i++) {\n" .
" field[i].checked = field[i].defaultChecked;\n" .
" }";
}
 
} else {
$value = " value{$jsIndex} = frm.elements['$elementName'].value;";
$tmp_reset .= ($reset) ? " field.value = field.defaultValue;\n" : '';
}
return array($value, $tmp_reset);
}
} // end class HTML_QuickForm_RuleRegistry
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/autocomplete.php
New file
0,0 → 1,249
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Matteo Di Giovinazzo <matteodg@infinito.it> |
// | |
// | For the JavaScript code thanks to Martin Honnen and |
// | Nicholas C. Zakas |
// | See: |
// | http://www.faqts.com/knowledge_base/view.phtml/aid/13562 |
// | and |
// | http://www.sitepoint.com/article/1220 |
// +----------------------------------------------------------------------+
//
// $Id: autocomplete.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
 
require_once("HTML/QuickForm/text.php");
 
 
/**
* Class to dynamically create an HTML input text element that
* at every keypressed javascript event, check in an array of options
* if there's a match and autocomplete the text in case of match.
*
* Ex:
* $autocomplete =& $form->addElement('autocomplete', 'fruit', 'Favourite fruit:');
* $options = array("Apple", "Orange", "Pear", "Strawberry");
* $autocomplete->setOptions($options);
*
* @author Matteo Di Giovinazzo <matteodg@infinito.it>
*/
class HTML_QuickForm_autocomplete extends HTML_QuickForm_text
{
// {{{ properties
 
/**
* Options for the autocomplete input text element
*
* @var array
* @access private
*/
var $_options = array();
 
/**
* "One-time" javascript (containing functions), see bug #4611
*
* @var string
* @access private
*/
var $_js = '';
 
// }}}
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label in form
* @param array $options (optional)Autocomplete options
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array. Date format is passed along the attributes.
* @access public
* @return void
*/
function HTML_QuickForm_autocomplete($elementName = null, $elementLabel = null, $options = null, $attributes = null)
{
$this->HTML_QuickForm_text($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_type = 'autocomplete';
if (isset($options)) {
$this->setOptions($options);
}
} //end constructor
 
// }}}
// {{{ setOptions()
 
/**
* Sets the options for the autocomplete input text element
*
* @param array $options Array of options for the autocomplete input text element
* @access public
* @return void
*/
function setOptions($options)
{
$this->_options = array_values($options);
} // end func setOptions
 
// }}}
// {{{ toHtml()
 
/**
* Returns Html for the autocomplete input text element
*
* @access public
* @return string
*/
function toHtml()
{
// prevent problems with grouped elements
$arrayName = str_replace(array('[', ']'), array('__', ''), $this->getName()) . '_values';
 
$this->updateAttributes(array(
'onkeypress' => 'return autocomplete(this, event, ' . $arrayName . ');'
));
if ($this->_flagFrozen) {
$js = '';
} else {
$js = "<script type=\"text/javascript\">\n//<![CDATA[\n";
if (!defined('HTML_QUICKFORM_AUTOCOMPLETE_EXISTS')) {
$this->_js .= <<<EOS
 
/* begin javascript for autocomplete */
function setSelectionRange(input, selectionStart, selectionEnd) {
if (input.setSelectionRange) {
input.setSelectionRange(selectionStart, selectionEnd);
}
else if (input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd("character", selectionEnd);
range.moveStart("character", selectionStart);
range.select();
}
input.focus();
}
 
function setCaretToPosition(input, position) {
setSelectionRange(input, position, position);
}
 
function replaceSelection (input, replaceString) {
var len = replaceString.length;
if (input.setSelectionRange) {
var selectionStart = input.selectionStart;
var selectionEnd = input.selectionEnd;
 
input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd);
input.selectionStart = selectionStart + len;
input.selectionEnd = selectionStart + len;
}
else if (document.selection) {
var range = document.selection.createRange();
var saved_range = range.duplicate();
 
if (range.parentElement() == input) {
range.text = replaceString;
range.moveEnd("character", saved_range.selectionStart + len);
range.moveStart("character", saved_range.selectionStart + len);
range.select();
}
}
input.focus();
}
 
 
function autocompleteMatch (text, values) {
for (var i = 0; i < values.length; i++) {
if (values[i].toUpperCase().indexOf(text.toUpperCase()) == 0) {
return values[i];
}
}
 
return null;
}
 
function autocomplete(textbox, event, values) {
if (textbox.setSelectionRange || textbox.createTextRange) {
switch (event.keyCode) {
case 38: // up arrow
case 40: // down arrow
case 37: // left arrow
case 39: // right arrow
case 33: // page up
case 34: // page down
case 36: // home
case 35: // end
case 13: // enter
case 9: // tab
case 27: // esc
case 16: // shift
case 17: // ctrl
case 18: // alt
case 20: // caps lock
case 8: // backspace
case 46: // delete
return true;
break;
 
default:
var c = String.fromCharCode(
(event.charCode == undefined) ? event.keyCode : event.charCode
);
replaceSelection(textbox, c);
sMatch = autocompleteMatch(textbox.value, values);
var len = textbox.value.length;
if (sMatch != null) {
textbox.value = sMatch;
setSelectionRange(textbox, len, textbox.value.length);
}
return false;
}
}
else {
return true;
}
}
/* end javascript for autocomplete */
 
EOS;
define('HTML_QUICKFORM_AUTOCOMPLETE_EXISTS', true);
}
$jsEscape = array(
"\r" => '\r',
"\n" => '\n',
"\t" => '\t',
"'" => "\\'",
'"' => '\"',
'\\' => '\\\\'
);
 
$js .= $this->_js;
$js .= 'var ' . $arrayName . " = new Array();\n";
for ($i = 0; $i < count($this->_options); $i++) {
$js .= $arrayName . '[' . $i . "] = '" . strtr($this->_options[$i], $jsEscape) . "';\n";
}
$js .= "//]]>\n</script>";
}
return $js . parent::toHtml();
}// end func toHtml
 
// }}}
} // end class HTML_QuickForm_autocomplete
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/password.php
New file
0,0 → 1,108
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: password.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a password type field
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.1
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_password extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array
* @since 1.0
* @access public
* @return void
* @throws
*/
function HTML_QuickForm_password($elementName=null, $elementLabel=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
$this->setType('password');
} //end constructor
// }}}
// {{{ setSize()
 
/**
* Sets size of password element
*
* @param string $size Size of password field
* @since 1.0
* @access public
* @return void
*/
function setSize($size)
{
$this->updateAttributes(array('size'=>$size));
} //end func setSize
 
// }}}
// {{{ setMaxlength()
 
/**
* Sets maxlength of password element
*
* @param string $maxlength Maximum length of password field
* @since 1.0
* @access public
* @return void
*/
function setMaxlength($maxlength)
{
$this->updateAttributes(array('maxlength'=>$maxlength));
} //end func setMaxlength
// }}}
// {{{ getFrozenHtml()
 
/**
* Returns the value of field without HTML tags (in this case, value is changed to a mask)
*
* @since 1.0
* @access public
* @return string
* @throws
*/
function getFrozenHtml()
{
$value = $this->getValue();
return ('' != $value? '**********': '&nbsp;') .
$this->_getPersistantData();
} //end func getFrozenHtml
 
// }}}
 
} //end class HTML_QuickForm_password
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/xbutton.php
New file
0,0 → 1,145
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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: Alexey Borzov <avb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: xbutton.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once 'HTML/QuickForm/element.php';
 
/**
* Class for HTML 4.0 <button> element
*
* @author Alexey Borzov <avb@php.net>
* @since 3.2.3
* @access public
*/
class HTML_QuickForm_xbutton extends HTML_QuickForm_element
{
/**
* Contents of the <button> tag
* @var string
* @access private
*/
var $_content;
 
/**
* Class constructor
*
* @param string Button name
* @param string Button content (HTML to add between <button></button> tags)
* @param mixed Either a typical HTML attribute string or an associative array
* @access public
*/
function HTML_QuickForm_xbutton($elementName = null, $elementContent = null, $attributes = null)
{
$this->HTML_QuickForm_element($elementName, null, $attributes);
$this->setContent($elementContent);
$this->setPersistantFreeze(false);
$this->_type = 'xbutton';
}
 
 
function toHtml()
{
return '<button' . $this->getAttributes(true) . '>' . $this->_content . '</button>';
}
 
 
function getFrozenHtml()
{
return $this->toHtml();
}
 
 
function freeze()
{
return false;
}
 
 
function setName($name)
{
$this->updateAttributes(array(
'name' => $name
));
}
 
 
function getName()
{
return $this->getAttribute('name');
}
 
 
function setValue($value)
{
$this->updateAttributes(array(
'value' => $value
));
}
 
 
function getValue()
{
return $this->getAttribute('value');
}
 
 
/**
* Sets the contents of the button element
*
* @param string Button content (HTML to add between <button></button> tags)
*/
function setContent($content)
{
$this->_content = $content;
}
 
 
function onQuickFormEvent($event, $arg, &$caller)
{
if ('updateValue' != $event) {
return parent::onQuickFormEvent($event, $arg, $caller);
} else {
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
$value = $this->_findValue($caller->_defaultValues);
}
if (null !== $value) {
$this->setValue($value);
}
}
return true;
}
 
 
/**
* Returns a 'safe' element's value
*
* The value is only returned if the button's type is "submit" and if this
* particlular button was clicked
*/
function exportValue(&$submitValues, $assoc = false)
{
if ('submit' == $this->getAttribute('type')) {
return $this->_prepareValue($this->_findValue($submitValues), $assoc);
} else {
return null;
}
}
}
?>
/branches/v1.0-menes/api/pear/HTML/QuickForm/submit.php
New file
0,0 → 1,82
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 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: Adam Daniel <adaniel1@eesus.jnj.com> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// +----------------------------------------------------------------------+
//
// $Id: submit.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
 
require_once("HTML/QuickForm/input.php");
 
/**
* HTML class for a submit type element
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version 1.0
* @since PHP4.04pl1
* @access public
*/
class HTML_QuickForm_submit extends HTML_QuickForm_input
{
// {{{ constructor
 
/**
* Class constructor
*
* @param string Input field name attribute
* @param string Input field value
* @param mixed Either a typical HTML attribute string or an associative array
* @since 1.0
* @access public
* @return void
*/
function HTML_QuickForm_submit($elementName=null, $value=null, $attributes=null)
{
HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
$this->setValue($value);
$this->setType('submit');
} //end constructor
// }}}
// {{{ freeze()
 
/**
* Freeze the element so that only its value is returned
*
* @access public
* @return void
*/
function freeze()
{
return false;
} //end func freeze
 
// }}}
// {{{ exportValue()
 
/**
* Only return the value if it is found within $submitValues (i.e. if
* this particular submit button was clicked)
*/
function exportValue(&$submitValues, $assoc = false)
{
return $this->_prepareValue($this->_findValue($submitValues), $assoc);
}
 
// }}}
} //end class HTML_QuickForm_submit
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Bold.php
New file
0,0 → 1,34
<?php
 
class Text_Wiki_Render_Xhtml_Bold extends Text_Wiki_Render {
 
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<b$css>";
}
if ($options['type'] == 'end') {
return '</b>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Wikilink.php
New file
0,0 → 1,122
<?php
 
class Text_Wiki_Render_Xhtml_Wikilink extends Text_Wiki_Render {
var $conf = array(
'pages' => array(), // set to null or false to turn off page checks
'view_url' => 'http://example.com/index.php?page=%s',
'new_url' => 'http://example.com/new.php?page=%s',
'new_text' => '?',
'new_text_pos' => 'after', // 'before', 'after', or null/false
'css' => null,
'css_new' => null
);
/**
*
* Renders a token into XHTML.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variable names (page, anchor, text)
extract($options);
// are we checking page existence?
$list =& $this->getConf('pages');
if (is_array($list)) {
// yes, check against the page list
$exists = in_array($page, $list);
} else {
// no, assume it exists
$exists = true;
}
// convert *after* checking against page names so as not to mess
// up what the user typed and what we're checking.
$page = htmlspecialchars($page);
$anchor = htmlspecialchars($anchor);
$text = htmlspecialchars($text);
// does the page exist?
if ($exists) {
// PAGE EXISTS.
// yes, link to the page view, but we have to build
// the HREF. we support both the old form where
// the page always comes at the end, and the new
// form that uses %s for sprintf()
$href = $this->getConf('view_url');
if (strpos($href, '%s') === false) {
// use the old form (page-at-end)
$href = $href . $page . $anchor;
} else {
// use the new form (sprintf format string)
$href = sprintf($href, $page . $anchor);
}
// get the CSS class and generate output
$css = $this->formatConf(' class="%s"', 'css');
$output = "<a$css href=\"$href\">$text</a>";
} else {
// PAGE DOES NOT EXIST.
// link to a create-page url, but only if new_url is set
$href = $this->getConf('new_url', null);
// set the proper HREF
if (! $href || trim($href) == '') {
// no useful href, return the text as it is
$output = $text;
} else {
// yes, link to the new-page href, but we have to build
// it. we support both the old form where
// the page always comes at the end, and the new
// form that uses sprintf()
if (strpos($href, '%s') === false) {
// use the old form
$href = $href . $page;
} else {
// use the new form
$href = sprintf($href, $page);
}
}
// get the appropriate CSS class and new-link text
$css = $this->formatConf(' class="%s"', 'css');
$new = $this->getConf('new_text');
// what kind of linking are we doing?
$pos = $this->getConf('new_text_pos');
if (! $pos || ! $new) {
// no position (or no new_text), use css only on the page name
$output = "<a$css href=\"$href\">$page</a>";
} elseif ($pos == 'before') {
// use the new_text BEFORE the page name
$output = "<a$css href=\"$href\">$new</a>$text";
} else {
// default, use the new_text link AFTER the page name
$output = "$text<a$css href=\"$href\">$new</a>";
}
}
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Image.php
New file
0,0 → 1,151
<?php
class Text_Wiki_Render_Xhtml_Image extends Text_Wiki_Render {
 
var $conf = array(
'base' => '/',
'css' => null,
'css_link' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// note the image source
$src = $options['src'];
// is the source a local file or URL?
if (strpos($src, '://') === false) {
// the source refers to a local file.
// add the URL base to it.
$src = $this->getConf('base', '/') . $src;
}
// stephane@metacites.net
// is the image clickable?
if (isset($options['attr']['link'])) {
// yes, the image is clickable.
// are we linked to a URL or a wiki page?
if (strpos($options['attr']['link'], '://')) {
// it's a URL
$href = $options['attr']['link'];
} else {
// it's a WikiPage; assume it exists.
/** @todo This needs to honor sprintf wikilinks (pmjones) */
/** @todo This needs to honor interwiki (pmjones) */
/** @todo This needs to honor freelinks (pmjones) */
$href = $this->wiki->getRenderConf('xhtml', 'wikilink', 'view_url') .
$options['attr']['link'];
}
} else {
// image is not clickable.
$href = null;
}
// unset so it won't show up as an attribute
unset($options['attr']['link']);
// stephane@metacites.net -- 25/07/2004
// we make up an align="center" value for the <img> tag.
if (isset($options['attr']['align']) &&
$options['attr']['align'] == 'center') {
// unset so it won't show up as an attribute
unset($options['attr']['align']);
// make sure we have a style attribute
if (! isset($options['attr']['style'])) {
// no style, set up a blank one
$options['attr']['style'] = '';
} else {
// style exists, add a space
$options['attr']['style'] .= ' ';
}
// add a "center" style to the existing style.
$options['attr']['style'] .=
'display: block; margin-left: auto; margin-right: auto;';
}
// stephane@metacites.net -- 25/07/2004
// try to guess width and height
if (! isset($options['attr']['width']) &&
! isset($options['attr']['height'])) {
// does the source refer to a local file or a URL?
if (strpos($src,'://')) {
// is a URL link
$imageFile = $src;
} else {
// is a local file
$imageFile = $_SERVER['DOCUMENT_ROOT'] . $src;
}
// attempt to get the image size
$imageSize = @getimagesize($imageFile);
if (is_array($imageSize)) {
$options['attr']['width'] = $imageSize[0];
$options['attr']['height'] = $imageSize[1];
}
}
// start the HTML output
$output = '<img src="' . htmlspecialchars($src) . '"';
// get the CSS class but don't add it yet
$css = $this->formatConf(' class="%s"', 'css');
// add the attributes to the output, and be sure to
// track whether or not we find an "alt" attribute
$alt = false;
foreach ($options['attr'] as $key => $val) {
// track the 'alt' attribute
if (strtolower($key) == 'alt') {
$alt = true;
}
// the 'class' attribute overrides the CSS class conf
if (strtolower($key) == 'class') {
$css = null;
}
$key = htmlspecialchars($key);
$val = htmlspecialchars($val);
$output .= " $key=\"$val\"";
}
// always add an "alt" attribute per Stephane Solliec
if (! $alt) {
$alt = htmlspecialchars(basename($options['src']));
$output .= " alt=\"$alt\"";
}
// end the image tag with the automatic CSS class (if any)
$output .= "$css />";
// was the image clickable?
if ($href) {
// yes, add the href and return
$href = htmlspecialchars($href);
$css = $this->formatConf(' class="%s"', 'css_link');
$output = "<a$css href=\"$href\">$output</a>";
}
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Tt.php
New file
0,0 → 1,35
<?php
 
class Text_Wiki_Render_Xhtml_tt extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<tt$css>";
}
if ($options['type'] == 'end') {
return '</tt>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Revise.php
New file
0,0 → 1,45
<?php
 
class Text_Wiki_Render_Xhtml_Revise extends Text_Wiki_Render {
var $conf = array(
'css_ins' => null,
'css_del' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'del_start') {
$css = $this->formatConf(' class="%s"', 'css_del');
return "<del$css>";
}
if ($options['type'] == 'del_end') {
return "</del>";
}
if ($options['type'] == 'ins_start') {
$css = $this->formatConf(' class="%s"', 'css_ins');
return "<ins$css>";
}
if ($options['type'] == 'ins_end') {
return "</ins>";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Freelink.php
New file
0,0 → 1,9
<?php
 
require_once 'Text/Wiki/Render/Xhtml/Wikilink.php';
 
class Text_Wiki_Render_Xhtml_Freelink extends Text_Wiki_Render_Xhtml_Wikilink {
// renders identically to wikilinks, only the parsing is different :-)
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Newline.php
New file
0,0 → 1,12
<?php
 
class Text_Wiki_Render_Xhtml_Newline extends Text_Wiki_Render {
function token($options)
{
return "<br />\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Url.php
New file
0,0 → 1,91
<?php
 
 
class Text_Wiki_Render_Xhtml_Url extends Text_Wiki_Render {
var $conf = array(
'target' => '_blank',
'images' => true,
'img_ext' => array('jpg', 'jpeg', 'gif', 'png'),
'css_inline' => null,
'css_footnote' => null,
'css_descr' => null,
'css_img' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// create local variables from the options array (text,
// href, type)
extract($options);
// find the rightmost dot and determine the filename
// extension.
$pos = strrpos($href, '.');
$ext = strtolower(substr($href, $pos + 1));
$href = htmlspecialchars($href);
// does the filename extension indicate an image file?
if ($this->getConf('images') &&
in_array($ext, $this->getConf('img_ext', array()))) {
// create alt text for the image
if (! isset($text) || $text == '') {
$text = basename($href);
$text = htmlspecialchars($text);
}
// generate an image tag
$css = $this->formatConf(' class="%s"', 'css_img');
$output = "<img$css src=\"$href\" alt=\"$text\" />";
} else {
// allow for alternative targets on non-anchor HREFs
if ($href{0} == '#') {
$target = '';
} else {
$target = $this->getConf('target');
}
// generate a regular link (not an image)
$text = htmlspecialchars($text);
$css = $this->formatConf(' class="%s"', "css_$type");
$output = "<a$css href=\"$href\"";
if ($target) {
// use a "popup" window. this is XHTML compliant, suggested by
// Aaron Kalin. uses the $target as the new window name.
$target = htmlspecialchars($target);
$output .= " onclick=\"window.open(this.href, '$target');";
$output .= " return false;\"";
}
// finish up output
$output .= ">$text</a>";
// make numbered references look like footnotes when no
// CSS class specified, make them superscript by default
if ($type == 'footnote' && ! $css) {
$output = '<sup>' . $output . '</sup>';
}
}
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Emphasis.php
New file
0,0 → 1,35
<?php
 
class Text_Wiki_Render_Xhtml_Emphasis extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<em$css>";
}
if ($options['type'] == 'end') {
return '</em>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Code.php
New file
0,0 → 1,102
<?php
 
class Text_Wiki_Render_Xhtml_Code extends Text_Wiki_Render {
var $conf = array(
'css' => null, // class for <pre>
'css_code' => null, // class for generic <code>
'css_php' => null, // class for PHP <code>
'css_html' => null // class for HTML <code>
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$text = $options['text'];
$attr = $options['attr'];
$type = strtolower($attr['type']);
$css = $this->formatConf(' class="%s"', 'css');
$css_code = $this->formatConf(' class="%s"', 'css_code');
$css_php = $this->formatConf(' class="%s"', 'css_php');
$css_html = $this->formatConf(' class="%s"', 'css_html');
if ($type == 'php') {
// PHP code example:
// add the PHP tags
$text = "<?php\n" . $options['text'] . "\n?>"; // <?php
// convert tabs to four spaces
$text = str_replace("\t", " ", $text);
// colorize the code block (also converts HTML entities and adds
// <code>...</code> tags)
ob_start();
highlight_string($text);
$text = ob_get_contents();
ob_end_clean();
// replace <br /> tags with simple newlines.
// replace non-breaking space with simple spaces.
// translate HTML <font> and color to XHTML <span> and style.
// courtesy of research by A. Kalin :-).
$map = array(
'<br />' => "\n",
'&nbsp;' => ' ',
'<font' => '<span',
'</font>' => '</span>',
'color="' => 'style="color:'
);
$text = strtr($text, $map);
// get rid of the last newline inside the code block
// (becuase higlight_string puts one there)
if (substr($text, -8) == "\n</code>") {
$text = substr($text, 0, -8) . "</code>";
}
// replace all <code> tags with classed tags
if ($css_php) {
$text = str_replace('<code>', "<code$css_php>", $text);
}
// done
$text = "<pre$css>$text</pre>";
} elseif ($type == 'html' || $type == 'xhtml') {
// HTML code example:
// add <html> opening and closing tags,
// convert tabs to four spaces,
// convert entities.
$text = str_replace("\t", " ", $text);
$text = "<html>\n$text\n</html>";
$text = htmlentities($text);
$text = "<pre$css><code$css_html>$text</code></pre>";
} else {
// generic code example:
// convert tabs to four spaces,
// convert entities.
$text = str_replace("\t", " ", $text);
$text = htmlentities($text);
$text = "<pre$css><code$css_code>$text</code></pre>";
}
return "\n$text\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Strong.php
New file
0,0 → 1,35
<?php
 
class Text_Wiki_Render_Xhtml_Strong extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<strong$css>";
}
if ($options['type'] == 'end') {
return '</strong>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Center.php
New file
0,0 → 1,29
<?php
 
class Text_Wiki_Render_Xhtml_Center extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
return '<div style="text-align: center;">';
}
if ($options['type'] == 'end') {
return '</div>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Phplookup.php
New file
0,0 → 1,59
<?php
 
// $Id: Phplookup.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
class Text_Wiki_Render_Xhtml_Phplookup extends Text_Wiki_Render {
var $conf = array(
'target' => '_blank',
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$text = trim($options['text']);
$css = $this->formatConf(' class="%s"', 'css');
// start the html
$output = "<a$css";
// are we targeting another window?
$target = $this->getConf('target', '');
if ($target) {
// use a "popup" window. this is XHTML compliant, suggested by
// Aaron Kalin. uses the $target as the new window name.
$target = htmlspecialchars($target);
$output .= " onclick=\"window.open(this.href, '$target');";
$output .= " return false;\"";
}
// take off the final parens for functions
if (substr($text, -2) == '()') {
$q = substr($text, 0, -2);
} else {
$q = $text;
}
$q = htmlspecialchars($q);
$text = htmlspecialchars($text);
// finish and return
$output .= " href=\"http://php.net/$q\">$text</a>";
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Colortext.php
New file
0,0 → 1,56
<?php
 
class Text_Wiki_Render_Xhtml_Colortext extends Text_Wiki_Render {
var $colors = array(
'aqua',
'black',
'blue',
'fuchsia',
'gray',
'green',
'lime',
'maroon',
'navy',
'olive',
'purple',
'red',
'silver',
'teal',
'white',
'yellow'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$color = $options['color'];
if (! in_array($color, $this->colors)) {
$color = '#' . $color;
}
if ($type == 'start') {
return "<span style=\"color: $color;\">";
}
if ($options['type'] == 'end') {
return '</span>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Include.php
New file
0,0 → 1,8
<?php
class Text_Wiki_Render_Xhtml_Include extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Superscript.php
New file
0,0 → 1,34
<?php
 
class Text_Wiki_Render_Xhtml_Superscript extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<sup$css>";
}
if ($options['type'] == 'end') {
return '</sup>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Break.php
New file
0,0 → 1,29
<?php
 
class Text_Wiki_Render_Xhtml_Break extends Text_Wiki_Render {
 
var $conf = array(
'css' => null
);
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$css = $this->formatConf(' class="%s"', 'css');
return "<br$css />\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Toc.php
New file
0,0 → 1,80
<?php
 
// $Id: Toc.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
class Text_Wiki_Render_Xhtml_Toc extends Text_Wiki_Render {
var $conf = array(
'css_list' => null,
'css_item' => null,
'title' => '<strong>Table of Contents</strong>',
'div_id' => 'toc'
);
var $min = 2;
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// type, id, level, count, attr
extract($options);
switch ($type) {
case 'list_start':
$html = '<div';
$css = $this->getConf('css_list');
if ($css) {
$html .= " class=\"$css\"";
}
$div_id = $this->getConf('div_id');
if ($div_id) {
$html .= " id=\"$div_id\"";
}
$html .= '>';
$html .= $this->getConf('title');
return $html;
break;
case 'list_end':
return "</div>\n";
break;
case 'item_start':
$html = '<div';
$css = $this->getConf('css_item');
if ($css) {
$html .= " class=\"$css\"";
}
$pad = ($level - $this->min);
$html .= " style=\"margin-left: {$pad}em;\">";
$html .= "<a href=\"#$id\">";
return $html;
break;
case 'item_end':
return "</a></div>\n";
break;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Function.php
New file
0,0 → 1,87
<?php
 
// $Id: Function.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
class Text_Wiki_Render_Xhtml_Function extends Text_Wiki_Render {
var $conf = array(
// list separator for params and throws
'list_sep' => ', ',
// the "main" format string
'format_main' => '%access %return <b>%name</b> ( %params ) %throws',
// the looped format string for required params
'format_param' => '%type <i>%descr</i>',
// the looped format string for params with default values
'format_paramd' => '[%type <i>%descr</i> default %default]',
// the looped format string for throws
'format_throws' => '<b>throws</b> %type <i>%descr</i>'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
extract($options); // name, access, return, params, throws
// build the baseline output
$output = $this->conf['format_main'];
$output = str_replace('%access', htmlspecialchars($access), $output);
$output = str_replace('%return', htmlspecialchars($return), $output);
$output = str_replace('%name', htmlspecialchars($name), $output);
// build the set of params
$list = array();
foreach ($params as $key => $val) {
// is there a default value?
if ($val['default']) {
$tmp = $this->conf['format_paramd'];
} else {
$tmp = $this->conf['format_param'];
}
// add the param elements
$tmp = str_replace('%type', htmlspecialchars($val['type']), $tmp);
$tmp = str_replace('%descr', htmlspecialchars($val['descr']), $tmp);
$tmp = str_replace('%default', htmlspecialchars($val['default']), $tmp);
$list[] = $tmp;
}
// insert params into output
$tmp = implode($this->conf['list_sep'], $list);
$output = str_replace('%params', $tmp, $output);
// build the set of throws
$list = array();
foreach ($throws as $key => $val) {
$tmp = $this->conf['format_throws'];
$tmp = str_replace('%type', htmlspecialchars($val['type']), $tmp);
$tmp = str_replace('%descr', htmlspecialchars($val['descr']), $tmp);
$list[] = $tmp;
}
// insert throws into output
$tmp = implode($this->conf['list_sep'], $list);
$output = str_replace('%throws', $tmp, $output);
// close the div and return the output
$output .= '</div>';
return "\n$output\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Table.php
New file
0,0 → 1,98
<?php
 
class Text_Wiki_Render_Xhtml_Table extends Text_Wiki_Render {
var $conf = array(
'css_table' => null,
'css_tr' => null,
'css_th' => null,
'css_td' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variable names (type, attr, span)
extract($options);
$pad = ' ';
switch ($type) {
case 'table_start':
$css = $this->formatConf(' class="%s"', 'css_table');
return "\n\n<table$css>\n";
break;
case 'table_end':
return "</table>\n\n";
break;
case 'row_start':
$css = $this->formatConf(' class="%s"', 'css_tr');
return "$pad<tr$css>\n";
break;
case 'row_end':
return "$pad</tr>\n";
break;
case 'cell_start':
// base html
$html = $pad . $pad;
// is this a TH or TD cell?
if ($attr == 'header') {
// start a header cell
$css = $this->formatConf(' class="%s"', 'css_th');
$html .= "<th$css";
} else {
// start a normal cell
$css = $this->formatConf(' class="%s"', 'css_td');
$html .= "<td$css";
}
// add the column span
if ($span > 1) {
$html .= " colspan=\"$span\"";
}
// add alignment
if ($attr != 'header' && $attr != '') {
$html .= " style=\"text-align: $attr;\"";
}
// done!
$html .= '>';
return $html;
break;
case 'cell_end':
if ($attr == 'header') {
return "</th>\n";
} else {
return "</td>\n";
}
break;
default:
return '';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Raw.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Xhtml_Raw extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Deflist.php
New file
0,0 → 1,64
<?php
 
class Text_Wiki_Render_Xhtml_Deflist extends Text_Wiki_Render {
var $conf = array(
'css_dl' => null,
'css_dt' => null,
'css_dd' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$pad = " ";
switch ($type) {
case 'list_start':
$css = $this->formatConf(' class="%s"', 'css_dl');
return "<dl$css>\n";
break;
case 'list_end':
return "</dl>\n\n";
break;
case 'term_start':
$css = $this->formatConf(' class="%s"', 'css_dt');
return $pad . "<dt$css>";
break;
case 'term_end':
return "</dt>\n";
break;
case 'narr_start':
$css = $this->formatConf(' class="%s"', 'css_dd');
return $pad . $pad . "<dd$css>";
break;
case 'narr_end':
return "</dd>\n";
break;
default:
return '';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Horiz.php
New file
0,0 → 1,28
<?php
 
class Text_Wiki_Render_Xhtml_Horiz extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$css = $this->formatConf(' class="%s"', 'css');
return "<hr$css />\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Prefilter.php
New file
0,0 → 1,40
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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 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: Paul M. Jones <pmjones@ciaweb.net> |
// +----------------------------------------------------------------------+
//
// $Id: Prefilter.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Render_Xhtml to "pre-filter" source text so
* that line endings are consistently \n, lines ending in a backslash \
* are concatenated with the next line, and tabs are converted to spaces.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Xhtml_Prefilter extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Heading.php
New file
0,0 → 1,29
<?php
 
class Text_Wiki_Render_Xhtml_Heading extends Text_Wiki_Render {
var $conf = array(
'css_h1' => null,
'css_h2' => null,
'css_h3' => null,
'css_h4' => null,
'css_h5' => null,
'css_h6' => null
);
function token($options)
{
// get nice variable names (id, type, level)
extract($options);
if ($type == 'start') {
$css = $this->formatConf(' class="%s"', "css_h$level");
return "<h$level$css id=\"$id\">";
}
if ($type == 'end') {
return "</h$level>\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Tighten.php
New file
0,0 → 1,10
<?php
class Text_Wiki_Render_Xhtml_Tighten extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Html.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Xhtml_Html extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Italic.php
New file
0,0 → 1,34
<?php
 
class Text_Wiki_Render_Xhtml_Italic extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<i$css>";
}
if ($options['type'] == 'end') {
return '</i>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Paragraph.php
New file
0,0 → 1,36
<?php
 
class Text_Wiki_Render_Xhtml_Paragraph extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
extract($options); //type
if ($type == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
return "<p$css>";
}
if ($type == 'end') {
return "</p>\n\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Interwiki.php
New file
0,0 → 1,74
<?php
 
class Text_Wiki_Render_Xhtml_Interwiki extends Text_Wiki_Render {
var $conf = array(
'sites' => array(
'MeatBall' => 'http://www.usemod.com/cgi-bin/mb.pl?%s',
'Advogato' => 'http://advogato.org/%s',
'Wiki' => 'http://c2.com/cgi/wiki?%s'
),
'target' => '_blank',
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$site = $options['site'];
$page = $options['page'];
$text = $options['text'];
$css = $this->formatConf(' class="%s"', 'css');
if (isset($this->conf['sites'][$site])) {
$href = $this->conf['sites'][$site];
} else {
return $text;
}
// old form where page is at end,
// or new form with %s placeholder for sprintf()?
if (strpos($href, '%s') === false) {
// use the old form
$href = $href . $page;
} else {
// use the new form
$href = sprintf($href, $page);
}
// allow for alternative targets
$target = $this->getConf('target');
// build base link
$text = htmlspecialchars($text);
$output = "<a$css href=\"$href\"";
// are we targeting a specific window?
if ($target) {
// this is XHTML compliant, suggested by Aaron Kalin.
// code tip is actually from youngpup.net, and it
// uses the $target as the new window name.
$target = htmlspecialchars($target);
$output .= " onClick=\"window.open(this.href, '$target');";
$output .= " return false;\"";
}
$output .= ">$text</a>";
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Blockquote.php
New file
0,0 → 1,46
<?php
 
class Text_Wiki_Render_Xhtml_Blockquote extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$level = $options['level'];
// set up indenting so that the results look nice; we do this
// in two steps to avoid str_pad mathematics. ;-)
$pad = str_pad('', $level, "\t");
$pad = str_replace("\t", ' ', $pad);
// pick the css type
$css = $this->formatConf(' class="%s"', 'css');
// starting
if ($type == 'start') {
return "$pad<blockquote$css>";
}
// ending
if ($type == 'end') {
return $pad . "</blockquote>\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Anchor.php
New file
0,0 → 1,37
<?php
 
/**
*
* This class renders an anchor target name in XHTML.
*
* @author Manuel Holtgrewe <purestorm at ggnore dot net>
*
* @author Paul M. Jones <pmjones at ciaweb dot net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Xhtml_Anchor extends Text_Wiki_Render {
var $conf = array(
'css' => null
);
function token($options)
{
extract($options); // $type, $name
if ($type == 'start') {
$css = $this->formatConf(' class="%s"', 'css');
$format = "<a$css id=\"%s\">'";
return sprintf($format ,$name);
}
if ($type == 'end') {
return '</a>';
}
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/List.php
New file
0,0 → 1,142
<?php
 
 
class Text_Wiki_Render_Xhtml_List extends Text_Wiki_Render {
var $conf = array(
'css_ol' => null,
'css_ol_li' => null,
'css_ul' => null,
'css_ul_li' => null
);
/**
*
* Renders a token into text matching the requested format.
*
* This rendering method is syntactically and semantically compliant
* with XHTML 1.1 in that sub-lists are part of the previous list item.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variables (type, level, count)
extract($options);
// set up indenting so that the results look nice; we do this
// in two steps to avoid str_pad mathematics. ;-)
$pad = str_pad('', $level, "\t");
$pad = str_replace("\t", ' ', $pad);
switch ($type) {
case 'bullet_list_start':
// build the base HTML
$css = $this->formatConf(' class="%s"', 'css_ul');
$html = "<ul$css>";
// if this is the opening block for the list,
// put an extra newline in front of it so the
// output looks nice.
if ($level == 0) {
$html = "\n$html";
}
// done!
return $html;
break;
case 'bullet_list_end':
// build the base HTML
$html = "</li>\n$pad</ul>";
// if this is the closing block for the list,
// put extra newlines after it so the output
// looks nice.
if ($level == 0) {
$html .= "\n\n";
}
// done!
return $html;
break;
case 'number_list_start':
// build the base HTML
$css = $this->formatConf(' class="%s"', 'css_ol');
$html = "<ol$css>";
// if this is the opening block for the list,
// put an extra newline in front of it so the
// output looks nice.
if ($level == 0) {
$html = "\n$html";
}
// done!
return $html;
break;
case 'number_list_end':
// build the base HTML
$html = "</li>\n$pad</ol>";
// if this is the closing block for the list,
// put extra newlines after it so the output
// looks nice.
if ($level == 0) {
$html .= "\n\n";
}
// done!
return $html;
break;
case 'bullet_item_start':
case 'number_item_start':
// pick the proper CSS class
if ($type == 'bullet_item_start') {
$css = $this->formatConf(' class="%s"', 'css_ul_li');
} else {
$css = $this->formatConf(' class="%s"', 'css_ol_li');
}
// build the base HTML
$html = "\n$pad<li$css>";
// for the very first item in the list, do nothing.
// but for additional items, be sure to close the
// previous item.
if ($count > 0) {
$html = "</li>$html";
}
// done!
return $html;
break;
case 'bullet_item_end':
case 'number_item_end':
default:
// ignore item endings and all other types.
// item endings are taken care of by the other types
// depending on their place in the list.
return '';
break;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Embed.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Xhtml_Embed extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml/Delimiter.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Xhtml_Delimiter extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Superscript.php
New file
0,0 → 1,31
<?php
 
class Text_Wiki_Render_Latex_Superscript extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return 'Superscript: NI';
if ($options['type'] == 'start') {
return '<sup>';
}
if ($options['type'] == 'end') {
return '</sup>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Include.php
New file
0,0 → 1,8
<?php
class Text_Wiki_Render_Latex_Include extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Colortext.php
New file
0,0 → 1,58
<?php
 
class Text_Wiki_Render_Latex_Colortext extends Text_Wiki_Render {
var $colors = array(
'aqua',
'black',
'blue',
'fuchsia',
'gray',
'green',
'lime',
'maroon',
'navy',
'olive',
'purple',
'red',
'silver',
'teal',
'white',
'yellow'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return 'Colortext: NI';
$type = $options['type'];
$color = $options['color'];
if (! in_array($color, $this->colors)) {
$color = '#' . $color;
}
if ($type == 'start') {
return "<span style=\"color: $color;\">";
}
if ($options['type'] == 'end') {
return '</span>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Break.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Latex_Break extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "\\newline\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Toc.php
New file
0,0 → 1,30
<?php
 
class Text_Wiki_Render_Latex_Toc extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if($options['type'] == 'list_start') {
return "\\tableofcontents\n\n";
}
return '';
}
 
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Function.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Latex_Function extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "Function: NI";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Table.php
New file
0,0 → 1,93
<?php
 
class Text_Wiki_Render_Latex_Table extends Text_Wiki_Render {
var $cell_id = 0;
var $cell_count = 0;
var $is_spanning = false;
var $conf = array(
'css_table' => null,
'css_tr' => null,
'css_th' => null,
'css_td' => null
);
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
 
function token($options)
{
// make nice variable names (type, attr, span)
extract($options);
 
switch ($type)
{
case 'table_start':
$this->cell_count = $cols;
$tbl_start = '\begin{tabular}{|';
for ($a=0; $a < $this->cell_count; $a++) {
$tbl_start .= 'l|';
}
$tbl_start .= "}\n";
return $tbl_start;
 
case 'table_end':
return "\\hline\n\\end{tabular}\n";
 
case 'row_start':
$this->is_spanning = false;
$this->cell_id = 0;
return "\\hline\n";
 
case 'row_end':
return "\\\\\n";
 
case 'cell_start':
if ($span > 1) {
$col_spec = '';
if ($this->cell_id == 0) {
$col_spec = '|';
}
$col_spec .= 'l|';
$this->cell_id += $span;
$this->is_spanning = true;
return "\\multicolumn\{$span}\{$col_spec}{";
}
 
$this->cell_id += 1;
return '';
 
case 'cell_end':
$out = '';
if ($this->is_spanning) {
$this->is_spanning = false;
$out = '}';
}
if ($this->cell_id != $this->cell_count) {
$out .= ' & ';
}
 
return $out;
 
default:
return '';
 
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Raw.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Latex_Raw extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "Raw: ".$options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Deflist.php
New file
0,0 → 1,53
<?php
 
class Text_Wiki_Render_Latex_Deflist extends Text_Wiki_Render {
 
var $conf = array(
'css_dl' => null,
'css_dt' => null,
'css_dd' => null
);
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
 
function token($options)
{
$type = $options['type'];
switch ($type)
{
case 'list_start':
return "\\begin{description}\n";
 
case 'list_end':
return "\\end{description}\n\n";
 
case 'term_start':
return '\item[';
 
case 'term_end':
return '] ';
 
case 'narr_start':
return '{';
 
case 'narr_end':
return "}\n";
 
default:
return '';
 
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Horiz.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Latex_Horiz extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "\n\\noindent\\rule{\\textwidth}{1pt}\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Prefilter.php
New file
0,0 → 1,40
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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 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: Jeremy Cowgar <jeremy@cowgar.com> |
// +----------------------------------------------------------------------+
//
// $Id: Prefilter.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Render_Latex to "pre-filter" source text so
* that line endings are consistently \n, lines ending in a backslash \
* are concatenated with the next line, and tabs are converted to spaces.
*
* @author Jeremy Cowgar <jeremy@cowgar.com>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Latex_Prefilter extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Heading.php
New file
0,0 → 1,33
<?php
 
class Text_Wiki_Render_Latex_Heading extends Text_Wiki_Render {
 
function token($options)
{
// get nice variable names (type, level)
extract($options);
 
if ($type == 'start') {
switch ($level)
{
case '1':
return '\part{';
case '2':
return '\section{';
case '3':
return '\subsection{';
case '4':
return '\subsubsection{';
case '5':
return '\paragraph{';
case '6':
return '\subparagraph{';
}
}
if ($type == 'end') {
return "}\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Tighten.php
New file
0,0 → 1,9
<?php
class Text_Wiki_Render_Latex_Tighten extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Html.php
New file
0,0 → 1,25
<?php
 
class Text_Wiki_Render_Latex_Html extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
print_r($this);
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Interwiki.php
New file
0,0 → 1,60
<?php
 
class Text_Wiki_Render_Latex_Interwiki extends Text_Wiki_Render {
var $conf = array(
'sites' => array(
'MeatBall' => 'http://www.usemod.com/cgi-bin/mb.pl?%s',
'Advogato' => 'http://advogato.org/%s',
'Wiki' => 'http://c2.com/cgi/wiki?%s'
),
'target' => '_blank'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$site = $options['site'];
$page = $options['page'];
$text = $options['text'];
if (isset($this->conf['sites'][$site])) {
$href = $this->conf['sites'][$site];
} else {
return $text;
}
// old form where page is at end,
// or new form with %s placeholder for sprintf()?
if (strpos($href, '%s') === false) {
// use the old form
$href = $href . $page;
} else {
// use the new form
$href = sprintf($href, $page);
}
// allow for alternative targets
$target = $this->getConf('target', '');
if ($target && trim($target) != '') {
$target = " target=\"$target\"";
}
return "$text\\footnote\{$href}";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Paragraph.php
New file
0,0 → 1,31
<?php
 
class Text_Wiki_Render_Latex_Paragraph extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
extract($options); //type
if ($type == 'start') {
return '';
}
if ($type == 'end') {
return "\n\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Italic.php
New file
0,0 → 1,5
<?php
 
class Text_Wiki_Render_Latex_Italic extends Text_Wiki_Render_Latex_Emphasis {
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Blockquote.php
New file
0,0 → 1,36
<?php
 
class Text_Wiki_Render_Latex_Blockquote extends Text_Wiki_Render {
var $conf = array('css' => null);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$level = $options['level'];
// starting
if ($type == 'start') {
return "\\begin{quote}\n";
}
// ending
if ($type == 'end') {
return "\\end{quote}\n\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Anchor.php
New file
0,0 → 1,33
<?php
 
/**
*
* This class renders an anchor target name in LaTeX.
*
* $Id: Anchor.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
* @author Jeremy Cowgar <jeremy@cowgar.com>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Latex_Anchor extends Text_Wiki_Render {
function token($options)
{
extract($options); // $type, $name
if ($type == 'start') {
//return sprintf('<a id="%s">',$name);
return '';
}
if ($type == 'end') {
//return '</a>';
return '';
}
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/List.php
New file
0,0 → 1,57
<?php
 
 
class Text_Wiki_Render_Latex_List extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* This rendering method is syntactically and semantically compliant
* with XHTML 1.1 in that sub-lists are part of the previous list item.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
 
function token($options)
{
// make nice variables (type, level, count)
extract($options);
switch ($type)
{
case 'bullet_list_start':
return "\\begin{itemize}\n";
case 'bullet_list_end':
return "\\end{itemize}\n";
case 'number_list_start':
return "\\begin{enumerate}\n";
case 'number_list_end':
return "\\end{enumerate}\n";
case 'bullet_item_start':
case 'number_item_start':
return "\\item{";
case 'bullet_item_end':
case 'number_item_end':
return "}\n";
default:
// ignore item endings and all other types.
// item endings are taken care of by the other types
// depending on their place in the list.
return '';
break;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Embed.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Latex_Embed extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "Embed: ".$options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Delimiter.php
New file
0,0 → 1,25
<?php
 
class Text_Wiki_Render_Latex_Delimiter extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// TODO: Is this where I can do some LaTeX escaping for items
// such as $ { } _ ?
return "Delimiter: ".$options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Bold.php
New file
0,0 → 1,4
<?php
 
class Text_Wiki_Render_Latex_Bold extends Text_Wiki_Render_Latex_Strong {}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Wikilink.php
New file
0,0 → 1,60
<?php
 
class Text_Wiki_Render_Latex_Wikilink extends Text_Wiki_Render {
var $conf = array(
'pages' => array(),
'view_url' => 'http://example.com/index.php?page=%s',
'new_url' => 'http://example.com/new.php?page=%s',
'new_text' => '?'
);
/**
*
* Renders a token into XHTML.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variable names (page, anchor, text)
extract($options);
// are we checking page existence?
$list =& $this->getConf('pages');
if (is_array($list)) {
// yes, check against the page list
$exists = in_array($page, $list);
} else {
// no, assume it exists
$exists = true;
}
// convert *after* checking against page names so as not to mess
// up what the user typed and what we're checking.
$page = htmlspecialchars($page);
$anchor = htmlspecialchars($anchor);
$text = htmlspecialchars($text);
$href = $this->getConf('view_url');
if (strpos($href, '%s') === false) {
// use the old form (page-at-end)
$href = $href . $page . $anchor;
} else {
// use the new form (sprintf format string)
$href = sprintf($href, $page . $anchor);
}
// get the CSS class and generate output
$css = $this->formatConf(' class="%s"', 'css');
return "$text\\footnote\{$href}";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Image.php
New file
0,0 → 1,70
<?php
class Text_Wiki_Render_Latex_Image extends Text_Wiki_Render {
 
var $conf = array(
'base' => '/'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return 'Image: NI';
$src = '"' .
$this->getConf('base', '/') .
$options['src'] . '"';
if (isset($options['attr']['link'])) {
// this image has a link
if (strpos($options['attr']['link'], '://')) {
// it's a URL
$href = $options['attr']['link'];
} else {
$href = $this->wiki->getRenderConf('xhtml', 'wikilink', 'view_url') .
$options['attr']['link'];
}
} else {
// image is not linked
$href = null;
}
// unset these so they don't show up as attributes
unset($options['attr']['link']);
$attr = '';
$alt = false;
foreach ($options['attr'] as $key => $val) {
if (strtolower($key) == 'alt') {
$alt = true;
}
$attr .= " $key=\"$val\"";
}
// always add an "alt" attribute per Stephane Solliec
if (! $alt) {
$attr .= ' alt="' . basename($options['src']) . '"';
}
if ($href) {
return "<a href=\"$href\"><img src=$src$attr/></a>";
} else {
return "<img src=$src$attr/>";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Tt.php
New file
0,0 → 1,30
<?php
 
class Text_Wiki_Render_Latex_tt extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
return '\texttt{';
}
if ($options['type'] == 'end') {
return '}';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Revise.php
New file
0,0 → 1,38
<?php
 
class Text_Wiki_Render_Latex_Revise extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'del_start') {
return '\sout{';
}
if ($options['type'] == 'del_end') {
return '}';
}
if ($options['type'] == 'ins_start') {
return '\underline{';
}
if ($options['type'] == 'ins_end') {
return '}';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Freelink.php
New file
0,0 → 1,34
<?php
 
class Text_Wiki_Render_Latex_Freelink extends Text_Wiki_Render {
var $conf = array(
'pages' => array(),
'view_url' => 'http://example.com/index.php?page=%s',
'new_url' => 'http://example.com/new.php?page=%s',
'new_text' => '?'
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// get nice variable names (page, text, anchor)
extract($options);
return "$text\\footnote\{$anchor} ";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Newline.php
New file
0,0 → 1,12
<?php
 
class Text_Wiki_Render_Latex_Newline extends Text_Wiki_Render {
function token($options)
{
return "\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Url.php
New file
0,0 → 1,35
<?php
 
 
class Text_Wiki_Render_Latex_Url extends Text_Wiki_Render {
var $conf = array(
'target' => false,
'images' => true,
'img_ext' => array('jpg', 'jpeg', 'gif', 'png')
);
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// create local variables from the options array (text,
// href, type)
extract($options);
 
return " $text\\footnote\{$href}";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Emphasis.php
New file
0,0 → 1,29
<?php
 
class Text_Wiki_Render_Latex_Emphasis extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
return '\textsl{';
}
if ($options['type'] == 'end') {
return '}';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Code.php
New file
0,0 → 1,26
<?php
 
class Text_Wiki_Render_Latex_Code extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$text = $options['text'];
 
return "\\begin{verbatim}\n$text\n\\end{verbatim}\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Strong.php
New file
0,0 → 1,30
<?php
 
class Text_Wiki_Render_Latex_Strong extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
if ($options['type'] == 'start') {
return '\textbf{';
}
if ($options['type'] == 'end') {
return '}';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Center.php
New file
0,0 → 1,33
<?php
 
class Text_Wiki_Render_Latex_Center extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return 'Center: NI';
if ($options['type'] == 'start') {
//return "\n<center>\n";
return '<div style="text-align: center;">';
}
if ($options['type'] == 'end') {
//return "</center>\n";
return '</div>';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex/Phplookup.php
New file
0,0 → 1,34
<?php
 
class Text_Wiki_Render_Latex_Phplookup extends Text_Wiki_Render {
var $conf = array('target' => '_blank');
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return 'Phplookup: NI';
$text = trim($options['text']);
$target = $this->getConf('target', '');
if ($target) {
$target = " target=\"$target\"";
}
return "<a$target href=\"http://php.net/$text\">$text</a>";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Xhtml.php
New file
0,0 → 1,33
<?php
 
class Text_Wiki_Render_Xhtml extends Text_Wiki_Render {
var $conf = array('translate' => HTML_ENTITIES);
function pre()
{
// attempt to translate HTML entities in the source before continuing.
$type = $this->getConf('translate', null);
// are we translating html?
if ($type) {
// yes! get the translation table.
$xlate = get_html_translation_table($type);
// remove the delimiter character it doesn't get translated
unset($xlate[$this->wiki->delim]);
// translate!
$this->wiki->source = strtr($this->wiki->source, $xlate);
}
}
function post()
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Latex.php
New file
0,0 → 1,90
<?php
 
/**
*
* Formats parsed Text_Wiki for LaTeX rendering.
*
* $Id: Latex.php,v 1.1 2005-01-20 19:44:30 jpm Exp $
*
* @author Jeremy Cowgar <jeremy@cowgar.com>
*
* @package Text_Wiki
*
* @todo [http://google.com] becomes 1 with a LaTeX footnote in subscript.
* This should be a normal LaTeX footnote associated with the
* previous word?
*
* @todo parse "..." to be ``...''
*
* @todo parse '...' to be `...'
*
* @todo move escape_latex to a static function, move escaping to the
* individual .php files they are associated with
*
* @todo allow the user to add conf items to do things like
* + A custom document header
* + Custom page headings
* + Include packages
* + Set Title, Author, Date
* + Include a title page
* + Not output Document Head/Foot (maybe combinding many pages?)
*
*/
 
class Text_Wiki_Render_Latex extends Text_Wiki_Render {
function escape_latex ($txt) {
$txt = str_replace("\\", "\\\\", $txt);
$txt = str_replace('#', '\#', $txt);
$txt = str_replace('$', '\$', $txt);
$txt = str_replace('%', '\%', $txt);
$txt = str_replace('^', '\^', $txt);
$txt = str_replace('&', '\&', $txt);
$txt = str_replace('_', '\_', $txt);
$txt = str_replace('{', '\{', $txt);
$txt = str_replace('}', '\}', $txt);
// Typeset things a bit prettier than normas
$txt = str_replace('~', '$\sim$', $txt);
$txt = str_replace('...', '\ldots', $txt);
 
return $txt;
}
 
function escape($tok, $ele) {
if (isset($tok[$ele])) {
$tok[$ele] = $this->escape_latex($tok[$ele]);
}
 
return $tok;
}
function pre()
{
foreach ($this->wiki->tokens as $k => $tok) {
if ($tok[0] == 'Code') {
continue;
}
 
$tok[1] = $this->escape($tok[1], 'text');
$tok[1] = $this->escape($tok[1], 'page');
$tok[1] = $this->escape($tok[1], 'href');
$this->wiki->tokens[$k] = $tok;
}
 
$this->wiki->source = $this->escape_latex($this->wiki->source);
 
return
"\\documentclass{article}\n".
"\\usepackage{ulem}\n".
"\\pagestyle{headings}\n".
"\\begin{document}\n";
}
function post()
{
return "\\end{document}\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Raw.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Raw extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Deflist.php
New file
0,0 → 1,59
<?php
 
class Text_Wiki_Render_Plain_Deflist extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$pad = " ";
switch ($type) {
case 'list_start':
return "\n";
break;
case 'list_end':
return "\n\n";
break;
case 'term_start':
// done!
return $pad;
break;
case 'term_end':
return "\n";
break;
case 'narr_start':
// done!
return $pad . $pad;
break;
case 'narr_end':
return "\n";
break;
default:
return '';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Horiz.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Horiz extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Prefilter.php
New file
0,0 → 1,40
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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 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: Paul M. Jones <pmjones@ciaweb.net> |
// +----------------------------------------------------------------------+
//
// $Id: Prefilter.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Render_Xhtml to "pre-filter" source text so
* that line endings are consistently \n, lines ending in a backslash \
* are concatenated with the next line, and tabs are converted to spaces.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Plain_Prefilter extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Revise.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Revise extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Heading.php
New file
0,0 → 1,14
<?php
 
class Text_Wiki_Render_Plain_Heading extends Text_Wiki_Render {
function token($options)
{
if ($options['type'] == 'end') {
return "\n\n";
} else {
return "\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Freelink.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Freelink extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Tighten.php
New file
0,0 → 1,10
<?php
class Text_Wiki_Render_Plain_Tighten extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Interwiki.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Interwiki extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Paragraph.php
New file
0,0 → 1,31
<?php
 
class Text_Wiki_Render_Plain_Paragraph extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
extract($options); //type
if ($type == 'start') {
return '';
}
if ($type == 'end') {
return "\n\n";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Emphasis.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Emphasis extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Code.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Code extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "\n" . $options['text'] . "\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Embed.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Embed extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return strip_tags($options['text']);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Strong.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Strong extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Delimiter.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Delimiter extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Center.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Center extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Image.php
New file
0,0 → 1,22
<?php
class Text_Wiki_Render_Plain_Image extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Function.php
New file
0,0 → 1,39
<?php
 
// $Id: Function.php,v 1.1 2005-01-20 19:43:21 jpm Exp $
 
class Text_Wiki_Render_Plain_Function extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
extract($options); // access, return, name, params, throws
$output = "$access $return $name ( ";
foreach ($params as $key => $val) {
$output .= "{$val['type']} {$val['descr']} {$val['default']} ";
}
$output .= ') ';
foreach ($throws as $key => $val) {
$output .= "{$val['type']} {$val['descr']} ";
}
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Newline.php
New file
0,0 → 1,12
<?php
 
class Text_Wiki_Render_Plain_Newline extends Text_Wiki_Render {
function token($options)
{
return "\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Url.php
New file
0,0 → 1,25
<?php
 
 
class Text_Wiki_Render_Plain_Url extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Html.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Html extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return strip_tags($options['text']);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Italic.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Italic extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Blockquote.php
New file
0,0 → 1,39
<?php
 
class Text_Wiki_Render_Plain_Blockquote extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
$type = $options['type'];
$level = $options['level'];
// set up indenting so that the results look nice; we do this
// in two steps to avoid str_pad mathematics. ;-)
$pad = str_pad('', $level + 1, "\t");
$pad = str_replace("\t", ' ', $pad);
// starting
if ($type == 'start') {
return "\n$pad";
}
// ending
if ($type == 'end') {
return "\n$pad";
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Anchor.php
New file
0,0 → 1,23
<?php
 
/**
*
* This class renders an anchor target name in XHTML.
*
* @author Manuel Holtgrewe <purestorm at ggnore dot net>
*
* @author Paul M. Jones <pmjones at ciaweb dot net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Render_Plain_Anchor extends Text_Wiki_Render {
function token($options)
{
return $options['name'];
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/List.php
New file
0,0 → 1,68
<?php
 
 
class Text_Wiki_Render_Plain_List extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* This rendering method is syntactically and semantically compliant
* with XHTML 1.1 in that sub-lists are part of the previous list item.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variables (type, level, count)
extract($options);
// set up indenting so that the results look nice; we do this
// in two steps to avoid str_pad mathematics. ;-)
$pad = str_pad('', $level, "\t");
$pad = str_replace("\t", ' ', $pad);
switch ($type) {
case 'bullet_list_start':
break;
case 'bullet_list_end':
if ($level == 0) {
return "\n\n";
}
break;
case 'number_list_start':
break;
case 'number_list_end':
if ($level == 0) {
return "\n\n";
}
break;
case 'bullet_item_start':
case 'number_item_start':
return "\n$pad";
break;
case 'bullet_item_end':
case 'number_item_end':
default:
// ignore item endings and all other types.
// item endings are taken care of by the other types
// depending on their place in the list.
return;
break;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Bold.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Bold extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Phplookup.php
New file
0,0 → 1,25
<?php
 
class Text_Wiki_Render_Plain_Phplookup extends Text_Wiki_Render {
var $conf = array('target' => '_blank');
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return trim($options['text']);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Wikilink.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Wikilink extends Text_Wiki_Render {
/**
*
* Renders a token into plain text.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return $options['text'];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Superscript.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Superscript extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Include.php
New file
0,0 → 1,8
<?php
class Text_Wiki_Render_Plain_Include extends Text_Wiki_Render {
function token()
{
return '';
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Colortext.php
New file
0,0 → 1,23
<?php
 
class Text_Wiki_Render_Plain_Colortext extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Break.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_Break extends Text_Wiki_Render {
 
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return "\n";
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Toc.php
New file
0,0 → 1,39
<?php
 
class Text_Wiki_Render_Plain_Toc extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// type, count, level
extract($options);
if ($type == 'item_start') {
// build some indenting spaces for the text
$indent = ($level - 2) * 4;
$pad = str_pad('', $indent);
return $pad;
}
if ($type == 'item_end') {
return "\n";
}
}
 
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Tt.php
New file
0,0 → 1,24
<?php
 
class Text_Wiki_Render_Plain_tt extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain/Table.php
New file
0,0 → 1,57
<?php
 
class Text_Wiki_Render_Plain_Table extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variable names (type, attr, span)
extract($options);
$pad = ' ';
switch ($type) {
case 'table_start':
return;
break;
case 'table_end':
return;
break;
case 'row_start':
return;
break;
case 'row_end':
return " ||\n";
break;
case 'cell_start':
return " || ";
break;
case 'cell_end':
return;
break;
default:
return '';
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render/Plain.php
New file
0,0 → 1,16
<?php
 
class Text_Wiki_Render_Plain extends Text_Wiki_Render {
function pre()
{
return;
}
function post()
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse.php
New file
0,0 → 1,253
<?php
 
/**
*
* Baseline rule class for extension into a "real" parser component.
*
* Text_Wiki_Rule classes do not stand on their own; they are called by a
* Text_Wiki object, typcially in the transform()method. Each rule class
* performs three main activities: parse, process, and render.
*
* The parse() method takes a regex and applies it to the whole block of
* source text at one time. Each match is sent as $matches to the
* process() method.
*
* The process() method acts on the matched text from the source, and
* then processes the source text is some way. This may mean the
* creation of a delimited token using addToken(). In every case, the
* process() method returns the text that should replace the matched text
* from parse().
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
* $Id: Parse.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
*/
 
class Text_Wiki_Parse {
/**
*
* Configuration options for this parser rule.
*
* @access public
*
* @var string
*
*/
var $conf = array();
/**
*
* Regular expression to find matching text for this rule.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = null;
/**
*
* The name of this rule for new token array elements.
*
* @access public
*
* @var string
*
*/
var $rule = null;
/**
*
* A reference to the calling Text_Wiki object.
*
* This is needed so that each rule has access to the same source
* text, token set, URLs, interwiki maps, page names, etc.
*
* @access public
*
* @var object
*/
var $wiki = null;
/**
*
* Constructor for this parser rule.
*
* @access public
*
* @param object &$obj The calling "parent" Text_Wiki object.
*
*/
function Text_Wiki_Parse(&$obj)
{
// set the reference to the calling Text_Wiki object;
// this allows us access to the shared source text, token
// array, etc.
$this->wiki =& $obj;
// set the name of this rule; generally used when adding
// to the tokens array. strip off the Text_Wiki_Parse_ portion.
// text_wiki_parse_
// 0123456789012345
$tmp = substr(get_class($this), 16);
$this->rule = ucwords(strtolower($tmp));
// override config options for the rule if specified
if (isset($this->wiki->parseConf[$this->rule]) &&
is_array($this->wiki->parseConf[$this->rule])) {
$this->conf = array_merge(
$this->conf,
$this->wiki->parseConf[$this->rule]
);
}
}
/**
*
* Abstrct method to parse source text for matches.
*
* Applies the rule's regular expression to the source text, passes
* every match to the process() method, and replaces the matched text
* with the results of the processing.
*
* @access public
*
* @see Text_Wiki_Parse::process()
*
*/
function parse()
{
$this->wiki->source = preg_replace_callback(
$this->regex,
array(&$this, 'process'),
$this->wiki->source
);
}
/**
*
* Abstract method to generate replacements for matched text.
*
* @access public
*
* @param array $matches An array of matches from the parse() method
* as generated by preg_replace_callback. $matches[0] is the full
* matched string, $matches[1] is the first matched pattern,
* $matches[2] is the second matched pattern, and so on.
*
* @return string The processed text replacement; defaults to the
* full matched string (i.e., no changes to the text).
*
* @see Text_Wiki_Parse::parse()
*
*/
function process(&$matches)
{
return $matches[0];
}
/**
*
* Simple method to safely get configuration key values.
*
* @access public
*
* @param string $key The configuration key.
*
* @param mixed $default If the key does not exist, return this value
* instead.
*
* @return mixed The configuration key value (if it exists) or the
* default value (if not).
*
*/
function getConf($key, $default = null)
{
if (isset($this->conf[$key])) {
return $this->conf[$key];
} else {
return $default;
}
}
/**
*
* Extract 'attribute="value"' portions of wiki markup.
*
* This kind of markup is typically used only in macros, but is useful
* anywhere.
*
* The syntax is pretty strict; there can be no spaces between the
* option name, the equals, and the first double-quote; the value
* must be surrounded by double-quotes. You can escape characters in
* the value with a backslash, and the backslash will be stripped for
* you.
*
* @access public
*
* @param string $text The "attributes" portion of markup.
*
* @return array An associative array of key-value pairs where the
* key is the option name and the value is the option value.
*
*/
function getAttrs($text)
{
// find the =" sections;
$tmp = explode('="', trim($text));
// basic setup
$k = count($tmp) - 1;
$attrs = array();
$key = null;
// loop through the sections
foreach ($tmp as $i => $val) {
// first element is always the first key
if ($i == 0) {
$key = trim($val);
continue;
}
// find the last double-quote in the value.
// the part to the left is the value for the last key,
// the part to the right is the next key name
$pos = strrpos($val, '"');
$attrs[$key] = stripslashes(substr($val, 0, $pos));
$key = trim(substr($val, $pos+1));
}
return $attrs;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Render.php
New file
0,0 → 1,167
<?php
 
class Text_Wiki_Render {
/**
*
* Configuration options for this render rule.
*
* @access public
*
* @var string
*
*/
var $conf = array();
/**
*
* The name of this rule's format.
*
* @access public
*
* @var string
*
*/
var $format = null;
/**
*
* The name of this rule's token array elements.
*
* @access public
*
* @var string
*
*/
var $rule = null;
/**
*
* A reference to the calling Text_Wiki object.
*
* This is needed so that each rule has access to the same source
* text, token set, URLs, interwiki maps, page names, etc.
*
* @access public
*
* @var object
*/
var $wiki = null;
/**
*
* Constructor for this render format or rule.
*
* @access public
*
* @param object &$obj The calling "parent" Text_Wiki object.
*
*/
function Text_Wiki_Render(&$obj)
{
// keep a reference to the calling Text_Wiki object
$this->wiki =& $obj;
// get the config-key-name for this object,
// strip the Text_Wiki_Render_ part
// 01234567890123456
$tmp = get_class($this);
$tmp = substr($tmp, 17);
// split into pieces at the _ mark.
// first part is format, second part is rule.
$part = explode('_', $tmp);
$this->format = isset($part[0]) ? ucwords(strtolower($part[0])) : null;
$this->rule = isset($part[1]) ? ucwords(strtolower($part[1])) : null;
// is there a format but no rule?
// then this is the "main" render object, with
// pre() and post() methods.
if ($this->format && ! $this->rule &&
isset($this->wiki->formatConf[$this->format]) &&
is_array($this->wiki->formatConf[$this->format])) {
// this is a format render object
$this->conf = array_merge(
$this->conf,
$this->wiki->formatConf[$this->format]
);
}
// is there a format and a rule?
if ($this->format && $this->rule &&
isset($this->wiki->renderConf[$this->format][$this->rule]) &&
is_array($this->wiki->renderConf[$this->format][$this->rule])) {
// this is a rule render object
$this->conf = array_merge(
$this->conf,
$this->wiki->renderConf[$this->format][$this->rule]
);
}
}
/**
*
* Simple method to safely get configuration key values.
*
* @access public
*
* @param string $key The configuration key.
*
* @param mixed $default If the key does not exist, return this value
* instead.
*
* @return mixed The configuration key value (if it exists) or the
* default value (if not).
*
*/
function getConf($key, $default = null)
{
if (isset($this->conf[$key])) {
return $this->conf[$key];
} else {
return $default;
}
}
/**
*
* Simple method to wrap a configuration in an sprintf() format.
*
* @access public
*
* @param string $key The configuration key.
*
* @param string $format The sprintf() format string.
*
* @return mixed The formatted configuration key value (if it exists)
* or null (if it does not).
*
*/
function formatConf($format, $key)
{
if (isset($this->conf[$key])) {
return sprintf($format, $this->conf[$key]);
} else {
return null;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Break.php
New file
0,0 → 1,54
<?php
// $Id: Break.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to mark forced line breaks in the
* source text.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Break extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/ _\n/';
/**
*
* Generates a replacement token for the matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A delimited token to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
return $this->wiki->addToken($this->rule);
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Function.php
New file
0,0 → 1,115
<?php
 
// $Id: Function.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
class Text_Wiki_Parse_Function extends Text_Wiki_Parse {
 
var $regex = '/^(\<function\>)\n(.+)\n(\<\/function\>)(\s|$)/Umsi';
function process(&$matches)
{
// default options
$opts = array(
'name' => null,
'access' => null,
'return' => null,
'params' => array(),
'throws' => array()
);
// split apart the markup lines and loop through them
$lines = explode("\n", $matches[2]);
foreach ($lines as $line) {
// skip blank lines
if (trim($line) == '') {
continue;
}
// find the first ':' on the line; the left part is the
// type, the right part is the value. skip lines without
// a ':' on them.
$pos = strpos($line, ':');
if ($pos === false) {
continue;
}
// $type is the line type: name, access, return, param, throws
// 012345678901234
// name: something
$type = trim(substr($line, 0, $pos));
$val = trim(substr($line, $pos+1));
switch($type) {
case 'a':
case 'access':
$opts['access'] = $val;
break;
case 'n':
case 'name':
$opts['name'] = $val;
break;
case 'p':
case 'param':
$tmp = explode(',', $val);
$k = count($tmp);
if ($k == 1) {
$opts['params'][] = array(
'type' => $tmp[0],
'descr' => null,
'default' => null
);
} elseif ($k == 2) {
$opts['params'][] = array(
'type' => $tmp[0],
'descr' => $tmp[1],
'default' => null
);
} else {
$opts['params'][] = array(
'type' => $tmp[0],
'descr' => $tmp[1],
'default' => $tmp[2]
);
}
break;
case 'r':
case 'return':
case 'returns':
$opts['return'] = $val;
break;
case 't':
case 'throws':
$tmp = explode(',', $val);
$k = count($tmp);
if ($k == 1) {
$opts['throws'][] = array(
'type' => $tmp[0],
'descr' => null
);
} else {
$opts['throws'][] = array(
'type' => $tmp[0],
'descr' => $tmp[1]
);
}
break;
default:
$opts[$type] = $val;
break;
}
}
// add the token back in place
return $this->wiki->addToken($this->rule, $opts) . $matches[4];
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Toc.php
New file
0,0 → 1,112
<?php
// $Id: Toc.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find all heading tokens and
* build a table of contents. The [[toc]] tag gets replaced with a list
* of all the level-2 through level-6 headings.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
 
class Text_Wiki_Parse_Toc extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\n\[\[toc( .*)?\]\]\n/m";
/**
*
* Generates a replacement for the matched text.
*
* Token options are:
*
* 'type' => ['list_start'|'list_end'|'item_start'|'item_end'|'target']
*
* 'level' => The heading level (1-6).
*
* 'count' => Which entry number this is in the list.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A token indicating the TOC collection point.
*
*/
function process(&$matches)
{
$count = 0;
if (isset($matches[1])) {
$attr = $this->getAttrs(trim($matches[1]));
} else {
$attr = array();
}
$output = $this->wiki->addToken(
$this->rule,
array(
'type' => 'list_start',
'level' => 0,
'attr' => $attr
)
);
foreach ($this->wiki->getTokens('Heading') as $key => $val) {
if ($val[1]['type'] != 'start') {
continue;
}
$options = array(
'type' => 'item_start',
'id' => $val[1]['id'],
'level' => $val[1]['level'],
'count' => $count ++
);
$output .= $this->wiki->addToken($this->rule, $options);
$output .= $val[1]['text'];
$output .= $this->wiki->addToken(
$this->rule,
array(
'type' => 'item_end',
'level' => $val[1]['level']
)
);
}
$output .= $this->wiki->addToken(
$this->rule, array(
'type' => 'list_end',
'level' => 0
)
);
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Table.php
New file
0,0 → 1,208
<?php
// $Id: Table.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as a
* set of table rows, where a line start and ends with double-pipes (||)
* and uses double-pipes to separate table cells. The rows must be on
* sequential lines (no blank lines between them) -- a blank line
* indicates the beginning of a new table.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Table extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/\n((\|\|).*)(\n)(?!(\|\|))/Us';
/**
*
* Generates a replacement for the matched text.
*
* Token options are:
*
* 'type' =>
* 'table_start' : the start of a bullet list
* 'table_end' : the end of a bullet list
* 'row_start' : the start of a number list
* 'row_end' : the end of a number list
* 'cell_start' : the start of item text (bullet or number)
* 'cell_end' : the end of item text (bullet or number)
*
* 'cols' => the number of columns in the table (for 'table_start')
*
* 'rows' => the number of rows in the table (for 'table_start')
*
* 'span' => column span (for 'cell_start')
*
* 'attr' => column attribute flag (for 'cell_start')
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A series of text and delimited tokens marking the different
* table elements and cell text.
*
*/
function process(&$matches)
{
// our eventual return value
$return = '';
// the number of columns in the table
$num_cols = 0;
// the number of rows in the table
$num_rows = 0;
// rows are separated by newlines in the matched text
$rows = explode("\n", $matches[1]);
// loop through each row
foreach ($rows as $row) {
// increase the row count
$num_rows ++;
// start a new row
$return .= $this->wiki->addToken(
$this->rule,
array('type' => 'row_start')
);
// cells are separated by double-pipes
$cell = explode("||", $row);
// get the number of cells (columns) in this row
$last = count($cell) - 1;
// is this more than the current column count?
// (we decrease by 1 because we never use cell zero)
if ($last - 1 > $num_cols) {
// increase the column count
$num_cols = $last - 1;
}
// by default, cells span only one column (their own)
$span = 1;
// ignore cell zero, and ignore the "last" cell; cell zero
// is before the first double-pipe, and the "last" cell is
// after the last double-pipe. both are always empty.
for ($i = 1; $i < $last; $i ++) {
// if there is no content at all, then it's an instance
// of two sets of || next to each other, indicating a
// span.
if ($cell[$i] == '') {
// add to the span and loop to the next cell
$span += 1;
continue;
} else {
// this cell has content.
// find any special "attr"ibute cell markers
if (substr($cell[$i], 0, 2) == '> ') {
// right-align
$attr = 'right';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '= ') {
// center-align
$attr = 'center';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '< ') {
// left-align
$attr = 'left';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '~ ') {
$attr = 'header';
$cell[$i] = substr($cell[$i], 2);
} else {
$attr = null;
}
// start a new cell...
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'cell_start',
'attr' => $attr,
'span' => $span
)
);
// ...add the content...
$return .= trim($cell[$i]);
// ...and end the cell.
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'cell_end',
'attr' => $attr,
'span' => $span
)
);
// reset the span.
$span = 1;
}
}
// end the row
$return .= $this->wiki->addToken(
$this->rule,
array('type' => 'row_end')
);
}
// wrap the return value in start and end tokens
$return =
$this->wiki->addToken(
$this->rule,
array(
'type' => 'table_start',
'rows' => $num_rows,
'cols' => $num_cols
)
)
. $return .
$this->wiki->addToken(
$this->rule,
array(
'type' => 'table_end'
)
);
// we're done!
return "\n$return\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Raw.php
New file
0,0 → 1,55
<?php
// $Id: Raw.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki rule to find sections of the source
* text that are not to be processed by Text_Wiki. These blocks of "raw"
* text will be rendered as they were found.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Raw extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = "/``(.*)``/U";
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'text' => The full matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
$options = array('text' => $matches[1]);
return $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Deflist.php
New file
0,0 → 1,104
<?php
// $Id: Deflist.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as a
* definition list. In short, if a line starts with ':' then it is a
* definition list item; another ':' on the same lines indicates the end
* of the definition term and the beginning of the definition narrative.
* The list items must be on sequential lines (no blank lines between
* them) -- a blank line indicates the beginning of a new list.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/\n((: ).*\n)(?!(: |\n))/Us';
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' =>
* 'list_start' : the start of a definition list
* 'list_end' : the end of a definition list
* 'term_start' : the start of a definition term
* 'term_end' : the end of a definition term
* 'narr_start' : the start of definition narrative
* 'narr_end' : the end of definition narrative
* 'unknown' : unknown type of definition portion
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A series of text and delimited tokens marking the different
* list text and list elements.
*
*/
function process(&$matches)
{
// the replacement text we will return to parse()
$return = '';
// the list of post-processing matches
$list = array();
// start the deflist
$options = array('type' => 'list_start');
$return .= $this->wiki->addToken($this->rule, $options);
// $matches[1] is the text matched as a list set by parse();
// create an array called $list that contains a new set of
// matches for the various definition-list elements.
preg_match_all(
'/^(: )(.*)?( : )(.*)?$/Ums',
$matches[1],
$list,
PREG_SET_ORDER
);
// add each term and narrative
foreach ($list as $key => $val) {
$return .= (
$this->wiki->addToken($this->rule, array('type' => 'term_start')) .
trim($val[2]) .
$this->wiki->addToken($this->rule, array('type' => 'term_end')) .
$this->wiki->addToken($this->rule, array('type' => 'narr_start')) .
trim($val[4]) .
$this->wiki->addToken($this->rule, array('type' => 'narr_end'))
);
}
// end the deflist
$options = array('type' => 'list_end');
$return .= $this->wiki->addToken($this->rule, $options);
// done!
return "\n" . $return . "\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Horiz.php
New file
0,0 → 1,52
<?php
// $Id: Horiz.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked to
* be a horizontal rule, as defined by four dashed on their own line.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Horiz extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/^([-]{4,})$/m';
/**
*
* Generates a replacement token for the matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A token marking the horizontal rule.
*
*/
function process(&$matches)
{
return $this->wiki->addToken($this->rule);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Prefilter.php
New file
0,0 → 1,62
<?php
// $Id: Prefilter.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* "Pre-filter" the source text.
*
* Convert DOS and Mac line endings to Unix, concat lines ending in a
* backslash \ with the next line, convert tabs to 4-spaces, add newlines
* to the top and end of the source text, compress 3 or more newlines to
* 2 newlines.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Prefilter extends Text_Wiki_Parse {
/**
*
* Simple parsing method.
*
* @access public
*
*/
function parse()
{
// convert DOS line endings
$this->wiki->source = str_replace("\r\n", "\n",
$this->wiki->source);
// convert Macintosh line endings
$this->wiki->source = str_replace("\r", "\n",
$this->wiki->source);
// concat lines ending in a backslash
$this->wiki->source = str_replace("\\\n", "",
$this->wiki->source);
// convert tabs to four-spaces
$this->wiki->source = str_replace("\t", " ",
$this->wiki->source);
// add extra newlines at the top and end; this
// seems to help many rules.
$this->wiki->source = "\n" . $this->wiki->source . "\n\n";
// finally, compress all instances of 3 or more newlines
// down to two newlines.
$find = "/\n{3,}/m";
$replace = "\n\n";
$this->wiki->source = preg_replace($find, $replace,
$this->wiki->source);
}
 
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Heading.php
New file
0,0 → 1,89
<?php
// $Id: Heading.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked to
* be a heading element, as defined by text on a line by itself prefixed
* with a number of plus signs (+). The heading text itself is left in
* the source, but is prefixed and suffixed with delimited tokens marking
* the start and end of the heading.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Heading extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/^(\+{1,6}) (.*)/m';
var $conf = array(
'id_prefix' => 'toc'
);
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* heading text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the heading text.
*
*/
function process(&$matches)
{
// keep a running count for header IDs. we use this later
// when constructing TOC entries, etc.
static $id;
if (! isset($id)) {
$id = 0;
}
$prefix = htmlspecialchars($this->getConf('id_prefix'));
$start = $this->wiki->addToken(
$this->rule,
array(
'type' => 'start',
'level' => strlen($matches[1]),
'text' => $matches[2],
'id' => $prefix . $id ++
)
);
$end = $this->wiki->addToken(
$this->rule,
array(
'type' => 'end',
'level' => strlen($matches[1])
)
);
return $start . $matches[2] . $end . "\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Tighten.php
New file
0,0 → 1,32
<?php
// $Id: Tighten.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* The rule removes all remaining newlines.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Tighten extends Text_Wiki_Parse {
/**
*
* Apply tightening directly to the source text.
*
* @access public
*
*/
function parse()
{
$this->wiki->source = str_replace("\n", '',
$this->wiki->source);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Html.php
New file
0,0 → 1,57
<?php
// $Id: Html.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as
* HTML to be redndred as-is. The block start is marked by <html> on its
* own line, and the block end is marked by </html> on its own line.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Html extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/^\<html\>\n(.+)\n\<\/html\>(\s|$)/Umsi';
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'text' => The text of the HTML to be rendered as-is.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text following the HTML block.
*
*/
function process(&$matches)
{
$options = array('text' => $matches[1]);
return $this->wiki->addToken($this->rule, $options) . $matches[2];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Interwiki.php
New file
0,0 → 1,120
<?php
// $Id: Interwiki.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as
* an Interwiki link. See the regex for a detailed explanation of the
* text matching procedure; e.g., "InterWikiName:PageName".
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Interwiki extends Text_Wiki_Parse {
var $regex = '([A-Za-z0-9_]+):([\/=&~#A-Za-z0-9_]+)';
/**
*
* Parser. We override the standard parser so we can
* find both described interwiki links and standalone links.
*
* @access public
*
* @return void
*
*/
function parse()
{
// described interwiki links
$tmp_regex = '/\[' . $this->regex . ' (.+?)\]/';
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'processDescr'),
$this->wiki->source
);
// standalone interwiki links
$tmp_regex = '/' . $this->regex . '/';
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'process'),
$this->wiki->source
);
}
/**
*
* Generates a replacement for the matched standalone interwiki text.
* Token options are:
*
* 'site' => The key name for the Text_Wiki interwiki array map,
* usually the name of the interwiki site.
*
* 'page' => The page on the target interwiki to link to.
*
* 'text' => The text to display as the link.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text priot to the match.
*
*/
function process(&$matches)
{
$options = array(
'site' => $matches[1],
'page' => $matches[2],
'text' => $matches[0]
);
return $this->wiki->addToken($this->rule, $options);
}
/**
*
* Generates a replacement for described interwiki links. Token
* options are:
*
* 'site' => The key name for the Text_Wiki interwiki array map,
* usually the name of the interwiki site.
*
* 'page' => The page on the target interwiki to link to.
*
* 'text' => The text to display as the link.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text priot to the match.
*
*/
function processDescr(&$matches)
{
$options = array(
'site' => $matches[1],
'page' => $matches[2],
'text' => $matches[3]
);
return $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Italic.php
New file
0,0 → 1,67
<?php
// $Id: Italic.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* emphasis (italics) as defined by text surrounded by two single-quotes.
* On parsing, the text itself is left in place, but the starting and ending
* instances of two single-quotes are replaced with tokens.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Italic extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/''(()|[^'].*)''/U";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the text to be
* emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Paragraph.php
New file
0,0 → 1,128
<?php
// $Id: Paragraph.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki rule to find sections of the source
* text that are paragraphs. A para is any line not starting with a token
* delimiter, followed by two newlines.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Paragraph extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = "/^.*?\n\n/m";
var $conf = array(
'skip' => array(
'blockquote', // are we sure about this one?
'code',
'heading',
'horiz',
'deflist',
'table',
'list',
'toc'
)
);
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'start' => The starting point of the paragraph.
*
* 'end' => The ending point of the paragraph.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
$delim = $this->wiki->delim;
// was anything there?
if (trim($matches[0]) == '') {
return '';
}
// does the match start with a delimiter?
if (substr($matches[0], 0, 1) != $delim) {
// no.
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . trim($matches[0]) . $end;
}
// the line starts with a delimiter. read in the delimited
// token number, check the token, and see if we should
// skip it.
// loop starting at the second character (we already know
// the first is a delimiter) until we find another
// delimiter; the text between them is a token key number.
$key = '';
$len = strlen($matches[0]);
for ($i = 1; $i < $len; $i++) {
$char = $matches[0]{$i};
if ($char == $delim) {
break;
} else {
$key .= $char;
}
}
// look at the token and see if it's skippable (if we skip,
// it will not be marked as a paragraph)
$token_type = strtolower($this->wiki->tokens[$key][0]);
$skip = $this->getConf('skip', array());
if (in_array($token_type, $skip)) {
// this type of token should not have paragraphs applied to it.
// return the entire matched text.
return $matches[0];
} else {
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . trim($matches[0]) . $end;
}
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Blockquote.php
New file
0,0 → 1,163
<?php
 
/**
*
* Parse for block-quoted text.
*
* Find source text marked as a blockquote, identified by any number of
* greater-than signs '>' at the start of the line, followed by a space,
* and then the quote text; each '>' indicates an additional level of
* quoting.
*
* $Id: Blockquote.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Blockquote extends Text_Wiki_Parse {
/**
*
* Regex for parsing the source text.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/\n((\>).*\n)(?!(\>))/Us';
/**
*
* Generates a replacement for the matched text.
*
* Token options are:
*
* 'type' =>
* 'start' : the start of a blockquote
* 'end' : the end of a blockquote
*
* 'level' => the indent level (0 for the first level, 1 for the
* second, etc)
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A series of text and delimited tokens marking the different
* list text and list elements.
*
*/
function process(&$matches)
{
// the replacement text we will return to parse()
$return = '';
// the list of post-processing matches
$list = array();
// $matches[1] is the text matched as a list set by parse();
// create an array called $list that contains a new set of
// matches for the various list-item elements.
preg_match_all(
'=^(\>+) (.*\n)=Ums',
$matches[1],
$list,
PREG_SET_ORDER
);
// a stack of starts and ends; we keep this so that we know what
// indent level we're at.
$stack = array();
// loop through each list-item element.
foreach ($list as $key => $val) {
// $val[0] is the full matched list-item line
// $val[1] is the number of initial '>' chars (indent level)
// $val[2] is the quote text
// we number levels starting at 1, not zero
$level = strlen($val[1]);
// get the text of the line
$text = $val[2];
// add a level to the list?
while ($level > count($stack)) {
// the current indent level is greater than the number
// of stack elements, so we must be starting a new
// level. push the new level onto the stack with a
// dummy value (boolean true)...
array_push($stack, true);
$return .= "\n";
// ...and add a start token to the return.
$return .= $this->wiki->addToken(
$this->rule,
array(
'type' => 'start',
'level' => $level - 1
)
);
$return .= "\n\n";
}
// remove a level?
while (count($stack) > $level) {
// as long as the stack count is greater than the
// current indent level, we need to end list types.
// continue adding end-list tokens until the stack count
// and the indent level are the same.
array_pop($stack);
$return .= "\n\n";
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'end',
'level' => count($stack)
)
);
$return .= "\n";
}
// add the line text.
$return .= $text;
}
// the last line may have been indented. go through the stack
// and create end-tokens until the stack is empty.
$return .= "\n";
while (count($stack) > 0) {
array_pop($stack);
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'end',
'level' => count($stack)
)
);
}
// we're done! send back the replacement text.
return "\n$return\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Anchor.php
New file
0,0 → 1,67
<?php
 
/**
*
* This class implements a Text_Wiki_Parse to add an anchor target name
* in the wiki page.
*
* @author Manuel Holtgrewe <purestorm at ggnore dot net>
*
* @author Paul M. Jones <pmjones at ciaweb dot net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Anchor extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/(\[\[# )([-_A-Za-z0-9.]+?)( .+)?(\]\])/i';
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'text' => The full matched text, not including the <code></code> tags.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches) {
$name = $matches[2];
$text = $matches[3];
$start = $this->wiki->addToken(
$this->rule,
array('type' => 'start', 'name' => $name)
);
$end = $this->wiki->addToken(
$this->rule,
array('type' => 'end', 'name' => $name)
);
// done, place the script output directly in the source
return $start . trim($text) . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/List.php
New file
0,0 → 1,230
<?php
// $Id: List.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as
* a bulleted or numbered list. In short, if a line starts with '* ' then
* it is a bullet list item; if a line starts with '# ' then it is a
* number list item. Spaces in front of the * or # indicate an indented
* sub-list. The list items must be on sequential lines, and may be
* separated by blank lines to improve readability. Using a non-* non-#
* non-whitespace character at the beginning of a line ends the list.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_List extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/\n((\*|#) .*\n)(?! {0,}(\* |# |\n))/Us';
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' =>
* 'bullet_start' : the start of a bullet list
* 'bullet_end' : the end of a bullet list
* 'number_start' : the start of a number list
* 'number_end' : the end of a number list
* 'item_start' : the start of item text (bullet or number)
* 'item_end' : the end of item text (bullet or number)
* 'unknown' : unknown type of list or item
*
* 'level' => the indent level (0 for the first level, 1 for the
* second, etc)
*
* 'count' => the list item number at this level. not needed for
* xhtml, but very useful for PDF and RTF.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A series of text and delimited tokens marking the different
* list text and list elements.
*
*/
function process(&$matches)
{
// the replacement text we will return
$return = '';
// the list of post-processing matches
$list = array();
// a stack of list-start and list-end types; we keep this
// so that we know what kind of list we're working with
// (bullet or number) and what indent level we're at.
$stack = array();
// the item count is the number of list items for any
// given list-type on the stack
$itemcount = array();
// have we processed the very first list item?
$pastFirst = false;
// populate $list with this set of matches. $matches[1] is the
// text matched as a list set by parse().
preg_match_all(
'=^( {0,})(\*|#) (.*)$=Ums',
$matches[1],
$list,
PREG_SET_ORDER
);
// loop through each list-item element.
foreach ($list as $key => $val) {
// $val[0] is the full matched list-item line
// $val[1] is the number of initial spaces (indent level)
// $val[2] is the list item type (* or #)
// $val[3] is the list item text
// how many levels are we indented? (1 means the "root"
// list level, no indenting.)
$level = strlen($val[1]) + 1;
// get the list item type
if ($val[2] == '*') {
$type = 'bullet';
} elseif ($val[2] == '#') {
$type = 'number';
} else {
$type = 'unknown';
}
// get the text of the list item
$text = $val[3];
// add a level to the list?
if ($level > count($stack)) {
// the current indent level is greater than the
// number of stack elements, so we must be starting
// a new list. push the new list type onto the
// stack...
array_push($stack, $type);
// ...and add a list-start token to the return.
$return .= $this->wiki->addToken(
$this->rule,
array(
'type' => $type . '_list_start',
'level' => $level - 1
)
);
}
// remove a level from the list?
while (count($stack) > $level) {
// so we don't keep counting the stack, we set up a temp
// var for the count. -1 becuase we're going to pop the
// stack in the next command. $tmp will then equal the
// current level of indent.
$tmp = count($stack) - 1;
// as long as the stack count is greater than the
// current indent level, we need to end list types.
// continue adding end-list tokens until the stack count
// and the indent level are the same.
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => array_pop($stack) . '_list_end',
'level' => $tmp
)
);
// reset to the current (previous) list type so that
// the new list item matches the proper list type.
$type = $stack[$tmp - 1];
// reset the item count for the popped indent level
unset($itemcount[$tmp + 1]);
}
// add to the item count for this list (taking into account
// which level we are at).
if (! isset($itemcount[$level])) {
// first count
$itemcount[$level] = 0;
} else {
// increment count
$itemcount[$level]++;
}
// is this the very first item in the list?
if (! $pastFirst) {
$first = true;
$pastFirst = true;
} else {
$first = false;
}
// create a list-item starting token.
$start = $this->wiki->addToken(
$this->rule,
array(
'type' => $type . '_item_start',
'level' => $level,
'count' => $itemcount[$level],
'first' => $first
)
);
// create a list-item ending token.
$end = $this->wiki->addToken(
$this->rule,
array(
'type' => $type . '_item_end',
'level' => $level,
'count' => $itemcount[$level]
)
);
// add the starting token, list-item text, and ending token
// to the return.
$return .= $start . $val[3] . $end;
}
// the last list-item may have been indented. go through the
// list-type stack and create end-list tokens until the stack
// is empty.
while (count($stack) > 0) {
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => array_pop($stack) . '_list_end',
'level' => count($stack)
)
);
}
// we're done! send back the replacement text.
return "\n" . $return . "\n\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Embed.php
New file
0,0 → 1,88
<?php
// $Id: Embed.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to embed the contents of a URL
* inside the page at render-time. Typically used to get script output.
* This differs from the 'include' rule, which incorporates results at
* parse-time; 'embed' output does not get parsed by Text_Wiki, while
* 'include' ouput does.
*
* This rule is inherently not secure; it allows cross-site scripting to
* occur if the embedded output has <script> or other similar tags. Be
* careful.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Embed extends Text_Wiki_Parse {
var $conf = array(
'base' => '/path/to/scripts/'
);
var $file = null;
 
var $output = null;
 
var $vars = null;
 
 
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/(\[\[embed )(.+?)( .+?)?(\]\])/i';
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'text' => The full matched text, not including the <code></code> tags.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
// save the file location
$this->file = $this->getConf('base', './') . $matches[2];
// extract attribs as variables in the local space
$this->vars = $this->getAttrs($matches[3]);
unset($this->vars['this']);
extract($this->vars);
// run the script
ob_start();
include($this->file);
$this->output = ob_get_contents();
ob_end_clean();
// done, place the script output directly in the source
return $this->wiki->addToken(
$this->rule,
array('text' => $this->output)
);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Delimiter.php
New file
0,0 → 1,62
<?php
// $Id: Delimiter.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find instances of the delimiter
* character already embedded in the source text; it extracts them and replaces
* them with a delimited token, then renders them as the delimiter itself
* when the target format is XHTML.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Delimiter extends Text_Wiki_Parse {
/**
*
* Constructor. Overrides the Text_Wiki_Parse constructor so that we
* can set the $regex property dynamically (we need to include the
* Text_Wiki $delim character.
*
* @param object &$obj The calling "parent" Text_Wiki object.
*
* @param string $name The token name to use for this rule.
*
*/
function Text_Wiki_Parse_delimiter(&$obj)
{
parent::Text_Wiki_Parse($obj);
$this->regex = '/' . $this->wiki->delim . '/';
}
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'text' => The full matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
return $this->wiki->addToken(
$this->rule,
array('text' => $this->wiki->delim)
);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Bold.php
New file
0,0 → 1,61
<?php
// $Id: Bold.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Rule to find source text marked for
* strong emphasis (bold) as defined by text surrounded by three
* single-quotes. On parsing, the text itself is left in place, but the
* starting and ending instances of three single-quotes are replaced with
* tokens.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Bold extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/'''(()|[^'].*)'''/U";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A pair of delimited tokens to be used as a placeholder in
* the source text surrounding the text to be emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken($this->rule, array('type' => 'start'));
$end = $this->wiki->addToken($this->rule, array('type' => 'end'));
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Wikilink.php
New file
0,0 → 1,158
<?php
 
/**
*
* Parse for links to wiki pages.
*
* Wiki page names are typically in StudlyCapsStyle made of
* WordsSmashedTogether.
*
* You can also create described links to pages in this style:
* [WikiPageName nice text link to use for display]
*
* The token options for this rule are:
*
* 'page' => the wiki page name.
*
* 'text' => the displayed link text.
*
* 'anchor' => a named anchor on the target wiki page.
*
* $Id: Wikilink.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Wikilink extends Text_Wiki_Parse {
/**
*
* Constructor.
*
* We override the Text_Wiki_Parse constructor so we can
* explicitly comment each part of the $regex property.
*
* @access public
*
* @param object &$obj The calling "parent" Text_Wiki object.
*
*/
function Text_Wiki_Parse_Wikilink(&$obj)
{
parent::Text_Wiki_Parse($obj);
// allows numbers as "lowercase letters" in the regex
$this->regex =
"(!?" . // START WikiPage pattern (1)
"[A-Z]" . // 1 upper
"[A-Za-z0-9]*" . // 0+ alpha or digit
"[a-z0-9]+" . // 1+ lower or digit
"[A-Z]" . // 1 upper
"[A-Za-z0-9]*" . // 0+ or more alpha or digit
")" . // END WikiPage pattern (/1)
"((\#" . // START Anchor pattern (2)(3)
"[A-Za-z]" . // 1 alpha
"(" . // start sub pattern (4)
"[-A-Za-z0-9_:.]*" . // 0+ dash, alpha, digit, underscore, colon, dot
"[-A-Za-z0-9_]" . // 1 dash, alpha, digit, or underscore
")?)?)"; // end subpatterns (/4)(/3)(/2)
}
/**
*
* First parses for described links, then for standalone links.
*
* @access public
*
* @return void
*
*/
function parse()
{
// described wiki links
$tmp_regex = '/\[' . $this->regex . ' (.+?)\]/';
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'processDescr'),
$this->wiki->source
);
// standalone wiki links
$tmp_regex = '/(^|[^A-Za-z0-9\-_])' . $this->regex . '/';
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'process'),
$this->wiki->source
);
}
/**
*
* Generate a replacement for described links.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text priot to the match.
*
*/
function processDescr(&$matches)
{
// set the options
$options = array(
'page' => $matches[1],
'text' => $matches[5],
'anchor' => $matches[3]
);
// create and return the replacement token and preceding text
return $this->wiki->addToken($this->rule, $options); // . $matches[7];
}
/**
*
* Generate a replacement for standalone links.
*
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text prior to the match.
*
*/
function process(&$matches)
{
// when prefixed with !, it's explicitly not a wiki link.
// return everything as it was.
if ($matches[2]{0} == '!') {
return $matches[1] . substr($matches[2], 1) . $matches[3];
}
// set the options
$options = array(
'page' => $matches[2],
'text' => $matches[2] . $matches[3],
'anchor' => $matches[3]
);
// create and return the replacement token and preceding text
return $matches[1] . $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Image.php
New file
0,0 → 1,76
<?php
// $Id: Image.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to embed the contents of a URL
* inside the page. Typically used to get script output.
*
* This rule is inherently not secure; it allows cross-site scripting to
* occur if the embedded output has <script> or other similar tags. Be
* careful.
*
* In the future, we'll add a rule config options to set the base embed
* path so that it is limited to one directory.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Image extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/(\[\[image )(.+?)(\]\])/i';
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'src' => The image source, typically a relative path name.
*
* 'opts' => Any macro options following the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
$pos = strpos($matches[2], ' ');
if ($pos === false) {
$options = array(
'src' => $matches[2],
'attr' => array());
} else {
// everything after the space is attribute arguments
$options = array(
'src' => substr($matches[2], 0, $pos),
'attr' => $this->getAttrs(substr($matches[2], $pos+1))
);
}
return $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Tt.php
New file
0,0 → 1,69
<?php
 
/**
*
* Find source text marked for teletype (monospace).
*
* Defined by text surrounded by two curly braces. On parsing, the text
* itself is left in place, but the starting and ending instances of
* curly braces are replaced with tokens.
*
* Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* teletype text. The text itself is left in the source.
*
*
* $Id: Tt.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Tt extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/{{({*?.*}*?)}}/U";
/**
*
* Generates a replacement for the matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the teletype text.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Revise.php
New file
0,0 → 1,130
<?php
// $Id: Revise.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* revision.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Revise extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\@\@({*?.*}*?)\@\@/U";
/**
*
* Config options.
*
* @access public
*
* @var array
*
*/
var $conf = array(
'delmark' => '---',
'insmark' => '+++'
);
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* inserted text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the teletype text.
*
*/
function process(&$matches)
{
$output = '';
$src = $matches[1];
$delmark = $this->getConf('delmark'); // ---
$insmark = $this->getConf('insmark'); // +++
// '---' must be before '+++' (if they both appear)
$del = strpos($src, $delmark);
$ins = strpos($src, $insmark);
// if neither is found, return right away
if ($del === false && $ins === false) {
return $matches[0];
}
// handle text to be deleted
if ($del !== false) {
// move forward to the end of the deletion mark
$del += strlen($delmark);
if ($ins === false) {
// there is no insertion text following
$text = substr($src, $del);
} else {
// there is insertion text following,
// mitigate the length
$text = substr($src, $del, $ins - $del);
}
$output .= $this->wiki->addToken(
$this->rule, array('type' => 'del_start')
);
$output .= $text;
$output .= $this->wiki->addToken(
$this->rule, array('type' => 'del_end')
);
}
// handle text to be inserted
if ($ins !== false) {
// move forward to the end of the insert mark
$ins += strlen($insmark);
$text = substr($src, $ins);
$output .= $this->wiki->addToken(
$this->rule, array('type' => 'ins_start')
);
$output .= $text;
$output .= $this->wiki->addToken(
$this->rule, array('type' => 'ins_end')
);
}
return $output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Freelink.php
New file
0,0 → 1,111
<?php
// $Id: Freelink.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked as a
* wiki freelink, and automatically create a link to that page.
*
* A freelink is any page name not conforming to the standard
* StudlyCapsStyle for a wiki page name. For example, a page normally
* named MyHomePage can be renamed and referred to as ((My Home Page)) --
* note the spaces in the page name. You can also make a "nice-looking"
* link without renaming the target page; e.g., ((MyHomePage|My Home
* Page)). Finally, you can use named anchors on the target page:
* ((MyHomePage|My Home Page#Section1)).
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Freelink extends Text_Wiki_Parse {
/**
*
* Constructor. We override the Text_Wiki_Parse constructor so we can
* explicitly comment each part of the $regex property.
*
* @access public
*
* @param object &$obj The calling "parent" Text_Wiki object.
*
*/
function Text_Wiki_Parse_Freelink(&$obj)
{
parent::Text_Wiki_Parse($obj);
$this->regex =
'/' . // START regex
"\\(\\(" . // double open-parens
"(" . // START freelink page patter
"[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
")" . // END freelink page pattern
"(" . // START display-name
"\|" . // a pipe to start the display name
"[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
")?" . // END display-name pattern 0 or 1
"(" . // START pattern for named anchors
"\#" . // a hash mark
"[A-Za-z]" . // 1 alpha
"[-A-Za-z0-9_:.]*" . // 0 or more alpha, digit, underscore
")?" . // END named anchors pattern 0 or 1
"()\\)\\)" . // double close-parens
'/'; // END regex
}
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'page' => the wiki page name (e.g., HomePage).
*
* 'text' => alternative text to be displayed in place of the wiki
* page name.
*
* 'anchor' => a named anchor on the target wiki page
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token to be used as a placeholder in
* the source text, plus any text priot to the match.
*
*/
function process(&$matches)
{
// use nice variable names
$page = $matches[1];
$text = $matches[2];
// get rid of the leading # from the anchor, if any
$anchor = substr($matches[3], 1);
// is the page given a new text appearance?
if (trim($text) == '') {
// no
$text = $page;
} else {
// yes, strip the leading | character
$text = substr($text, 1);
}
// set the options
$options = array(
'page' => $page,
'text' => $text,
'anchor' => $anchor
);
// return a token placeholder
return $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Newline.php
New file
0,0 → 1,57
<?php
// $Id: Newline.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to mark implied line breaks in the
* source text, usually a single carriage return in the middle of a paragraph
* or block-quoted text.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Newline extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = '/([^\n])\n([^\n])/m';
/**
*
* Generates a replacement token for the matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A delimited token to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
return $matches[1] .
$this->wiki->addToken($this->rule) .
$matches[2];
}
}
 
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Url.php
New file
0,0 → 1,265
<?php
 
/**
*
* Parse for URLS in the source text.
*
* Various URL markings are supported: inline (the URL by itself),
* numbered or footnote reference (where the URL is enclosed in square brackets), and
* named reference (where the URL is enclosed in square brackets and has a
* name included inside the brackets). E.g.:
*
* inline -- http://example.com
* numbered -- [http://example.com]
* described -- [http://example.com Example Description]
*
* When rendering a URL token, this will convert URLs pointing to a .gif,
* .jpg, or .png image into an inline <img /> tag (for the 'xhtml'
* format).
*
* Token options are:
*
* 'type' => ['inline'|'footnote'|'descr'] the type of URL
*
* 'href' => the URL link href portion
*
* 'text' => the displayed text of the URL link
*
* $Id: Url.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Url extends Text_Wiki_Parse {
/**
*
* Keeps a running count of numbered-reference URLs.
*
* @access public
*
* @var int
*
*/
var $footnoteCount = 0;
/**
*
* URL schemes recognized by this rule.
*
* @access public
*
* @var array
*
*/
var $conf = array(
'schemes' => array(
'http://',
'https://',
'ftp://',
'gopher://',
'news://',
'mailto:'
)
);
/**
*
* Constructor.
*
* We override the constructor so we can comment the regex nicely.
*
* @access public
*
*/
function Text_Wiki_Parse_Url(&$obj)
{
parent::Text_Wiki_Parse($obj);
// convert the list of recognized schemes to a regex-safe string,
// where the pattern delim is a slash
$tmp = array();
$list = $this->getConf('schemes', array());
foreach ($list as $val) {
$tmp[] = preg_quote($val, '/');
}
$schemes = implode('|', $tmp);
// build the regex
$this->regex =
"($schemes)" . // allowed schemes
"(" . // start pattern
"[^ \\/\"\'{$this->wiki->delim}]*\\/" . // no spaces, backslashes, slashes, double-quotes, single quotes, or delimiters;
")*" . // end pattern
"[^ \\t\\n\\/\"\'{$this->wiki->delim}]*" .
"[A-Za-z0-9\\/?=&~_]";
}
/**
*
* Find three different kinds of URLs in the source text.
*
* @access public
*
*/
function parse()
{
// -------------------------------------------------------------
//
// Described-reference (named) URLs.
//
// the regular expression for this kind of URL
$tmp_regex = '/\[(' . $this->regex . ') ([^\]]+)\]/';
// use a custom callback processing method to generate
// the replacement text for matches.
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'processDescr'),
$this->wiki->source
);
// -------------------------------------------------------------
//
// Numbered-reference (footnote-style) URLs.
//
// the regular expression for this kind of URL
$tmp_regex = '/\[(' . $this->regex . ')\]/U';
// use a custom callback processing method to generate
// the replacement text for matches.
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'processFootnote'),
$this->wiki->source
);
// -------------------------------------------------------------
//
// Normal inline URLs.
//
// the regular expression for this kind of URL
$tmp_regex = '/(^|[^A-Za-z])(' . $this->regex . ')(.*?)/';
// use the standard callback for inline URLs
$this->wiki->source = preg_replace_callback(
$tmp_regex,
array(&$this, 'process'),
$this->wiki->source
);
}
/**
*
* Process inline URLs.
*
* @param array &$matches
*
* @param array $matches An array of matches from the parse() method
* as generated by preg_replace_callback. $matches[0] is the full
* matched string, $matches[1] is the first matched pattern,
* $matches[2] is the second matched pattern, and so on.
*
* @return string The processed text replacement.
*
*/
function process(&$matches)
{
// set options
$options = array(
'type' => 'inline',
'href' => $matches[2],
'text' => $matches[2]
);
// tokenize
return $matches[1] . $this->wiki->addToken($this->rule, $options) . $matches[5];
}
/**
*
* Process numbered (footnote) URLs.
*
* Token options are:
* @param array &$matches
*
* @param array $matches An array of matches from the parse() method
* as generated by preg_replace_callback. $matches[0] is the full
* matched string, $matches[1] is the first matched pattern,
* $matches[2] is the second matched pattern, and so on.
*
* @return string The processed text replacement.
*
*/
function processFootnote(&$matches)
{
// keep a running count for footnotes
$this->footnoteCount++;
// set options
$options = array(
'type' => 'footnote',
'href' => $matches[1],
'text' => $this->footnoteCount
);
// tokenize
return $this->wiki->addToken($this->rule, $options);
}
/**
*
* Process described-reference (named-reference) URLs.
*
* Token options are:
* 'type' => ['inline'|'footnote'|'descr'] the type of URL
* 'href' => the URL link href portion
* 'text' => the displayed text of the URL link
*
* @param array &$matches
*
* @param array $matches An array of matches from the parse() method
* as generated by preg_replace_callback. $matches[0] is the full
* matched string, $matches[1] is the first matched pattern,
* $matches[2] is the second matched pattern, and so on.
*
* @return string The processed text replacement.
*
*/
function processDescr(&$matches)
{
// set options
$options = array(
'type' => 'descr',
'href' => $matches[1],
'text' => $matches[4]
);
// tokenize
return $this->wiki->addToken($this->rule, $options);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Emphasis.php
New file
0,0 → 1,67
<?php
// $Id: Emphasis.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* emphasis (italics) as defined by text surrounded by two single-quotes.
* On parsing, the text itself is left in place, but the starting and ending
* instances of two single-quotes are replaced with tokens.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_emphasis extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\/\/(()|.*)\/\//U";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the text to be
* emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Code.php
New file
0,0 → 1,72
<?php
// $Id: Code.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find sections marked as code
* examples. Blocks are marked as the string <code> on a line by itself,
* followed by the inline code example, and terminated with the string
* </code> on a line by itself. The code example is run through the
* native PHP highlight_string() function to colorize it, then surrounded
* with <pre>...</pre> tags when rendered as XHTML.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Code extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/^(\<code( .+)?\>)\n(.+)\n(\<\/code\>)(\s|$)/Umsi';
/**
*
* Generates a token entry for the matched text. Token options are:
*
* 'text' => The full matched text, not including the <code></code> tags.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
// are there additional attribute arguments?
$args = trim($matches[2]);
if ($args == '') {
$options = array(
'text' => $matches[3],
'attr' => array('type' => '')
);
} else {
$options = array(
'text' => $matches[3],
'attr' => $this->getAttrs($args)
);
}
return $this->wiki->addToken($this->rule, $options) . $matches[5];
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Strong.php
New file
0,0 → 1,67
<?php
// $Id: Strong.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* strong emphasis (bold) as defined by text surrounded by three
* single-quotes. On parsing, the text itself is left in place, but the
* starting and ending instances of three single-quotes are replaced with
* tokens.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Strong extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\*\*(()|.*)\*\*/U";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A pair of delimited tokens to be used as a placeholder in
* the source text surrounding the text to be emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Center.php
New file
0,0 → 1,60
<?php
// $Id: Center.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find lines marked for centering.
* The line must start with "= " (i.e., an equal-sign followed by a space).
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Center extends Text_Wiki_Parse {
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/\n\= (.*?)\n/';
/**
*
* Generates a token entry for the matched text.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A delimited token number to be used as a placeholder in
* the source text.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule,
array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule,
array('type' => 'end')
);
return "\n" . $start . $matches[1] . $end . "\n";
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Phplookup.php
New file
0,0 → 1,58
<?php
// $Id: Phplookup.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* Find source text marked for
* lookup in the PHP online manual.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Phplookup extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\[\[php (.+?)\]\]/";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* teletype text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the teletype text.
*
*/
function process(&$matches)
{
return $this->wiki->addToken(
$this->rule, array('text' => $matches[1])
);
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Colortext.php
New file
0,0 → 1,74
<?php
// $Id: Colortext.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* coloring.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Colortext extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\#\#(.+?)\|(.+?)\#\#/";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* 'color' => the color indicator
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return string A pair of delimited tokens to be used as a
* placeholder in the source text surrounding the text to be
* emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule,
array(
'type' => 'start',
'color' => $matches[1]
)
);
$end = $this->wiki->addToken(
$this->rule,
array(
'type' => 'end',
'color' => $matches[1]
)
);
return $start . $matches[2] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Include.php
New file
0,0 → 1,84
<?php
// $Id: Include.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to include the results of a
* script directly into the source at parse-time; thus, the output of the
* script will be parsed by Text_Wiki. This differs from the 'embed'
* rule, which incorporates the results at render-time, meaning that the
* 'embed' content is not parsed by Text_Wiki.
*
* DANGER!
*
* This rule is inherently not secure; it allows cross-site scripting to
* occur if the embedded output has <script> or other similar tags. Be
* careful.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Include extends Text_Wiki_Parse {
var $conf = array(
'base' => '/path/to/scripts/'
);
var $file = null;
var $output = null;
var $vars = null;
 
/**
*
* The regular expression used to find source text matching this
* rule.
*
* @access public
*
* @var string
*
*/
var $regex = '/(\[\[include )(.+?)( .+?)?(\]\])/i';
/**
*
* Includes the results of the script directly into the source; the output
* will subsequently be parsed by the remaining Text_Wiki rules.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return The results of the included script.
*
*/
function process(&$matches)
{
// save the file location
$this->file = $this->getConf('base', './') . $matches[2];
 
// extract attribs as variables in the local space
$this->vars = $this->getAttrs($matches[3]);
unset($this->vars['this']);
extract($this->vars);
 
// run the script
ob_start();
include($this->file);
$this->output = ob_get_contents();
ob_end_clean();
// done, place the script output directly in the source
return $this->output;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki/Parse/Superscript.php
New file
0,0 → 1,67
<?php
// $Id: Superscript.php,v 1.1 2005-01-20 19:43:20 jpm Exp $
 
 
/**
*
* This class implements a Text_Wiki_Parse to find source text marked for
* strong emphasis (bold) as defined by text surrounded by three
* single-quotes. On parsing, the text itself is left in place, but the
* starting and ending instances of three single-quotes are replaced with
* tokens.
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
*/
 
class Text_Wiki_Parse_Superscript extends Text_Wiki_Parse {
/**
*
* The regular expression used to parse the source text and find
* matches conforming to this rule. Used by the parse() method.
*
* @access public
*
* @var string
*
* @see parse()
*
*/
var $regex = "/\^\^(()|.*)\^\^/U";
/**
*
* Generates a replacement for the matched text. Token options are:
*
* 'type' => ['start'|'end'] The starting or ending point of the
* emphasized text. The text itself is left in the source.
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A pair of delimited tokens to be used as a placeholder in
* the source text surrounding the text to be emphasized.
*
*/
function process(&$matches)
{
$start = $this->wiki->addToken(
$this->rule, array('type' => 'start')
);
$end = $this->wiki->addToken(
$this->rule, array('type' => 'end')
);
return $start . $matches[1] . $end;
}
}
?>
/branches/v1.0-menes/api/pear/Text/Wiki.php
New file
0,0 → 1,1258
<?php
 
/**
* The baseline abstract parser class.
*/
 
require_once 'Wiki/Parse.php';
 
/**
* The baseline abstract render class.
*/
 
require_once 'Wiki/Render.php';
 
/**
*
* Parse structured wiki text and render into arbitrary formats such as XHTML.
*
* This is the "master" class for handling the management and convenience
* functions to transform Wiki-formatted text.
*
* $Id: Wiki.php,v 1.2 2005-06-24 10:47:09 jpm Exp $
*
* @author Paul M. Jones <pmjones@ciaweb.net>
*
* @package Text_Wiki
*
* @version 0.23.1
*
* @license LGPL
*
*/
 
class Text_Wiki {
/**
*
* The default list of rules, in order, to apply to the source text.
*
* @access public
*
* @var array
*
*/
var $rules = array(
'Prefilter',
'Delimiter',
'Code',
'Function',
'Html',
'Raw',
'Include',
'Embed',
'Anchor',
'Heading',
'Toc',
'Horiz',
'Break',
'Blockquote',
'List',
'Deflist',
'Table',
'Image',
'Phplookup',
'Center',
'Newline',
'Paragraph',
'Url',
'Freelink',
'Interwiki',
'Wikilink',
'Colortext',
'Strong',
'Bold',
'Emphasis',
'Italic',
'Tt',
'Superscript',
'Revise',
'Tighten'
);
/**
*
* The list of rules to not-apply to the source text.
*
* @access public
*
* @var array
*
*/
var $disable = array(
'Html',
'Include',
'Embed'
);
/**
*
* Custom configuration for rules at the parsing stage.
*
* In this array, the key is the parsing rule name, and the value is
* an array of key-value configuration pairs corresponding to the $conf
* property in the target parsing rule.
*
* For example:
*
* <code>
* $parseConf = array(
* 'Include' => array(
* 'base' => '/path/to/scripts/'
* )
* );
* </code>
*
* Note that most default rules do not need any parsing configuration.
*
* @access public
*
* @var array
*
*/
var $parseConf = array();
/**
*
* Custom configuration for rules at the rendering stage.
*
* Because rendering may be different for each target format, the
* first-level element in this array is always a format name (e.g.,
* 'Xhtml').
*
* Within that first level element, the subsequent elements match the
* $parseConf format. That is, the sub-key is the rendering rule name,
* and the sub-value is an array of key-value configuration pairs
* corresponding to the $conf property in the target rendering rule.
*
* @access public
*
* @var array
*
*/
var $renderConf = array(
'Docbook' => array(),
'Latex' => array(),
'Pdf' => array(),
'Plain' => array(),
'Rtf' => array(),
'Xhtml' => array()
);
/**
*
* Custom configuration for the output format itself.
*
* Even though Text_Wiki will render the tokens from parsed text,
* the format itself may require some configuration. For example,
* RTF needs to know font names and sizes, PDF requires page layout
* information, and DocBook needs a section hierarchy. This array
* matches the $conf property of the the format-level renderer
* (e.g., Text_Wiki_Render_Xhtml).
*
* In this array, the key is the rendering format name, and the value is
* an array of key-value configuration pairs corresponding to the $conf
* property in the rendering format rule.
*
* @access public
*
* @var array
*
*/
var $formatConf = array(
'Docbook' => array(),
'Latex' => array(),
'Pdf' => array(),
'Plain' => array(),
'Rtf' => array(),
'Xhtml' => array()
);
/**
*
* The delimiter for token numbers of parsed elements in source text.
*
* @access public
*
* @var string
*
*/
var $delim = "\xFF";
/**
*
* The tokens generated by rules as the source text is parsed.
*
* As Text_Wiki applies rule classes to the source text, it will
* replace portions of the text with a delimited token number. This
* is the array of those tokens, representing the replaced text and
* any options set by the parser for that replaced text.
*
* The tokens array is sequential; each element is itself a sequential
* array where element 0 is the name of the rule that generated the
* token, and element 1 is an associative array where the key is an
* option name and the value is an option value.
*
* @access private
*
* @var array
*
*/
var $tokens = array();
/**
*
* The source text to which rules will be applied.
*
* This text will be transformed in-place, which means that it will
* change as the rules are applied.
*
* @access private
*
* @var string
*
*/
var $source = '';
/**
*
* Array of rule parsers.
*
* Text_Wiki creates one instance of every rule that is applied to
* the source text; this array holds those instances. The array key
* is the rule name, and the array value is an instance of the rule
* class.
*
* @access private
*
* @var array
*
*/
var $parseObj = array();
/**
*
* Array of rule renderers.
*
* Text_Wiki creates one instance of every rule that is applied to
* the source text; this array holds those instances. The array key
* is the rule name, and the array value is an instance of the rule
* class.
*
* @access private
*
* @var array
*
*/
var $renderObj = array();
/**
*
* Array of format renderers.
*
* @access private
*
* @var array
*
*/
var $formatObj = array();
/**
*
* Array of paths to search, in order, for parsing and rendering rules.
*
* @access private
*
* @var array
*
*/
var $path = array(
'parse' => array(),
'render' => array()
);
/**
*
* The directory separator character.
*
* @access private
*
* @var string
*
*/
var $_dirSep = DIRECTORY_SEPARATOR;
/**
*
* Constructor.
*
* @access public
*
* @param array $rules The set of rules to load for this object.
*
*/
function Text_Wiki($rules = null)
{
if (is_array($rules)) {
$this->rules = $rules;
}
$this->addPath(
'parse',
$this->fixPath(dirname(__FILE__)) . 'Wiki/Parse/'
);
$this->addPath(
'render',
$this->fixPath(dirname(__FILE__)) . 'Wiki/Render/'
);
}
/**
*
* Set parser configuration for a specific rule and key.
*
* @access public
*
* @param string $rule The parse rule to set config for.
*
* @param array|string $arg1 The full config array to use for the
* parse rule, or a conf key in that array.
*
* @param string $arg2 The config value for the key.
*
* @return void
*
*/
function setParseConf($rule, $arg1, $arg2 = null)
{
$rule = ucwords(strtolower($rule));
if (! isset($this->parseConf[$rule])) {
$this->parseConf[$rule] = array();
}
// if first arg is an array, use it as the entire
// conf array for the rule. otherwise, treat arg1
// as a key and arg2 as a value for the rule conf.
if (is_array($arg1)) {
$this->parseConf[$rule] = $arg1;
} else {
$this->parseConf[$rule][$arg1] = $arg2;
}
}
/**
*
* Get parser configuration for a specific rule and key.
*
* @access public
*
* @param string $rule The parse rule to get config for.
*
* @param string $key A key in the conf array; if null,
* returns the entire conf array.
*
* @return mixed The whole conf array if no key is specified,
* or the specific conf key value.
*
*/
function getParseConf($rule, $key = null)
{
$rule = ucwords(strtolower($rule));
// the rule does not exist
if (! isset($this->parseConf[$rule])) {
return null;
}
// no key requested, return the whole array
if (is_null($key)) {
return $this->parseConf[$rule];
}
// does the requested key exist?
if (isset($this->parseConf[$rule][$key])) {
// yes, return that value
return $this->parseConf[$rule][$key];
} else {
// no
return null;
}
}
/**
*
* Set renderer configuration for a specific format, rule, and key.
*
* @access public
*
* @param string $format The render format to set config for.
*
* @param string $rule The render rule to set config for in the format.
*
* @param array|string $arg1 The config array, or the config key
* within the render rule.
*
* @param string $arg2 The config value for the key.
*
* @return void
*
*/
function setRenderConf($format, $rule, $arg1, $arg2 = null)
{
$format = ucwords(strtolower($format));
$rule = ucwords(strtolower($rule));
if (! isset($this->renderConf[$format])) {
$this->renderConf[$format] = array();
}
if (! isset($this->renderConf[$format][$rule])) {
$this->renderConf[$format][$rule] = array();
}
// if first arg is an array, use it as the entire
// conf array for the render rule. otherwise, treat arg1
// as a key and arg2 as a value for the render rule conf.
if (is_array($arg1)) {
$this->renderConf[$format][$rule] = $arg1;
} else {
$this->renderConf[$format][$rule][$arg1] = $arg2;
}
}
/**
*
* Get renderer configuration for a specific format, rule, and key.
*
* @access public
*
* @param string $format The render format to get config for.
*
* @param string $rule The render format rule to get config for.
*
* @param string $key A key in the conf array; if null,
* returns the entire conf array.
*
* @return mixed The whole conf array if no key is specified,
* or the specific conf key value.
*
*/
function getRenderConf($format, $rule, $key = null)
{
$format = ucwords(strtolower($format));
$rule = ucwords(strtolower($rule));
if (! isset($this->renderConf[$format]) ||
! isset($this->renderConf[$format][$rule])) {
return null;
}
// no key requested, return the whole array
if (is_null($key)) {
return $this->renderConf[$format][$rule];
}
// does the requested key exist?
if (isset($this->renderConf[$format][$rule][$key])) {
// yes, return that value
return $this->renderConf[$format][$rule][$key];
} else {
// no
return null;
}
}
/**
*
* Set format configuration for a specific rule and key.
*
* @access public
*
* @param string $format The format to set config for.
*
* @param string $key The config key within the format.
*
* @param string $val The config value for the key.
*
* @return void
*
*/
function setFormatConf($format, $arg1, $arg2 = null)
{
if (! is_array($this->formatConf[$format])) {
$this->formatConf[$format] = array();
}
// if first arg is an array, use it as the entire
// conf array for the format. otherwise, treat arg1
// as a key and arg2 as a value for the format conf.
if (is_array($arg1)) {
$this->formatConf[$format] = $arg1;
} else {
$this->formatConf[$format][$arg1] = $arg2;
}
}
/**
*
* Get configuration for a specific format and key.
*
* @access public
*
* @param string $format The format to get config for.
*
* @param mixed $key A key in the conf array; if null,
* returns the entire conf array.
*
* @return mixed The whole conf array if no key is specified,
* or the specific conf key value.
*
*/
function getFormatConf($format, $key = null)
{
// the format does not exist
if (! isset($this->formatConf[$format])) {
return null;
}
// no key requested, return the whole array
if (is_null($key)) {
return $this->formatConf[$format];
}
// does the requested key exist?
if (isset($this->formatConf[$format][$key])) {
// yes, return that value
return $this->formatConf[$format][$key];
} else {
// no
return null;
}
}
/**
*
* Inserts a rule into to the rule set.
*
* @access public
*
* @param string $name The name of the rule. Should be different from
* all other keys in the rule set.
*
* @param string $tgt The rule after which to insert this new rule. By
* default (null) the rule is inserted at the end; if set to '', inserts
* at the beginning.
*
* @return void
*
*/
function insertRule($name, $tgt = null)
{
$name = ucwords(strtolower($name));
if (! is_null($tgt)) {
$tgt = ucwords(strtolower($tgt));
}
// does the rule name to be inserted already exist?
if (in_array($name, $this->rules)) {
// yes, return
return null;
}
// the target name is not null, and not '', but does not exist
// in the list of rules. this means we're trying to insert after
// a target key, but the target key isn't there.
if (! is_null($tgt) && $tgt != '' &&
! in_array($tgt, $this->rules)) {
return false;
}
// if $tgt is null, insert at the end. We know this is at the
// end (instead of resetting an existing rule) becuase we exited
// at the top of this method if the rule was already in place.
if (is_null($tgt)) {
$this->rules[] = $name;
return true;
}
// save a copy of the current rules, then reset the rule set
// so we can insert in the proper place later.
// where to insert the rule?
if ($tgt == '') {
// insert at the beginning
array_unshift($this->rules, $name);
return true;
}
// insert after the named rule
$tmp = $this->rules;
$this->rules = array();
foreach ($tmp as $val) {
$this->rules[] = $val;
if ($val == $tgt) {
$this->rules[] = $name;
}
}
return true;
}
/**
*
* Delete (remove or unset) a rule from the $rules property.
*
* @access public
*
* @param string $rule The name of the rule to remove.
*
* @return void
*
*/
function deleteRule($name)
{
$name = ucwords(strtolower($name));
$key = array_search($name, $this->rules);
if ($key !== false) {
unset($this->rules[$key]);
}
}
/**
*
* Change from one rule to another in-place.
*
* @access public
*
* @param string $old The name of the rule to change from.
*
* @param string $new The name of the rule to change to.
*
* @return void
*
*/
function changeRule($old, $new)
{
$old = ucwords(strtolower($old));
$new = ucwords(strtolower($new));
$key = array_search($old, $this->rules);
if ($key !== false) {
$this->rules[$old] = $new;
}
}
/**
*
* Enables a rule so that it is applied when parsing.
*
* @access public
*
* @param string $rule The name of the rule to enable.
*
* @return void
*
*/
function enableRule($name)
{
$name = ucwords(strtolower($name));
$key = array_search($name, $this->disable);
if ($key !== false) {
unset($this->disable[$key]);
}
}
/**
*
* Disables a rule so that it is not applied when parsing.
*
* @access public
*
* @param string $rule The name of the rule to disable.
*
* @return void
*
*/
function disableRule($name)
{
$name = ucwords(strtolower($name));
$key = array_search($name, $this->disable);
if ($key === false) {
$this->disable[] = $name;
}
}
/**
*
* Parses and renders the text passed to it, and returns the results.
*
* First, the method parses the source text, applying rules to the
* text as it goes. These rules will modify the source text
* in-place, replacing some text with delimited tokens (and
* populating the $this->tokens array as it goes).
*
* Next, the method renders the in-place tokens into the requested
* output format.
*
* Finally, the method returns the transformed text. Note that the
* source text is transformed in place; once it is transformed, it is
* no longer the same as the original source text.
*
* @access public
*
* @param string $text The source text to which wiki rules should be
* applied, both for parsing and for rendering.
*
* @param string $format The target output format, typically 'xhtml'.
* If a rule does not support a given format, the output from that
* rule is rule-specific.
*
* @return string The transformed wiki text.
*
*/
function transform($text, $format = 'Xhtml')
{
$this->parse($text);
return $this->render($format);
}
/**
*
* Sets the $_source text property, then parses it in place and
* retains tokens in the $_tokens array property.
*
* @access public
*
* @param string $text The source text to which wiki rules should be
* applied, both for parsing and for rendering.
*
* @return void
*
*/
function parse($text)
{
// set the object property for the source text
$this->source = $text;
// reset the tokens.
$this->tokens = array();
// apply the parse() method of each requested rule to the source
// text.
foreach ($this->rules as $name) {
// do not parse the rules listed in $disable
if (! in_array($name, $this->disable)) {
// load the parsing object
$this->loadParseObj($name);
// load may have failed; only parse if
// an object is in the array now
if (is_object($this->parseObj[$name])) {
$this->parseObj[$name]->parse();
}
}
}
}
/**
*
* Renders tokens back into the source text, based on the requested format.
*
* @access public
*
* @param string $format The target output format, typically 'xhtml'.
* If a rule does not support a given format, the output from that
* rule is rule-specific.
*
* @return string The transformed wiki text.
*
*/
function render($format = 'Xhtml')
{
// the rendering method we're going to use from each rule
$format = ucwords(strtolower($format));
// the eventual output text
$output = '';
// when passing through the parsed source text, keep track of when
// we are in a delimited section
$in_delim = false;
// when in a delimited section, capture the token key number
$key = '';
// load the format object
$this->loadFormatObj($format);
// pre-rendering activity
if (is_object($this->formatObj[$format])) {
$output .= $this->formatObj[$format]->pre();
}
// load the render objects
foreach (array_keys($this->parseObj) as $rule) {
$this->loadRenderObj($format, $rule);
}
// pass through the parsed source text character by character
$k = strlen($this->source);
for ($i = 0; $i < $k; $i++) {
// the current character
$char = $this->source{$i};
// are alredy in a delimited section?
if ($in_delim) {
// yes; are we ending the section?
if ($char == $this->delim) {
// yes, get the replacement text for the delimited
// token number and unset the flag.
$key = (int)$key;
$rule = $this->tokens[$key][0];
$opts = $this->tokens[$key][1];
$output .= $this->renderObj[$rule]->token($opts);
$in_delim = false;
} else {
// no, add to the dlimited token key number
$key .= $char;
}
} else {
// not currently in a delimited section.
// are we starting into a delimited section?
if ($char == $this->delim) {
// yes, reset the previous key and
// set the flag.
$key = '';
$in_delim = true;
} else {
// no, add to the output as-is
$output .= $char;
}
}
}
// post-rendering activity
if (is_object($this->formatObj[$format])) {
$output .= $this->formatObj[$format]->post();
}
// return the rendered source text.
return $output;
}
/**
*
* Returns the parsed source text with delimited token placeholders.
*
* @access public
*
* @return string The parsed source text.
*
*/
function getSource()
{
return $this->source;
}
/**
*
* Returns tokens that have been parsed out of the source text.
*
* @access public
*
* @param array $rules If an array of rule names is passed, only return
* tokens matching these rule names. If no array is passed, return all
* tokens.
*
* @return array An array of tokens.
*
*/
function getTokens($rules = null)
{
if (is_null($rules)) {
return $this->tokens;
} else {
settype($rules, 'array');
$result = array();
foreach ($this->tokens as $key => $val) {
if (in_array($val[0], $rules)) {
$result[] = $val;
}
}
return $result;
}
}
/**
*
* Add a token to the Text_Wiki tokens array, and return a delimited
* token number.
*
* @access public
*
* @param array $options An associative array of options for the new
* token array element. The keys and values are specific to the
* rule, and may or may not be common to other rule options. Typical
* options keys are 'text' and 'type' but may include others.
*
* @param boolean $id_only If true, return only the token number, not
* a delimited token string.
*
* @return string|int By default, return the number of the
* newly-created token array element with a delimiter prefix and
* suffix; however, if $id_only is set to true, return only the token
* number (no delimiters).
*
*/
function addToken($rule, $options = array(), $id_only = false)
{
// increment the token ID number. note that if you parse
// multiple times with the same Text_Wiki object, the ID number
// will not reset to zero.
static $id;
if (! isset($id)) {
$id = 0;
} else {
$id ++;
}
// force the options to be an array
settype($options, 'array');
// add the token
$this->tokens[$id] = array(
0 => $rule,
1 => $options
);
// return a value
if ($id_only) {
// return the last token number
return $id;
} else {
// return the token number with delimiters
return $this->delim . $id . $this->delim;
}
}
/**
*
* Set or re-set a token with specific information, overwriting any
* previous rule name and rule options.
*
* @access public
*
* @param int $id The token number to reset.
*
* @param int $rule The rule name to use.
*
* @param array $options An associative array of options for the
* token array element. The keys and values are specific to the
* rule, and may or may not be common to other rule options. Typical
* options keys are 'text' and 'type' but may include others.
*
* @return void
*
*/
function setToken($id, $rule, $options = array())
{
// reset the token
$this->tokens[$id] = array(
0 => $rule,
1 => $options
);
}
/**
*
* Load a rule parser class file.
*
* @access public
*
* @return bool True if loaded, false if not.
*
*/
function loadParseObj($rule)
{
$rule = ucwords(strtolower($rule));
$file = $rule . '.php';
$class = "Text_Wiki_Parse_$rule";
if (! class_exists($class)) {
$loc = $this->findFile('parse', $file);
if ($loc) {
// found the class
include_once $loc;
} else {
// can't find the class
$this->parseObj[$rule] = null;
return false;
}
}
$this->parseObj[$rule] =& new $class($this);
 
}
/**
*
* Load a rule-render class file.
*
* @access public
*
* @return bool True if loaded, false if not.
*
*/
function loadRenderObj($format, $rule)
{
$format = ucwords(strtolower($format));
$rule = ucwords(strtolower($rule));
$file = "$format/$rule.php";
$class = "Text_Wiki_Render_$format" . "_$rule";
if (! class_exists($class)) {
// load the class
$loc = $this->findFile('render', $file);
if ($loc) {
// found the class
include_once $loc;
} else {
// can't find the class
return false;
}
}
$this->renderObj[$rule] =& new $class($this);
}
/**
*
* Load a format-render class file.
*
* @access public
*
* @return bool True if loaded, false if not.
*
*/
function loadFormatObj($format)
{
$format = ucwords(strtolower($format));
$file = $format . '.php';
$class = "Text_Wiki_Render_$format";
if (! class_exists($class)) {
$loc = $this->findFile('render', $file);
if ($loc) {
// found the class
include_once $loc;
} else {
// can't find the class
return false;
}
}
$this->formatObj[$format] =& new $class($this);
}
/**
*
* Add a path to a path array.
*
* @access public
*
* @param string $type The path-type to add (parse or render).
*
* @param string $dir The directory to add to the path-type.
*
* @return void
*
*/
function addPath($type, $dir)
{
$dir = $this->fixPath($dir);
if (! isset($this->path[$type])) {
$this->path[$type] = array($dir);
} else {
array_unshift($this->path[$type], $dir);
}
}
/**
*
* Get the current path array for a path-type.
*
* @access public
*
* @param string $type The path-type to look up (plugin, filter, or
* template). If not set, returns all path types.
*
* @return array The array of paths for the requested type.
*
*/
function getPath($type = null)
{
if (is_null($type)) {
return $this->path;
} elseif (! isset($this->path[$type])) {
return array();
} else {
return $this->path[$type];
}
}
/**
*
* Searches a series of paths for a given file.
*
* @param array $type The type of paths to search (template, plugin,
* or filter).
*
* @param string $file The file name to look for.
*
* @return string|bool The full path and file name for the target file,
* or boolean false if the file is not found in any of the paths.
*
*/
function findFile($type, $file)
{
// get the set of paths
$set = $this->getPath($type);
// start looping through them
foreach ($set as $path) {
$fullname = $path . $file;
if (file_exists($fullname) && is_readable($fullname)) {
return $fullname;
}
}
// could not find the file in the set of paths
return false;
}
/**
*
* Append a trailing '/' to paths, unless the path is empty.
*
* @access private
*
* @param string $path The file path to fix
*
* @return string The fixed file path
*
*/
function fixPath($path)
{
$len = strlen($this->_dirSep);
if (! empty($path) &&
substr($path, -1 * $len, $len) != $this->_dirSep) {
return $path . $this->_dirSep;
} else {
return $path;
}
}
}
 
?>
/branches/v1.0-menes/api/pear/DB/msql.php
New file
0,0 → 1,810
<?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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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 (DB::isManip($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 @msql_free_result($result);
}
 
// }}}
// {{{ 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);
}
 
// }}}
// {{{ 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;
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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/dbase.php
New 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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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;
}
 
// }}}
// {{{ 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);
}
 
// }}}
// {{{ quoteSmart()
 
/**
* Formats input so it can be safely used in a query
*
* @param mixed $in the data to be formatted
*
* @return mixed the formatted data. The format depends on the input's
* PHP type:
* + null = the string <samp>NULL</samp>
* + boolean = <samp>T</samp> if true or
* <samp>F</samp> if false. Use the <kbd>Logical</kbd>
* data type.
* + integer or double = the unquoted number
* + other (including strings and numeric strings) =
* the data with single quotes escaped by preceeding
* single quotes then the whole string is encapsulated
* between single quotes
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
function quoteSmart($in)
{
if (is_int($in) || is_double($in)) {
return $in;
} elseif (is_bool($in)) {
return $in ? 'T' : 'F';
} elseif (is_null($in)) {
return 'NULL';
} else {
return "'" . $this->escapeSimple($in) . "'";
}
}
 
// }}}
// {{{ 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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/mysqli.php
New file
0,0 → 1,1076
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* The PEAR DB driver for PHP's mysqli extension
* for interacting with MySQL 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 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: mysqli.php,v 1.2 2005-09-20 17:01:22 ddelon 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 mysqli extension
* for interacting with MySQL databases
*
* This is for MySQL versions 4.1 and above. Requires PHP 5.
*
* Note that persistent connections no longer exist.
*
* These methods overload the ones declared in DB_common.
*
* @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: @package_version@
* @link http://pear.php.net/package/DB
* @since Class functional since Release 1.6.3
*/
class DB_mysqli extends DB_common
{
// {{{ properties
 
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'mysqli';
 
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'mysqli';
 
/**
* 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' => false,
'prepare' => false,
'ssl' => true,
'transactions' => true,
);
 
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
1004 => DB_ERROR_CANNOT_CREATE,
1005 => DB_ERROR_CANNOT_CREATE,
1006 => DB_ERROR_CANNOT_CREATE,
1007 => DB_ERROR_ALREADY_EXISTS,
1008 => DB_ERROR_CANNOT_DROP,
1022 => DB_ERROR_ALREADY_EXISTS,
1044 => DB_ERROR_ACCESS_VIOLATION,
1046 => DB_ERROR_NODBSELECTED,
1048 => DB_ERROR_CONSTRAINT,
1049 => DB_ERROR_NOSUCHDB,
1050 => DB_ERROR_ALREADY_EXISTS,
1051 => DB_ERROR_NOSUCHTABLE,
1054 => DB_ERROR_NOSUCHFIELD,
1061 => DB_ERROR_ALREADY_EXISTS,
1062 => DB_ERROR_ALREADY_EXISTS,
1064 => DB_ERROR_SYNTAX,
1091 => DB_ERROR_NOT_FOUND,
1100 => DB_ERROR_NOT_LOCKED,
1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
1142 => DB_ERROR_ACCESS_VIOLATION,
1146 => DB_ERROR_NOSUCHTABLE,
1216 => DB_ERROR_CONSTRAINT,
1217 => 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();
 
 
/**
* 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 = '';
 
/**
* Array for converting MYSQLI_*_FLAG constants to text values
* @var array
* @access public
* @since Property available since Release 1.6.5
*/
var $mysqli_flags = array(
MYSQLI_NOT_NULL_FLAG => 'not_null',
MYSQLI_PRI_KEY_FLAG => 'primary_key',
MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
MYSQLI_BLOB_FLAG => 'blob',
MYSQLI_UNSIGNED_FLAG => 'unsigned',
MYSQLI_ZEROFILL_FLAG => 'zerofill',
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
MYSQLI_TIMESTAMP_FLAG => 'timestamp',
MYSQLI_SET_FLAG => 'set',
// MYSQLI_NUM_FLAG => 'numeric', // unnecessary
// MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie
MYSQLI_GROUP_FLAG => 'group_by'
);
 
/**
* Array for converting MYSQLI_TYPE_* constants to text values
* @var array
* @access public
* @since Property available since Release 1.6.5
*/
var $mysqli_types = array(
MYSQLI_TYPE_DECIMAL => 'decimal',
MYSQLI_TYPE_TINY => 'tinyint',
MYSQLI_TYPE_SHORT => 'int',
MYSQLI_TYPE_LONG => 'int',
MYSQLI_TYPE_FLOAT => 'float',
MYSQLI_TYPE_DOUBLE => 'double',
// MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it
MYSQLI_TYPE_TIMESTAMP => 'timestamp',
MYSQLI_TYPE_LONGLONG => 'bigint',
MYSQLI_TYPE_INT24 => 'mediumint',
MYSQLI_TYPE_DATE => 'date',
MYSQLI_TYPE_TIME => 'time',
MYSQLI_TYPE_DATETIME => 'datetime',
MYSQLI_TYPE_YEAR => 'year',
MYSQLI_TYPE_NEWDATE => 'date',
MYSQLI_TYPE_ENUM => 'enum',
MYSQLI_TYPE_SET => 'set',
MYSQLI_TYPE_TINY_BLOB => 'tinyblob',
MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
MYSQLI_TYPE_LONG_BLOB => 'longblob',
MYSQLI_TYPE_BLOB => 'blob',
MYSQLI_TYPE_VAR_STRING => 'varchar',
MYSQLI_TYPE_STRING => 'char',
MYSQLI_TYPE_GEOMETRY => 'geometry',
);
 
 
// }}}
// {{{ constructor
 
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_mysqli()
{
$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 mysqli driver supports the following extra DSN options:
* + When the 'ssl' $option passed to DB::connect() is true:
* + key The path to the key file.
* + cert The path to the certificate file.
* + ca The path to the certificate authority file.
* + capath The path to a directory that contains trusted SSL
* CA certificates in pem format.
* + cipher The list of allowable ciphers for SSL encryption.
*
* Example of how to connect using SSL:
* <code>
* require_once 'DB.php';
*
* $dsn = array(
* 'phptype' => 'mysqli',
* 'username' => 'someuser',
* 'password' => 'apasswd',
* 'hostspec' => 'localhost',
* 'database' => 'thedb',
* 'key' => 'client-key.pem',
* 'cert' => 'client-cert.pem',
* 'ca' => 'cacert.pem',
* 'capath' => '/path/to/ca/dir',
* 'cipher' => 'AES',
* );
*
* $options = array(
* 'ssl' => true,
* );
*
* $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('mysqli')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
 
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
 
$ini = ini_get('track_errors');
ini_set('track_errors', 1);
$php_errormsg = '';
 
if ($this->getOption('ssl') === true) {
$init = mysqli_init();
mysqli_ssl_set(
$init,
empty($dsn['key']) ? null : $dsn['key'],
empty($dsn['cert']) ? null : $dsn['cert'],
empty($dsn['ca']) ? null : $dsn['ca'],
empty($dsn['capath']) ? null : $dsn['capath'],
empty($dsn['cipher']) ? null : $dsn['cipher']
);
if ($this->connection = @mysqli_real_connect(
$init,
$dsn['hostspec'],
$dsn['username'],
$dsn['password'],
$dsn['database'],
$dsn['port'],
$dsn['socket']))
{
$this->connection = $init;
}
} else {
$this->connection = @mysqli_connect(
$dsn['hostspec'],
$dsn['username'],
$dsn['password'],
$dsn['database'],
$dsn['port'],
$dsn['socket']
);
}
 
ini_set('track_errors', $ini);
 
if (!$this->connection) {
if (($err = @mysqli_connect_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 ($dsn['database']) {
$this->_db = $dsn['database'];
}
 
return DB_OK;
}
 
// }}}
// {{{ disconnect()
 
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @mysqli_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 = DB::isManip($query);
$this->last_query = $query;
$query = $this->modifyQuery($query);
if ($this->_db) {
if (!@mysqli_select_db($this->connection, $this->_db)) {
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
}
}
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0');
$result = @mysqli_query($this->connection, 'BEGIN');
if (!$result) {
return $this->mysqliRaiseError();
}
}
$this->transaction_opcount++;
}
$result = @mysqli_query($this->connection, $query);
if (!$result) {
return $this->mysqliRaiseError();
}
if (is_object($result)) {
return $result;
}
return DB_OK;
}
 
// }}}
// {{{ nextResult()
 
/**
* Move the internal mysql result pointer to the next available result.
*
* This method has not been implemented yet.
*
* @param resource $result a valid sql result resource
* @return false
* @access public
*/
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 (!@mysqli_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @mysqli_fetch_array($result, MYSQLI_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @mysqli_fetch_row($result);
}
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)
{
return @mysqli_free_result($result);
}
 
// }}}
// {{{ 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 = @mysqli_num_fields($result);
if (!$cols) {
return $this->mysqliRaiseError();
}
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 = @mysqli_num_rows($result);
if ($rows === null) {
return $this->mysqliRaiseError();
}
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 ($this->_db) {
if (!@mysqli_select_db($this->connection, $this->_db)) {
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysqli_query($this->connection, 'COMMIT');
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqliRaiseError();
}
}
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) {
if (!@mysqli_select_db($this->connection, $this->_db)) {
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysqli_query($this->connection, 'ROLLBACK');
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqliRaiseError();
}
}
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 (DB::isManip($this->last_query)) {
return @mysqli_affected_rows($this->connection);
} else {
return 0;
}
}
 
// }}}
// {{{ 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_mysqli::createSequence(), DB_mysqli::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
do {
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query('UPDATE ' . $seqname
. ' SET id = LAST_INSERT_ID(id + 1)');
$this->popErrorHandling();
if ($result === DB_OK) {
// COMMON CASE
$id = @mysqli_insert_id($this->connection);
if ($id != 0) {
return $id;
}
 
// EMPTY SEQ TABLE
// Sequence table must be empty for some reason,
// so fill it and return 1
// Obtain a user-level lock
$result = $this->getOne('SELECT GET_LOCK('
. "'${seqname}_lock', 10)");
if (DB::isError($result)) {
return $this->raiseError($result);
}
if ($result == 0) {
return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
}
 
// add the default value
$result = $this->query('REPLACE INTO ' . $seqname
. ' (id) VALUES (0)');
if (DB::isError($result)) {
return $this->raiseError($result);
}
 
// Release the lock
$result = $this->getOne('SELECT RELEASE_LOCK('
. "'${seqname}_lock')");
if (DB::isError($result)) {
return $this->raiseError($result);
}
// We know what the result will be, so no need to try again
return 1;
 
} elseif ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE)
{
// ONDEMAND TABLE CREATION
$result = $this->createSequence($seq_name);
 
// Since createSequence initializes the ID to be 1,
// we do not need to retrieve the ID again (or we will get 2)
if (DB::isError($result)) {
return $this->raiseError($result);
} else {
// First ID of a newly created sequence is 1
return 1;
}
 
} elseif (DB::isError($result) &&
$result->getCode() == DB_ERROR_ALREADY_EXISTS)
{
// BACKWARDS COMPAT
// see _BCsequence() comment
$result = $this->_BCsequence($seqname);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$repeat = 1;
}
} while ($repeat);
 
return $this->raiseError($result);
}
 
/**
* 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_mysqli::nextID(), DB_mysqli::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
. ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
. ' PRIMARY KEY(id))');
if (DB::isError($res)) {
return $res;
}
// insert yields value 1, nextId call will generate ID 2
return $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
}
 
// }}}
// {{{ 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_mysql::nextID(), DB_mysql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
 
// }}}
// {{{ _BCsequence()
 
/**
* Backwards compatibility with old sequence emulation implementation
* (clean up the dupes)
*
* @param string $seqname the sequence name to clean up
*
* @return bool true on success. A DB_Error object on failure.
*
* @access private
*/
function _BCsequence($seqname)
{
// Obtain a user-level lock... this will release any previous
// application locks, but unlike LOCK TABLES, it does not abort
// the current transaction and is much less frequently used.
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
if (DB::isError($result)) {
return $result;
}
if ($result == 0) {
// Failed to get the lock, can't do the conversion, bail
// with a DB_ERROR_NOT_LOCKED error
return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
}
 
$highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
if (DB::isError($highest_id)) {
return $highest_id;
}
 
// This should kill all rows except the highest
// We should probably do something if $highest_id isn't
// numeric, but I'm at a loss as how to handle that...
$result = $this->query('DELETE FROM ' . $seqname
. " WHERE id <> $highest_id");
if (DB::isError($result)) {
return $result;
}
 
// If another thread has been waiting for this lock,
// it will go thru the above procedure, but will have no
// real effect
$result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
if (DB::isError($result)) {
return $result;
}
return true;
}
 
// }}}
// {{{ quoteIdentifier()
 
/**
* Quotes a string so it can be safely used as a table or column name
*
* MySQL can't handle the backtick character (<kbd>`</kbd>) in
* table or column names.
*
* @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 . '`';
}
 
// }}}
// {{{ 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.6.0
*/
function escapeSimple($str)
{
return @mysqli_real_escape_string($this->connection, $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())
{
if (DB::isManip($query)) {
return $query . " LIMIT $count";
} else {
return $query . " LIMIT $from, $count";
}
}
 
// }}}
// {{{ mysqliRaiseError()
 
/**
* 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_mysqli::errorNative(), DB_common::errorCode()
*/
function mysqliRaiseError($errno = null)
{
if ($errno === null) {
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
$this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
$this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
} else {
// Doing this in case mode changes during runtime.
$this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
$this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
}
$errno = $this->errorCode(mysqli_errno($this->connection));
}
return $this->raiseError($errno, null, null, null,
@mysqli_errno($this->connection) . ' ** ' .
@mysqli_error($this->connection));
}
 
// }}}
// {{{ errorNative()
 
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code
*/
function errorNative()
{
return @mysqli_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::setOption()
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @mysqli_query($this->connection,
"SELECT * FROM $result LIMIT 0");
$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_a($id, 'mysqli_result')) {
return $this->mysqliRaiseError(DB_ERROR_NEED_MORE_DATA);
}
 
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
 
$count = @mysqli_num_fields($id);
$res = array();
 
if ($mode) {
$res['num_fields'] = $count;
}
 
for ($i = 0; $i < $count; $i++) {
$tmp = @mysqli_fetch_field($id);
 
$flags = '';
foreach ($this->mysqli_flags as $const => $means) {
if ($tmp->flags & $const) {
$flags .= $means . ' ';
}
}
if ($tmp->def) {
$flags .= 'default_' . rawurlencode($tmp->def);
}
$flags = trim($flags);
 
$res[$i] = array(
'table' => $case_func($tmp->table),
'name' => $case_func($tmp->name),
'type' => isset($this->mysqli_types[$tmp->type])
? $this->mysqli_types[$tmp->type]
: 'unknown',
'len' => $tmp->max_length,
'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) {
@mysqli_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 'SHOW TABLES';
case 'users':
return 'SELECT DISTINCT User FROM mysql.user';
case 'databases':
return 'SHOW DATABASES';
default:
return null;
}
}
 
// }}}
 
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/mssql.php
New file
0,0 → 1,914
<?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.2 2005-09-20 17:01:22 ddelon 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.
*
* @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: @package_version@
* @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(
110 => DB_ERROR_VALUE_COUNT_ON_ROW,
155 => DB_ERROR_NOSUCHFIELD,
170 => DB_ERROR_SYNTAX,
207 => DB_ERROR_NOSUCHFIELD,
208 => DB_ERROR_NOSUCHTABLE,
245 => DB_ERROR_INVALID_NUMBER,
515 => DB_ERROR_CONSTRAINT_NOT_NULL,
547 => DB_ERROR_CONSTRAINT,
1913 => DB_ERROR_ALREADY_EXISTS,
2627 => DB_ERROR_CONSTRAINT,
2714 => DB_ERROR_ALREADY_EXISTS,
3701 => DB_ERROR_NOSUCHTABLE,
8134 => DB_ERROR_DIVZERO,
);
 
/**
* 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 = DB::isManip($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_array($result, MSSQL_ASSOC);
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 @mssql_free_result($result);
}
 
// }}}
// {{{ 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 (DB::isManip($this->last_query)) {
$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 @@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++) {
$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),
// We only support flags for table
'flags' => $got_string
? $this->_mssql_field_flags($result,
@mssql_field_name($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) {
@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);
 
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);
 
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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/sqlite.php
New file
0,0 → 1,942
<?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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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']) {
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);
}
} else {
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 = DB::isManip($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;
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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/oci8.php
New file
0,0 → 1,1117
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* The PEAR DB driver for PHP's oci8 extension
* for interacting with Oracle 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 James L. Pine <jlp@valinux.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: oci8.php,v 1.2 2005-09-20 17:01:22 ddelon 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 oci8 extension
* for interacting with Oracle databases
*
* Definitely works with versions 8 and 9 of Oracle.
*
* These methods overload the ones declared in DB_common.
*
* Be aware... OCIError() only appears to return anything when given a
* statement, so functions return the generic DB_ERROR instead of more
* useful errors that have to do with feedback from the database.
*
* @category Database
* @package DB
* @author James L. Pine <jlp@valinux.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: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_oci8 extends DB_common
{
// {{{ properties
 
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'oci8';
 
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'oci8';
 
/**
* 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' => '5.0.0',
'numrows' => 'subquery',
'pconnect' => true,
'prepare' => true,
'ssl' => false,
'transactions' => true,
);
 
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
1 => DB_ERROR_CONSTRAINT,
900 => DB_ERROR_SYNTAX,
904 => DB_ERROR_NOSUCHFIELD,
913 => DB_ERROR_VALUE_COUNT_ON_ROW,
921 => DB_ERROR_SYNTAX,
923 => DB_ERROR_SYNTAX,
942 => DB_ERROR_NOSUCHTABLE,
955 => DB_ERROR_ALREADY_EXISTS,
1400 => DB_ERROR_CONSTRAINT_NOT_NULL,
1401 => DB_ERROR_INVALID,
1407 => DB_ERROR_CONSTRAINT_NOT_NULL,
1418 => DB_ERROR_NOT_FOUND,
1476 => DB_ERROR_DIVZERO,
1722 => DB_ERROR_INVALID_NUMBER,
2289 => DB_ERROR_NOSUCHTABLE,
2291 => DB_ERROR_CONSTRAINT,
2292 => DB_ERROR_CONSTRAINT,
2449 => 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();
 
 
/**
* Should data manipulation queries be committed automatically?
* @var bool
* @access private
*/
var $autocommit = true;
 
/**
* Stores the $data passed to execute() in the oci8 driver
*
* Gets reset to array() when simpleQuery() is run.
*
* Needed in case user wants to call numRows() after prepare/execute
* was used.
*
* @var array
* @access private
*/
var $_data = array();
 
/**
* The result or statement handle from the most recently executed query
* @var resource
*/
var $last_stmt;
 
/**
* Is the given prepared statement a data manipulation query?
* @var array
* @access private
*/
var $manip_query = array();
 
 
// }}}
// {{{ constructor
 
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_oci8()
{
$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.
*
* If PHP is at version 5.0.0 or greater:
* + Generally, oci_connect() or oci_pconnect() are used.
* + But if the new_link DSN option is set to true, oci_new_connect()
* is used.
*
* When using PHP version 4.x, OCILogon() or OCIPLogon() are used.
*
* PEAR DB's oci8 driver supports the following extra DSN options:
* + charset The character set to be used on the connection.
* Only used if PHP is at version 5.0.0 or greater
* and the Oracle server is at 9.2 or greater.
* Available since PEAR DB 1.7.0.
* + new_link If set to true, causes subsequent calls to
* connect() to return a new connection link
* instead of the existing one. WARNING: this is
* not portable to other DBMS's.
* 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('oci8')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
 
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
 
if (function_exists('oci_connect')) {
if (isset($dsn['new_link'])
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true))
{
$connect_function = 'oci_new_connect';
} else {
$connect_function = $persistent ? 'oci_pconnect'
: 'oci_connect';
}
 
// Backwards compatibility with DB < 1.7.0
if (empty($dsn['database']) && !empty($dsn['hostspec'])) {
$db = $dsn['hostspec'];
} else {
$db = $dsn['database'];
}
 
$char = empty($dsn['charset']) ? null : $dsn['charset'];
$this->connection = @$connect_function($dsn['username'],
$dsn['password'],
$db,
$char);
$error = OCIError();
if (!empty($error) && $error['code'] == 12541) {
// Couldn't find TNS listener. Try direct connection.
$this->connection = @$connect_function($dsn['username'],
$dsn['password'],
null,
$char);
}
} else {
$connect_function = $persistent ? 'OCIPLogon' : 'OCILogon';
if ($dsn['hostspec']) {
$this->connection = @$connect_function($dsn['username'],
$dsn['password'],
$dsn['hostspec']);
} elseif ($dsn['username'] || $dsn['password']) {
$this->connection = @$connect_function($dsn['username'],
$dsn['password']);
}
}
 
if (!$this->connection) {
$error = OCIError();
$error = (is_array($error)) ? $error['message'] : null;
return $this->raiseError(DB_ERROR_CONNECT_FAILED,
null, null, null,
$error);
}
return DB_OK;
}
 
// }}}
// {{{ disconnect()
 
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
if (function_exists('oci_close')) {
$ret = @oci_close($this->connection);
} else {
$ret = @OCILogOff($this->connection);
}
$this->connection = null;
return $ret;
}
 
// }}}
// {{{ simpleQuery()
 
/**
* Sends a query to the database server
*
* To determine how many rows of a result set get buffered using
* ocisetprefetch(), see the "result_buffering" option in setOptions().
* This option was added in Release 1.7.0.
*
* @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->_data = array();
$this->last_parameters = array();
$this->last_query = $query;
$query = $this->modifyQuery($query);
$result = @OCIParse($this->connection, $query);
if (!$result) {
return $this->oci8RaiseError();
}
if ($this->autocommit) {
$success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
} else {
$success = @OCIExecute($result,OCI_DEFAULT);
}
if (!$success) {
return $this->oci8RaiseError($result);
}
$this->last_stmt = $result;
if (DB::isManip($query)) {
return DB_OK;
} else {
@ocisetprefetch($result, $this->options['result_buffering']);
return $result;
}
}
 
// }}}
// {{{ nextResult()
 
/**
* Move the internal oracle result pointer to the next available result
*
* @param a valid oci8 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) {
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE &&
$moredata)
{
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
}
if (!$moredata) {
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 @OCIFreeStatement($result);
}
 
/**
* Frees the internal resources associated with a prepared query
*
* @param resource $stmt the prepared statement's resource
* @param bool $free_resource should the PHP resource be freed too?
* Use false if you need to get data
* from the result set later.
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_oci8::prepare()
*/
function freePrepared($stmt, $free_resource = true)
{
if (!is_resource($stmt)) {
return false;
}
if ($free_resource) {
@ocifreestatement($stmt);
}
if (isset($this->prepare_types[(int)$stmt])) {
unset($this->prepare_types[(int)$stmt]);
unset($this->manip_query[(int)$stmt]);
} else {
return false;
}
return true;
}
 
// }}}
// {{{ numRows()
 
/**
* Gets the number of rows in a result set
*
* Only works if the DB_PORTABILITY_NUMROWS portability option
* is turned on.
*
* 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(), DB_common::setOption()
*/
function numRows($result)
{
// emulate numRows for Oracle. yuck.
if ($this->options['portability'] & DB_PORTABILITY_NUMROWS &&
$result === $this->last_stmt)
{
$countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')';
$save_query = $this->last_query;
$save_stmt = $this->last_stmt;
 
if (count($this->_data)) {
$smt = $this->prepare('SELECT COUNT(*) FROM ('.$this->last_query.')');
$count = $this->execute($smt, $this->_data);
} else {
$count =& $this->query($countquery);
}
 
if (DB::isError($count) ||
DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED)))
{
$this->last_query = $save_query;
$this->last_stmt = $save_stmt;
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
return $row[0];
}
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ 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 = @OCINumCols($result);
if (!$cols) {
return $this->oci8RaiseError($result);
}
return $cols;
}
 
// }}}
// {{{ prepare()
 
/**
* Prepares a query for multiple execution with execute().
*
* With oci8, this is emulated.
*
* prepare() requires a generic query as string like <code>
* INSERT INTO numbers VALUES (?, ?, ?)
* </code>. The <kbd>?</kbd> characters are placeholders.
*
* Three types of placeholders can be used:
* + <kbd>?</kbd> a quoted scalar value, i.e. strings, integers
* + <kbd>!</kbd> value is inserted 'as is'
* + <kbd>&</kbd> requires a file name. The file's contents get
* inserted into the query (i.e. saving binary
* data in a db)
*
* Use backslashes to escape placeholder characters if you don't want
* them to be interpreted as placeholders. Example: <code>
* "UPDATE foo SET col=? WHERE col='over \& under'"
* </code>
*
* @param string $query the query to be prepared
*
* @return mixed DB statement resource on success. DB_Error on failure.
*
* @see DB_oci8::execute()
*/
function prepare($query)
{
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1,
PREG_SPLIT_DELIM_CAPTURE);
$binds = count($tokens) - 1;
$token = 0;
$types = array();
$newquery = '';
 
foreach ($tokens as $key => $val) {
switch ($val) {
case '?':
$types[$token++] = DB_PARAM_SCALAR;
unset($tokens[$key]);
break;
case '&':
$types[$token++] = DB_PARAM_OPAQUE;
unset($tokens[$key]);
break;
case '!':
$types[$token++] = DB_PARAM_MISC;
unset($tokens[$key]);
break;
default:
$tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
if ($key != $binds) {
$newquery .= $tokens[$key] . ':bind' . $token;
} else {
$newquery .= $tokens[$key];
}
}
}
 
$this->last_query = $query;
$newquery = $this->modifyQuery($newquery);
if (!$stmt = @OCIParse($this->connection, $newquery)) {
return $this->oci8RaiseError();
}
$this->prepare_types[(int)$stmt] = $types;
$this->manip_query[(int)$stmt] = DB::isManip($query);
return $stmt;
}
 
// }}}
// {{{ execute()
 
/**
* Executes a DB statement prepared with prepare().
*
* To determine how many rows of a result set get buffered using
* ocisetprefetch(), see the "result_buffering" option in setOptions().
* This option was added in Release 1.7.0.
*
* @param resource $stmt a DB statement resource returned from prepare()
* @param mixed $data 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 for non-array items or the
* quantity of elements in the array.
*
* @return mixed returns an oic8 result resource for successful SELECT
* queries, DB_OK for other successful queries.
* A DB error object is returned on failure.
*
* @see DB_oci8::prepare()
*/
function &execute($stmt, $data = array())
{
$data = (array)$data;
$this->last_parameters = $data;
$this->_data = $data;
 
$types =& $this->prepare_types[(int)$stmt];
if (count($types) != count($data)) {
$tmp =& $this->raiseError(DB_ERROR_MISMATCH);
return $tmp;
}
 
$i = 0;
foreach ($data as $key => $value) {
if ($types[$i] == DB_PARAM_MISC) {
/*
* Oracle doesn't seem to have the ability to pass a
* parameter along unchanged, so strip off quotes from start
* and end, plus turn two single quotes to one single quote,
* in order to avoid the quotes getting escaped by
* Oracle and ending up in the database.
*/
$data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
$data[$key] = str_replace("''", "'", $data[$key]);
} elseif ($types[$i] == DB_PARAM_OPAQUE) {
$fp = @fopen($data[$key], 'rb');
if (!$fp) {
$tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
return $tmp;
}
$data[$key] = fread($fp, filesize($data[$key]));
fclose($fp);
}
if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) {
$tmp = $this->oci8RaiseError($stmt);
return $tmp;
}
$i++;
}
if ($this->autocommit) {
$success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS);
} else {
$success = @OCIExecute($stmt, OCI_DEFAULT);
}
if (!$success) {
$tmp = $this->oci8RaiseError($stmt);
return $tmp;
}
$this->last_stmt = $stmt;
if ($this->manip_query[(int)$stmt]) {
$tmp = DB_OK;
} else {
@ocisetprefetch($stmt, $this->options['result_buffering']);
$tmp =& new DB_result($this, $stmt);
}
return $tmp;
}
 
// }}}
// {{{ 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)
{
$this->autocommit = (bool)$onoff;;
return DB_OK;
}
 
// }}}
// {{{ commit()
 
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
$result = @OCICommit($this->connection);
if (!$result) {
return $this->oci8RaiseError();
}
return DB_OK;
}
 
// }}}
// {{{ rollback()
 
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
$result = @OCIRollback($this->connection);
if (!$result) {
return $this->oci8RaiseError();
}
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_stmt === false) {
return $this->oci8RaiseError();
}
$result = @OCIRowCount($this->last_stmt);
if ($result === false) {
return $this->oci8RaiseError($this->last_stmt);
}
return $result;
}
 
// }}}
// {{{ modifyQuery()
 
/**
* Changes a query string for various DBMS specific reasons
*
* "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle.
*
* @param string $query the query string to modify
*
* @return string the modified query string
*
* @access protected
*/
function modifyQuery($query)
{
if (preg_match('/^\s*SELECT/i', $query) &&
!preg_match('/\sFROM\s/i', $query)) {
$query .= ' FROM dual';
}
return $query;
}
 
// }}}
// {{{ 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())
{
// Let Oracle return the name of the columns instead of
// coding a "home" SQL parser
 
if (count($params)) {
$result = $this->prepare("SELECT * FROM ($query) "
. 'WHERE NULL = NULL');
$tmp =& $this->execute($result, $params);
} else {
$q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
 
if (!$result = @OCIParse($this->connection, $q_fields)) {
$this->last_query = $q_fields;
return $this->oci8RaiseError();
}
if (!@OCIExecute($result, OCI_DEFAULT)) {
$this->last_query = $q_fields;
return $this->oci8RaiseError($result);
}
}
 
$ncols = OCINumCols($result);
$cols = array();
for ( $i = 1; $i <= $ncols; $i++ ) {
$cols[] = '"' . OCIColumnName($result, $i) . '"';
}
$fields = implode(', ', $cols);
// XXX Test that (tip by John Lim)
//if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
// // Introduce the FIRST_ROWS Oracle query optimizer
// $query = substr($query, strlen($match[0]), strlen($query));
// $query = "SELECT /* +FIRST_ROWS */ " . $query;
//}
 
// Construct the query
// more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
// Perhaps this could be optimized with the use of Unions
$query = "SELECT $fields FROM".
" (SELECT rownum as linenum, $fields FROM".
" ($query)".
' WHERE rownum <= '. ($from + $count) .
') WHERE linenum >= ' . ++$from;
return $query;
}
 
// }}}
// {{{ 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_oci8::createSequence(), DB_oci8::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
$repeat = 0;
do {
$this->expectError(DB_ERROR_NOSUCHTABLE);
$result =& $this->query("SELECT ${seqname}.nextval FROM dual");
$this->popExpect();
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
}
} else {
$repeat = 0;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
return $arr[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_oci8::nextID(), DB_oci8::dropSequence()
*/
function createSequence($seq_name)
{
return $this->query('CREATE SEQUENCE '
. $this->getSequenceName($seq_name));
}
 
// }}}
// {{{ 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_oci8::nextID(), DB_oci8::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP SEQUENCE '
. $this->getSequenceName($seq_name));
}
 
// }}}
// {{{ oci8RaiseError()
 
/**
* 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_oci8::errorNative(), DB_oci8::errorCode()
*/
function oci8RaiseError($errno = null)
{
if ($errno === null) {
$error = @OCIError($this->connection);
return $this->raiseError($this->errorCode($error['code']),
null, null, null, $error['message']);
} elseif (is_resource($errno)) {
$error = @OCIError($errno);
return $this->raiseError($this->errorCode($error['code']),
null, null, null, $error['message']);
}
return $this->raiseError($this->errorCode($errno));
}
 
// }}}
// {{{ errorNative()
 
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code. FALSE if the code could not be
* determined
*/
function errorNative()
{
if (is_resource($this->last_stmt)) {
$error = @OCIError($this->last_stmt);
} else {
$error = @OCIError($this->connection);
}
if (is_array($error)) {
return $error['code'];
}
return false;
}
 
// }}}
// {{{ tableInfo()
 
/**
* Returns information about a table or a result set
*
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
* is a table name.
*
* NOTE: flags won't contain index information.
*
* @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 ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
 
$res = array();
 
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$result = strtoupper($result);
$q_fields = 'SELECT column_name, data_type, data_length, '
. 'nullable '
. 'FROM user_tab_columns '
. "WHERE table_name='$result' ORDER BY column_id";
 
$this->last_query = $q_fields;
 
if (!$stmt = @OCIParse($this->connection, $q_fields)) {
return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA);
}
if (!@OCIExecute($stmt, OCI_DEFAULT)) {
return $this->oci8RaiseError($stmt);
}
 
$i = 0;
while (@OCIFetch($stmt)) {
$res[$i] = array(
'table' => $case_func($result),
'name' => $case_func(@OCIResult($stmt, 1)),
'type' => @OCIResult($stmt, 2),
'len' => @OCIResult($stmt, 3),
'flags' => (@OCIResult($stmt, 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++;
}
 
if ($mode) {
$res['num_fields'] = $i;
}
@OCIFreeStatement($stmt);
 
} else {
if (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$result = $result->result;
}
 
$res = array();
 
if ($result === $this->last_stmt) {
$count = @OCINumCols($result);
if ($mode) {
$res['num_fields'] = $count;
}
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => '',
'name' => $case_func(@OCIColumnName($result, $i+1)),
'type' => @OCIColumnType($result, $i+1),
'len' => @OCIColumnSize($result, $i+1),
'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;
}
}
} else {
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
}
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 user_tables';
case 'synonyms':
return 'SELECT synonym_name FROM user_synonyms';
default:
return null;
}
}
 
// }}}
 
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/ibase.php
New file
0,0 → 1,1071
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* The PEAR DB driver for PHP's interbase extension
* for interacting with Interbase and Firebird databases
*
* While this class works with PHP 4, PHP's InterBase extension is
* unstable in PHP 4. Use PHP 5.
*
* 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: ibase.php,v 1.2 2005-09-20 17:01:22 ddelon 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 interbase extension
* for interacting with Interbase and Firebird databases
*
* These methods overload the ones declared in DB_common.
*
* While this class works with PHP 4, PHP's InterBase extension is
* unstable in PHP 4. Use PHP 5.
*
* NOTICE: limitQuery() only works for Firebird.
*
* @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: @package_version@
* @link http://pear.php.net/package/DB
* @since Class became stable in Release 1.7.0
*/
class DB_ibase extends DB_common
{
// {{{ properties
 
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'ibase';
 
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'ibase';
 
/**
* 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: only firebird supports limit.
*
* @var array
*/
var $features = array(
'limit' => false,
'new_link' => false,
'numrows' => 'emulate',
'pconnect' => true,
'prepare' => true,
'ssl' => false,
'transactions' => true,
);
 
/**
* A mapping of native error codes to DB error codes
* @var array
*/
var $errorcode_map = array(
-104 => DB_ERROR_SYNTAX,
-150 => DB_ERROR_ACCESS_VIOLATION,
-151 => DB_ERROR_ACCESS_VIOLATION,
-155 => DB_ERROR_NOSUCHTABLE,
-157 => DB_ERROR_NOSUCHFIELD,
-158 => DB_ERROR_VALUE_COUNT_ON_ROW,
-170 => DB_ERROR_MISMATCH,
-171 => DB_ERROR_MISMATCH,
-172 => DB_ERROR_INVALID,
// -204 => // Covers too many errors, need to use regex on msg
-205 => DB_ERROR_NOSUCHFIELD,
-206 => DB_ERROR_NOSUCHFIELD,
-208 => DB_ERROR_INVALID,
-219 => DB_ERROR_NOSUCHTABLE,
-297 => DB_ERROR_CONSTRAINT,
-303 => DB_ERROR_INVALID,
-413 => DB_ERROR_INVALID_NUMBER,
-530 => DB_ERROR_CONSTRAINT,
-551 => DB_ERROR_ACCESS_VIOLATION,
-552 => DB_ERROR_ACCESS_VIOLATION,
// -607 => // Covers too many errors, need to use regex on msg
-625 => DB_ERROR_CONSTRAINT_NOT_NULL,
-803 => DB_ERROR_CONSTRAINT,
-804 => DB_ERROR_VALUE_COUNT_ON_ROW,
-904 => DB_ERROR_CONNECT_FAILED,
-922 => DB_ERROR_NOSUCHDB,
-923 => DB_ERROR_CONNECT_FAILED,
-924 => DB_ERROR_CONNECT_FAILED
);
 
/**
* 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;
 
/**
* Should data manipulation queries be committed automatically?
* @var bool
* @access private
*/
var $autocommit = true;
 
/**
* The prepared statement handle from the most recently executed statement
*
* {@internal Mainly here because the InterBase/Firebird API is only
* able to retrieve data from result sets if the statemnt handle is
* still in scope.}}
*
* @var resource
*/
var $last_stmt;
 
/**
* Is the given prepared statement a data manipulation query?
* @var array
* @access private
*/
var $manip_query = array();
 
 
// }}}
// {{{ constructor
 
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_ibase()
{
$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 ibase driver supports the following extra DSN options:
* + buffers The number of database buffers to allocate for the
* server-side cache.
* + charset The default character set for a database.
* + dialect The default SQL dialect for any statement
* executed within a connection. Defaults to the
* highest one supported by client libraries.
* Functional only with InterBase 6 and up.
* + role Functional only with InterBase 5 and up.
*
* @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('interbase')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
 
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
if ($this->dbsyntax == 'firebird') {
$this->features['limit'] = 'alter';
}
 
$params = array(
$dsn['hostspec']
? ($dsn['hostspec'] . ':' . $dsn['database'])
: $dsn['database'],
$dsn['username'] ? $dsn['username'] : null,
$dsn['password'] ? $dsn['password'] : null,
isset($dsn['charset']) ? $dsn['charset'] : null,
isset($dsn['buffers']) ? $dsn['buffers'] : null,
isset($dsn['dialect']) ? $dsn['dialect'] : null,
isset($dsn['role']) ? $dsn['role'] : null,
);
 
$connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect';
 
$this->connection = @call_user_func_array($connect_function, $params);
if (!$this->connection) {
return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED);
}
return DB_OK;
}
 
// }}}
// {{{ disconnect()
 
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @ibase_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 = DB::isManip($query);
$this->last_query = $query;
$query = $this->modifyQuery($query);
$result = @ibase_query($this->connection, $query);
 
if (!$result) {
return $this->ibaseRaiseError();
}
if ($this->autocommit && $ismanip) {
@ibase_commit($this->connection);
}
if ($ismanip) {
$this->affected = $result;
return DB_OK;
} else {
$this->affected = 0;
return $result;
}
}
 
// }}}
// {{{ modifyLimitQuery()
 
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* Only works with Firebird.
*
* @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 ($this->dsn['dbsyntax'] == 'firebird') {
$query = preg_replace('/^([\s(])*SELECT/i',
"SELECT FIRST $count SKIP $from", $query);
}
return $query;
}
 
// }}}
// {{{ nextResult()
 
/**
* Move the internal ibase 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.
*
* @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) {
return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
if (function_exists('ibase_fetch_assoc')) {
$arr = @ibase_fetch_assoc($result);
} else {
$arr = get_object_vars(ibase_fetch_object($result));
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @ibase_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 @ibase_free_result($result);
}
 
// }}}
// {{{ freeQuery()
 
function freeQuery($query)
{
@ibase_free_query($query);
return true;
}
 
// }}}
// {{{ 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 (is_integer($this->affected)) {
return $this->affected;
}
return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ 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 = @ibase_num_fields($result);
if (!$cols) {
return $this->ibaseRaiseError();
}
return $cols;
}
 
// }}}
// {{{ prepare()
 
/**
* Prepares a query for multiple execution with execute().
*
* prepare() requires a generic query as string like <code>
* INSERT INTO numbers VALUES (?, ?, ?)
* </code>. The <kbd>?</kbd> characters are placeholders.
*
* Three types of placeholders can be used:
* + <kbd>?</kbd> a quoted scalar value, i.e. strings, integers
* + <kbd>!</kbd> value is inserted 'as is'
* + <kbd>&</kbd> requires a file name. The file's contents get
* inserted into the query (i.e. saving binary
* data in a db)
*
* Use backslashes to escape placeholder characters if you don't want
* them to be interpreted as placeholders. Example: <code>
* "UPDATE foo SET col=? WHERE col='over \& under'"
* </code>
*
* @param string $query query to be prepared
* @return mixed DB statement resource on success. DB_Error on failure.
*/
function prepare($query)
{
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1,
PREG_SPLIT_DELIM_CAPTURE);
$token = 0;
$types = array();
$newquery = '';
 
foreach ($tokens as $key => $val) {
switch ($val) {
case '?':
$types[$token++] = DB_PARAM_SCALAR;
break;
case '&':
$types[$token++] = DB_PARAM_OPAQUE;
break;
case '!':
$types[$token++] = DB_PARAM_MISC;
break;
default:
$tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
$newquery .= $tokens[$key] . '?';
}
}
 
$newquery = substr($newquery, 0, -1);
$this->last_query = $query;
$newquery = $this->modifyQuery($newquery);
$stmt = @ibase_prepare($this->connection, $newquery);
$this->prepare_types[(int)$stmt] = $types;
$this->manip_query[(int)$stmt] = DB::isManip($query);
return $stmt;
}
 
// }}}
// {{{ execute()
 
/**
* Executes a DB statement prepared with prepare().
*
* @param resource $stmt a DB statement resource returned from prepare()
* @param mixed $data 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 for non-array items or the
* quantity of elements in the array.
* @return object a new DB_Result or a DB_Error when fail
* @see DB_ibase::prepare()
* @access public
*/
function &execute($stmt, $data = array())
{
$data = (array)$data;
$this->last_parameters = $data;
 
$types =& $this->prepare_types[(int)$stmt];
if (count($types) != count($data)) {
$tmp =& $this->raiseError(DB_ERROR_MISMATCH);
return $tmp;
}
 
$i = 0;
foreach ($data as $key => $value) {
if ($types[$i] == DB_PARAM_MISC) {
/*
* ibase doesn't seem to have the ability to pass a
* parameter along unchanged, so strip off quotes from start
* and end, plus turn two single quotes to one single quote,
* in order to avoid the quotes getting escaped by
* ibase and ending up in the database.
*/
$data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
$data[$key] = str_replace("''", "'", $data[$key]);
} elseif ($types[$i] == DB_PARAM_OPAQUE) {
$fp = @fopen($data[$key], 'rb');
if (!$fp) {
$tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
return $tmp;
}
$data[$key] = fread($fp, filesize($data[$key]));
fclose($fp);
}
$i++;
}
 
array_unshift($data, $stmt);
 
$res = call_user_func_array('ibase_execute', $data);
if (!$res) {
$tmp =& $this->ibaseRaiseError();
return $tmp;
}
/* XXX need this?
if ($this->autocommit && $this->manip_query[(int)$stmt]) {
@ibase_commit($this->connection);
}*/
$this->last_stmt = $stmt;
if ($this->manip_query[(int)$stmt]) {
$tmp = DB_OK;
} else {
$tmp =& new DB_result($this, $res);
}
return $tmp;
}
 
/**
* Frees the internal resources associated with a prepared query
*
* @param resource $stmt the prepared statement's PHP resource
* @param bool $free_resource should the PHP resource be freed too?
* Use false if you need to get data
* from the result set later.
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_ibase::prepare()
*/
function freePrepared($stmt, $free_resource = true)
{
if (!is_resource($stmt)) {
return false;
}
if ($free_resource) {
@ibase_free_query($stmt);
}
unset($this->prepare_tokens[(int)$stmt]);
unset($this->prepare_types[(int)$stmt]);
unset($this->manip_query[(int)$stmt]);
return true;
}
 
// }}}
// {{{ 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)
{
$this->autocommit = $onoff ? 1 : 0;
return DB_OK;
}
 
// }}}
// {{{ commit()
 
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
return @ibase_commit($this->connection);
}
 
// }}}
// {{{ rollback()
 
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
return @ibase_rollback($this->connection);
}
 
// }}}
// {{{ transactionInit()
 
function transactionInit($trans_args = 0)
{
return $trans_args
? @ibase_trans($trans_args, $this->connection)
: @ibase_trans();
}
 
// }}}
// {{{ 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_ibase::createSequence(), DB_ibase::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$sqn = strtoupper($this->getSequenceName($seq_name));
$repeat = 0;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result =& $this->query("SELECT GEN_ID(${sqn}, 1) "
. 'FROM RDB$GENERATORS '
. "WHERE RDB\$GENERATOR_NAME='${sqn}'");
$this->popErrorHandling();
if ($ondemand && DB::isError($result)) {
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $result;
}
} else {
$repeat = 0;
}
} 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
*
* @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_ibase::nextID(), DB_ibase::dropSequence()
*/
function createSequence($seq_name)
{
$sqn = strtoupper($this->getSequenceName($seq_name));
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("CREATE GENERATOR ${sqn}");
$this->popErrorHandling();
 
return $result;
}
 
// }}}
// {{{ 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_ibase::nextID(), DB_ibase::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DELETE FROM RDB$GENERATORS '
. "WHERE RDB\$GENERATOR_NAME='"
. strtoupper($this->getSequenceName($seq_name))
. "'");
}
 
// }}}
// {{{ _ibaseFieldFlags()
 
/**
* Get the column's flags
*
* Supports "primary_key", "unique_key", "not_null", "default",
* "computed" and "blob".
*
* @param string $field_name the name of the field
* @param string $table_name the name of the table
*
* @return string the flags
*
* @access private
*/
function _ibaseFieldFlags($field_name, $table_name)
{
$sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
.' FROM RDB$INDEX_SEGMENTS I'
.' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
.' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\''
.' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'';
 
$result = @ibase_query($this->connection, $sql);
if (!$result) {
return $this->ibaseRaiseError();
}
 
$flags = '';
if ($obj = @ibase_fetch_object($result)) {
@ibase_free_result($result);
if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') {
$flags .= 'primary_key ';
}
if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') {
$flags .= 'unique_key ';
}
}
 
$sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
.' R.RDB$DEFAULT_SOURCE AS DSOURCE,'
.' F.RDB$FIELD_TYPE AS FTYPE,'
.' F.RDB$COMPUTED_SOURCE AS CSOURCE'
.' FROM RDB$RELATION_FIELDS R '
.' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
.' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''
.' AND R.RDB$FIELD_NAME=\'' . $field_name . '\'';
 
$result = @ibase_query($this->connection, $sql);
if (!$result) {
return $this->ibaseRaiseError();
}
if ($obj = @ibase_fetch_object($result)) {
@ibase_free_result($result);
if (isset($obj->NFLAG)) {
$flags .= 'not_null ';
}
if (isset($obj->DSOURCE)) {
$flags .= 'default ';
}
if (isset($obj->CSOURCE)) {
$flags .= 'computed ';
}
if (isset($obj->FTYPE) && $obj->FTYPE == 261) {
$flags .= 'blob ';
}
}
 
return trim($flags);
}
 
// }}}
// {{{ ibaseRaiseError()
 
/**
* 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_ibase::errorNative(), DB_ibase::errorCode()
*/
function &ibaseRaiseError($errno = null)
{
if ($errno === null) {
$errno = $this->errorCode($this->errorNative());
}
$tmp =& $this->raiseError($errno, null, null, null, @ibase_errmsg());
return $tmp;
}
 
// }}}
// {{{ errorNative()
 
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code. NULL if there is no error code.
*
* @since Method available since Release 1.7.0
*/
function errorNative()
{
if (function_exists('ibase_errcode')) {
return @ibase_errcode();
}
if (preg_match('/^Dynamic SQL Error SQL error code = ([0-9-]+)/i',
@ibase_errmsg(), $m)) {
return (int)$m[1];
}
return null;
}
 
// }}}
// {{{ errorCode()
 
/**
* Maps native error codes to DB's portable ones
*
* @param int $nativecode the error code returned by the DBMS
*
* @return int the portable DB error code. Return DB_ERROR if the
* current driver doesn't have a mapping for the
* $nativecode submitted.
*
* @since Method available since Release 1.7.0
*/
function errorCode($nativecode = null)
{
if (isset($this->errorcode_map[$nativecode])) {
return $this->errorcode_map[$nativecode];
}
 
static $error_regexps;
if (!isset($error_regexps)) {
$error_regexps = array(
'/generator .* is not defined/'
=> DB_ERROR_SYNTAX, // for compat. w ibase_errcode()
'/table.*(not exist|not found|unknown)/i'
=> DB_ERROR_NOSUCHTABLE,
'/table .* already exists/i'
=> DB_ERROR_ALREADY_EXISTS,
'/unsuccessful metadata update .* failed attempt to store duplicate value/i'
=> DB_ERROR_ALREADY_EXISTS,
'/unsuccessful metadata update .* not found/i'
=> DB_ERROR_NOT_FOUND,
'/validation error for column .* value "\*\*\* null/i'
=> DB_ERROR_CONSTRAINT_NOT_NULL,
'/violation of [\w ]+ constraint/i'
=> DB_ERROR_CONSTRAINT,
'/conversion error from string/i'
=> DB_ERROR_INVALID_NUMBER,
'/no permission for/i'
=> DB_ERROR_ACCESS_VIOLATION,
'/arithmetic exception, numeric overflow, or string truncation/i'
=> DB_ERROR_INVALID,
);
}
 
$errormsg = @ibase_errmsg();
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()
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @ibase_query($this->connection,
"SELECT * FROM $result WHERE 1=0");
$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->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA);
}
 
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
 
$count = @ibase_num_fields($id);
$res = array();
 
if ($mode) {
$res['num_fields'] = $count;
}
 
for ($i = 0; $i < $count; $i++) {
$info = @ibase_field_info($id, $i);
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
'name' => $case_func($info['name']),
'type' => $info['type'],
'len' => $info['length'],
'flags' => ($got_string)
? $this->_ibaseFieldFlags($info['name'], $result)
: '',
);
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) {
@ibase_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 DISTINCT R.RDB$RELATION_NAME FROM '
. 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0';
case 'views':
return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS';
case 'users':
return 'SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES';
default:
return null;
}
}
 
// }}}
 
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/storage.php
New file
0,0 → 1,504
<?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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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()
{
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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/mysql.php
New file
0,0 → 1,1034
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* The PEAR DB driver for PHP's mysql extension
* for interacting with MySQL 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 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: mysql.php,v 1.2 2005-09-20 17:01:22 ddelon 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 mysql extension
* for interacting with MySQL databases
*
* These methods overload the ones declared in DB_common.
*
* @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: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_mysql extends DB_common
{
// {{{ properties
 
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'mysql';
 
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'mysql';
 
/**
* 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' => '4.2.0',
'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(
1004 => DB_ERROR_CANNOT_CREATE,
1005 => DB_ERROR_CANNOT_CREATE,
1006 => DB_ERROR_CANNOT_CREATE,
1007 => DB_ERROR_ALREADY_EXISTS,
1008 => DB_ERROR_CANNOT_DROP,
1022 => DB_ERROR_ALREADY_EXISTS,
1044 => DB_ERROR_ACCESS_VIOLATION,
1046 => DB_ERROR_NODBSELECTED,
1048 => DB_ERROR_CONSTRAINT,
1049 => DB_ERROR_NOSUCHDB,
1050 => DB_ERROR_ALREADY_EXISTS,
1051 => DB_ERROR_NOSUCHTABLE,
1054 => DB_ERROR_NOSUCHFIELD,
1061 => DB_ERROR_ALREADY_EXISTS,
1062 => DB_ERROR_ALREADY_EXISTS,
1064 => DB_ERROR_SYNTAX,
1091 => DB_ERROR_NOT_FOUND,
1100 => DB_ERROR_NOT_LOCKED,
1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
1142 => DB_ERROR_ACCESS_VIOLATION,
1146 => DB_ERROR_NOSUCHTABLE,
1216 => DB_ERROR_CONSTRAINT,
1217 => 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();
 
 
/**
* 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_mysql()
{
$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 mysql driver supports the following extra DSN options:
* + new_link If set to true, causes subsequent calls to connect()
* to return a new connection link instead of the
* existing one. WARNING: this is not portable to
* other DBMS's. Available since PEAR DB 1.7.0.
* + client_flags Any combination of MYSQL_CLIENT_* constants.
* Only used if PHP is at version 4.3.0 or greater.
* 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('mysql')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
 
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
 
$params = array();
if ($dsn['protocol'] && $dsn['protocol'] == 'unix') {
$params[0] = ':' . $dsn['socket'];
} else {
$params[0] = $dsn['hostspec'] ? $dsn['hostspec']
: 'localhost';
if ($dsn['port']) {
$params[0] .= ':' . $dsn['port'];
}
}
$params[] = $dsn['username'] ? $dsn['username'] : null;
$params[] = $dsn['password'] ? $dsn['password'] : null;
 
if (!$persistent) {
if (isset($dsn['new_link'])
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true))
{
$params[] = true;
} else {
$params[] = false;
}
}
if (version_compare(phpversion(), '4.3.0', '>=')) {
$params[] = isset($dsn['client_flags'])
? $dsn['client_flags'] : null;
}
 
$connect_function = $persistent ? 'mysql_pconnect' : 'mysql_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 = @mysql_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 ($dsn['database']) {
if (!@mysql_select_db($dsn['database'], $this->connection)) {
return $this->mysqlRaiseError();
}
$this->_db = $dsn['database'];
}
 
return DB_OK;
}
 
// }}}
// {{{ disconnect()
 
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @mysql_close($this->connection);
$this->connection = null;
return $ret;
}
 
// }}}
// {{{ simpleQuery()
 
/**
* Sends a query to the database server
*
* Generally uses mysql_query(). If you want to use
* mysql_unbuffered_query() set the "result_buffering" option to 0 using
* setOptions(). This option was added in Release 1.7.0.
*
* @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 = DB::isManip($query);
$this->last_query = $query;
$query = $this->modifyQuery($query);
if ($this->_db) {
if (!@mysql_select_db($this->_db, $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @mysql_query('SET AUTOCOMMIT=0', $this->connection);
$result = @mysql_query('BEGIN', $this->connection);
if (!$result) {
return $this->mysqlRaiseError();
}
}
$this->transaction_opcount++;
}
if (!$this->options['result_buffering']) {
$result = @mysql_unbuffered_query($query, $this->connection);
} else {
$result = @mysql_query($query, $this->connection);
}
if (!$result) {
return $this->mysqlRaiseError();
}
if (is_resource($result)) {
return $result;
}
return DB_OK;
}
 
// }}}
// {{{ nextResult()
 
/**
* Move the internal mysql result pointer to the next available result
*
* This method has not been implemented yet.
*
* @param a valid sql result resource
*
* @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 (!@mysql_data_seek($result, $rownum)) {
return null;
}
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @mysql_fetch_array($result, MYSQL_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @mysql_fetch_row($result);
}
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)
{
return @mysql_free_result($result);
}
 
// }}}
// {{{ 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 = @mysql_num_fields($result);
if (!$cols) {
return $this->mysqlRaiseError();
}
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 = @mysql_num_rows($result);
if ($rows === null) {
return $this->mysqlRaiseError();
}
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 ($this->_db) {
if (!@mysql_select_db($this->_db, $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysql_query('COMMIT', $this->connection);
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqlRaiseError();
}
}
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) {
if (!@mysql_select_db($this->_db, $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysql_query('ROLLBACK', $this->connection);
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqlRaiseError();
}
}
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 (DB::isManip($this->last_query)) {
return @mysql_affected_rows($this->connection);
} else {
return 0;
}
}
 
// }}}
// {{{ 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_mysql::createSequence(), DB_mysql::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
do {
$repeat = 0;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result = $this->query("UPDATE ${seqname} ".
'SET id=LAST_INSERT_ID(id+1)');
$this->popErrorHandling();
if ($result === DB_OK) {
// COMMON CASE
$id = @mysql_insert_id($this->connection);
if ($id != 0) {
return $id;
}
// EMPTY SEQ TABLE
// Sequence table must be empty for some reason, so fill
// it and return 1 and obtain a user-level lock
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
if (DB::isError($result)) {
return $this->raiseError($result);
}
if ($result == 0) {
// Failed to get the lock
return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
}
 
// add the default value
$result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)");
if (DB::isError($result)) {
return $this->raiseError($result);
}
 
// Release the lock
$result = $this->getOne('SELECT RELEASE_LOCK('
. "'${seqname}_lock')");
if (DB::isError($result)) {
return $this->raiseError($result);
}
// We know what the result will be, so no need to try again
return 1;
 
} elseif ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE)
{
// ONDEMAND TABLE CREATION
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
} else {
$repeat = 1;
}
 
} elseif (DB::isError($result) &&
$result->getCode() == DB_ERROR_ALREADY_EXISTS)
{
// BACKWARDS COMPAT
// see _BCsequence() comment
$result = $this->_BCsequence($seqname);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$repeat = 1;
}
} while ($repeat);
 
return $this->raiseError($result);
}
 
// }}}
// {{{ createSequence()
 
/**
* 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_mysql::nextID(), DB_mysql::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$res = $this->query('CREATE TABLE ' . $seqname
. ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
. ' PRIMARY KEY(id))');
if (DB::isError($res)) {
return $res;
}
// insert yields value 1, nextId call will generate ID 2
$res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
if (DB::isError($res)) {
return $res;
}
// so reset to zero
return $this->query("UPDATE ${seqname} SET id = 0");
}
 
// }}}
// {{{ 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_mysql::nextID(), DB_mysql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
}
 
// }}}
// {{{ _BCsequence()
 
/**
* Backwards compatibility with old sequence emulation implementation
* (clean up the dupes)
*
* @param string $seqname the sequence name to clean up
*
* @return bool true on success. A DB_Error object on failure.
*
* @access private
*/
function _BCsequence($seqname)
{
// Obtain a user-level lock... this will release any previous
// application locks, but unlike LOCK TABLES, it does not abort
// the current transaction and is much less frequently used.
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
if (DB::isError($result)) {
return $result;
}
if ($result == 0) {
// Failed to get the lock, can't do the conversion, bail
// with a DB_ERROR_NOT_LOCKED error
return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
}
 
$highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
if (DB::isError($highest_id)) {
return $highest_id;
}
// This should kill all rows except the highest
// We should probably do something if $highest_id isn't
// numeric, but I'm at a loss as how to handle that...
$result = $this->query('DELETE FROM ' . $seqname
. " WHERE id <> $highest_id");
if (DB::isError($result)) {
return $result;
}
 
// If another thread has been waiting for this lock,
// it will go thru the above procedure, but will have no
// real effect
$result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
if (DB::isError($result)) {
return $result;
}
return true;
}
 
// }}}
// {{{ quoteIdentifier()
 
/**
* Quotes a string so it can be safely used as a table or column name
*
* MySQL can't handle the backtick character (<kbd>`</kbd>) in
* table or column names.
*
* @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 . '`';
}
 
// }}}
// {{{ quote()
 
/**
* @deprecated Deprecated in release 1.6.0
*/
function quote($str)
{
return $this->quoteSmart($str);
}
 
// }}}
// {{{ 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.6.0
*/
function escapeSimple($str)
{
if (function_exists('mysql_real_escape_string')) {
return @mysql_real_escape_string($str, $this->connection);
} else {
return @mysql_escape_string($str);
}
}
 
// }}}
// {{{ 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) {
// "DELETE FROM table" gives 0 affected rows in MySQL.
// This little hack lets you know how many rows were deleted.
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;
}
 
// }}}
// {{{ 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)) {
return $query . " LIMIT $count";
} else {
return $query . " LIMIT $from, $count";
}
}
 
// }}}
// {{{ mysqlRaiseError()
 
/**
* 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_mysql::errorNative(), DB_common::errorCode()
*/
function mysqlRaiseError($errno = null)
{
if ($errno === null) {
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
$this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
$this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
} else {
// Doing this in case mode changes during runtime.
$this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
$this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
}
$errno = $this->errorCode(mysql_errno($this->connection));
}
return $this->raiseError($errno, null, null, null,
@mysql_errno($this->connection) . ' ** ' .
@mysql_error($this->connection));
}
 
// }}}
// {{{ errorNative()
 
/**
* Gets the DBMS' native error code produced by the last query
*
* @return int the DBMS' error code
*/
function errorNative()
{
return @mysql_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 = @mysql_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->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA);
}
 
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
 
$count = @mysql_num_fields($id);
$res = array();
 
if ($mode) {
$res['num_fields'] = $count;
}
 
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $case_func(@mysql_field_table($id, $i)),
'name' => $case_func(@mysql_field_name($id, $i)),
'type' => @mysql_field_type($id, $i),
'len' => @mysql_field_len($id, $i),
'flags' => @mysql_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) {
@mysql_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 'SHOW TABLES';
case 'users':
return 'SELECT DISTINCT User FROM mysql.user';
case 'databases':
return 'SHOW DATABASES';
default:
return null;
}
}
 
// }}}
 
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/ifx.php
New file
0,0 → 1,681
<?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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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,
'-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,
'-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 = DB::isManip($query);
$this->last_query = $query;
$this->affected = null;
if (preg_match('/(SELECT)/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)/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 (DB::isManip($this->last_query)) {
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 @ifx_free_result($result);
}
 
// }}}
// {{{ 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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/pgsql.php
New file
0,0 → 1,1097
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* The PEAR DB driver for PHP's pgsql extension
* for interacting with PostgreSQL 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 Rui Hirokawa <hirokawa@php.net>
* @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: pgsql.php,v 1.2 2005-09-20 17:01:22 ddelon 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 pgsql extension
* for interacting with PostgreSQL databases
*
* These methods overload the ones declared in DB_common.
*
* @category Database
* @package DB
* @author Rui Hirokawa <hirokawa@php.net>
* @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: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_pgsql extends DB_common
{
// {{{ properties
 
/**
* The DB driver type (mysql, oci8, odbc, etc.)
* @var string
*/
var $phptype = 'pgsql';
 
/**
* The database syntax variant to be used (db2, access, etc.), if any
* @var string
*/
var $dbsyntax = 'pgsql';
 
/**
* 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' => '4.3.0',
'numrows' => true,
'pconnect' => true,
'prepare' => false,
'ssl' => true,
'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 number of rows affected by a data manipulation query
* @var integer
*/
var $affected = 0;
 
/**
* The current row being looked at in fetchInto()
* @var array
* @access private
*/
var $row = array();
 
/**
* The number of rows in a given result set
* @var array
* @access private
*/
var $_num_rows = array();
 
 
// }}}
// {{{ constructor
 
/**
* This constructor calls <kbd>$this->DB_common()</kbd>
*
* @return void
*/
function DB_pgsql()
{
$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 pgsql driver supports the following extra DSN options:
* + connect_timeout How many seconds to wait for a connection to
* be established. Available since PEAR DB 1.7.0.
* + new_link If set to true, causes subsequent calls to
* connect() to return a new connection link
* instead of the existing one. WARNING: this is
* not portable to other DBMS's. Available only
* if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0.
* + options Command line options to be sent to the server.
* Available since PEAR DB 1.6.4.
* + service Specifies a service name in pg_service.conf that
* holds additional connection parameters.
* Available since PEAR DB 1.7.0.
* + sslmode How should SSL be used when connecting? Values:
* disable, allow, prefer or require.
* Available since PEAR DB 1.7.0.
* + tty This was used to specify where to send server
* debug output. Available since PEAR DB 1.6.4.
*
* Example of connecting to a new link via a socket:
* <code>
* require_once 'DB.php';
*
* $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
* $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.
*
* @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT
*/
function connect($dsn, $persistent = false)
{
if (!PEAR::loadExtension('pgsql')) {
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
}
 
$this->dsn = $dsn;
if ($dsn['dbsyntax']) {
$this->dbsyntax = $dsn['dbsyntax'];
}
 
$protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp';
 
$params = array('');
if ($protocol == 'tcp') {
if ($dsn['hostspec']) {
$params[0] .= 'host=' . $dsn['hostspec'];
}
if ($dsn['port']) {
$params[0] .= ' port=' . $dsn['port'];
}
} elseif ($protocol == 'unix') {
// Allow for pg socket in non-standard locations.
if ($dsn['socket']) {
$params[0] .= 'host=' . $dsn['socket'];
}
if ($dsn['port']) {
$params[0] .= ' port=' . $dsn['port'];
}
}
if ($dsn['database']) {
$params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\'';
}
if ($dsn['username']) {
$params[0] .= ' user=\'' . addslashes($dsn['username']) . '\'';
}
if ($dsn['password']) {
$params[0] .= ' password=\'' . addslashes($dsn['password']) . '\'';
}
if (!empty($dsn['options'])) {
$params[0] .= ' options=' . $dsn['options'];
}
if (!empty($dsn['tty'])) {
$params[0] .= ' tty=' . $dsn['tty'];
}
if (!empty($dsn['connect_timeout'])) {
$params[0] .= ' connect_timeout=' . $dsn['connect_timeout'];
}
if (!empty($dsn['sslmode'])) {
$params[0] .= ' sslmode=' . $dsn['sslmode'];
}
if (!empty($dsn['service'])) {
$params[0] .= ' service=' . $dsn['service'];
}
 
if (isset($dsn['new_link'])
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true))
{
if (version_compare(phpversion(), '4.3.0', '>=')) {
$params[] = PGSQL_CONNECT_FORCE_NEW;
}
}
 
$connect_function = $persistent ? 'pg_pconnect' : 'pg_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);
}
return DB_OK;
}
 
// }}}
// {{{ disconnect()
 
/**
* Disconnects from the database server
*
* @return bool TRUE on success, FALSE on failure
*/
function disconnect()
{
$ret = @pg_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 = DB::isManip($query);
$this->last_query = $query;
$query = $this->modifyQuery($query);
if (!$this->autocommit && $ismanip) {
if ($this->transaction_opcount == 0) {
$result = @pg_exec($this->connection, 'begin;');
if (!$result) {
return $this->pgsqlRaiseError();
}
}
$this->transaction_opcount++;
}
$result = @pg_exec($this->connection, $query);
if (!$result) {
return $this->pgsqlRaiseError();
}
// Determine which queries that should return data, and which
// should return an error code only.
if ($ismanip) {
$this->affected = @pg_affected_rows($result);
return DB_OK;
} elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) {
/* PostgreSQL commands:
ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
UNLISTEN, UPDATE, VACUUM
*/
$this->row[(int)$result] = 0; // reset the row counter.
$numrows = $this->numRows($result);
if (is_object($numrows)) {
return $numrows;
}
$this->_num_rows[(int)$result] = $numrows;
$this->affected = 0;
return $result;
} else {
$this->affected = 0;
return DB_OK;
}
}
 
// }}}
// {{{ nextResult()
 
/**
* Move the internal pgsql 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.
*
* @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)
{
$result_int = (int)$result;
$rownum = ($rownum !== null) ? $rownum : $this->row[$result_int];
if ($rownum >= $this->_num_rows[$result_int]) {
return null;
}
if ($fetchmode & DB_FETCHMODE_ASSOC) {
$arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
$arr = array_change_key_case($arr, CASE_LOWER);
}
} else {
$arr = @pg_fetch_row($result, $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);
}
$this->row[$result_int] = ++$rownum;
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)
{
if (is_resource($result)) {
unset($this->row[(int)$result]);
unset($this->_num_rows[(int)$result]);
$this->affected = 0;
return @pg_freeresult($result);
}
return false;
}
 
// }}}
// {{{ quote()
 
/**
* @deprecated Deprecated in release 1.6.0
* @internal
*/
function quote($str)
{
return $this->quoteSmart($str);
}
 
// }}}
// {{{ quoteSmart()
 
/**
* Formats input so it can be safely used in a query
*
* @param mixed $in the data to be formatted
*
* @return mixed the formatted data. The format depends on the input's
* PHP type:
* + null = the string <samp>NULL</samp>
* + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
* + integer or double = the unquoted number
* + other (including strings and numeric strings) =
* the data escaped according to MySQL's settings
* then encapsulated between single quotes
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
function quoteSmart($in)
{
if (is_int($in) || is_double($in)) {
return $in;
} elseif (is_bool($in)) {
return $in ? 'TRUE' : 'FALSE';
} elseif (is_null($in)) {
return 'NULL';
} else {
return "'" . $this->escapeSimple($in) . "'";
}
}
 
// }}}
// {{{ escapeSimple()
 
/**
* Escapes a string according to the current DBMS's standards
*
* {@internal PostgreSQL treats a backslash as an escape character,
* so they are escaped as well.
*
* Not using pg_escape_string() yet because it requires PostgreSQL
* to be at version 7.2 or greater.}}
*
* @param string $str the string to be escaped
*
* @return string the escaped string
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
function escapeSimple($str)
{
return str_replace("'", "''", str_replace('\\', '\\\\', $str));
}
 
// }}}
// {{{ 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 = @pg_numfields($result);
if (!$cols) {
return $this->pgsqlRaiseError();
}
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 = @pg_numrows($result);
if ($rows === null) {
return $this->pgsqlRaiseError();
}
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) {
// (disabled) hack to shut up error messages from libpq.a
//@fclose(@fopen("php://stderr", "w"));
$result = @pg_exec($this->connection, 'end;');
$this->transaction_opcount = 0;
if (!$result) {
return $this->pgsqlRaiseError();
}
}
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 = @pg_exec($this->connection, 'abort;');
$this->transaction_opcount = 0;
if (!$result) {
return $this->pgsqlRaiseError();
}
}
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()
{
return $this->affected;
}
 
// }}}
// {{{ 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_pgsql::createSequence(), DB_pgsql::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
$repeat = false;
do {
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$result =& $this->query("SELECT NEXTVAL('${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
*
* @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_pgsql::nextID(), DB_pgsql::dropSequence()
*/
function createSequence($seq_name)
{
$seqname = $this->getSequenceName($seq_name);
$result = $this->query("CREATE SEQUENCE ${seqname}");
return $result;
}
 
// }}}
// {{{ 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_pgsql::nextID(), DB_pgsql::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP SEQUENCE '
. $this->getSequenceName($seq_name));
}
 
// }}}
// {{{ 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";
}
 
// }}}
// {{{ pgsqlRaiseError()
 
/**
* 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_pgsql::errorNative(), DB_pgsql::errorCode()
*/
function pgsqlRaiseError($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
*
* {@internal Error messages are used instead of error codes
* in order to support older versions of PostgreSQL.}}
*
* @return string the DBMS' error message
*/
function errorNative()
{
return @pg_errormessage($this->connection);
}
 
// }}}
// {{{ 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;
if (!isset($error_regexps)) {
$error_regexps = array(
'/(relation|sequence|table).*does not exist|class .* not found/i'
=> DB_ERROR_NOSUCHTABLE,
'/index .* does not exist/'
=> DB_ERROR_NOT_FOUND,
'/column .* does not exist/i'
=> DB_ERROR_NOSUCHFIELD,
'/relation .* already exists/i'
=> DB_ERROR_ALREADY_EXISTS,
'/(divide|division) by zero$/i'
=> DB_ERROR_DIVZERO,
'/pg_atoi: error in .*: can\'t parse /i'
=> DB_ERROR_INVALID_NUMBER,
'/invalid input syntax for( type)? (integer|numeric)/i'
=> DB_ERROR_INVALID_NUMBER,
'/value .* is out of range for type \w*int/i'
=> DB_ERROR_INVALID_NUMBER,
'/integer out of range/i'
=> DB_ERROR_INVALID_NUMBER,
'/value too long for type character/i'
=> DB_ERROR_INVALID,
'/attribute .* not found|relation .* does not have attribute/i'
=> DB_ERROR_NOSUCHFIELD,
'/column .* specified in USING clause does not exist in (left|right) table/i'
=> DB_ERROR_NOSUCHFIELD,
'/parser: parse error at or near/i'
=> DB_ERROR_SYNTAX,
'/syntax error at/'
=> DB_ERROR_SYNTAX,
'/column reference .* is ambiguous/i'
=> DB_ERROR_SYNTAX,
'/permission denied/'
=> DB_ERROR_ACCESS_VIOLATION,
'/violates not-null constraint/'
=> DB_ERROR_CONSTRAINT_NOT_NULL,
'/violates [\w ]+ constraint/'
=> DB_ERROR_CONSTRAINT,
'/referential integrity violation/'
=> DB_ERROR_CONSTRAINT,
'/more expressions than target 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 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.
*/
$id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
$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->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
}
 
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
 
$count = @pg_numfields($id);
$res = array();
 
if ($mode) {
$res['num_fields'] = $count;
}
 
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $got_string ? $case_func($result) : '',
'name' => $case_func(@pg_fieldname($id, $i)),
'type' => @pg_fieldtype($id, $i),
'len' => @pg_fieldsize($id, $i),
'flags' => $got_string
? $this->_pgFieldFlags($id, $i, $result)
: '',
);
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) {
@pg_freeresult($id);
}
return $res;
}
 
// }}}
// {{{ _pgFieldFlags()
 
/**
* Get a column's flags
*
* Supports "not_null", "default_value", "primary_key", "unique_key"
* and "multiple_key". The default value is passed through
* rawurlencode() in case there are spaces in it.
*
* @param int $resource the PostgreSQL result identifier
* @param int $num_field the field number
*
* @return string the flags
*
* @access private
*/
function _pgFieldFlags($resource, $num_field, $table_name)
{
$field_name = @pg_fieldname($resource, $num_field);
 
$result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
FROM pg_attribute f, pg_class tab, pg_type typ
WHERE tab.relname = typ.typname
AND typ.typrelid = f.attrelid
AND f.attname = '$field_name'
AND tab.relname = '$table_name'");
if (@pg_numrows($result) > 0) {
$row = @pg_fetch_row($result, 0);
$flags = ($row[0] == 't') ? 'not_null ' : '';
 
if ($row[1] == 't') {
$result = @pg_exec($this->connection, "SELECT a.adsrc
FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
AND f.attrelid = a.adrelid AND f.attname = '$field_name'
AND tab.relname = '$table_name' AND f.attnum = a.adnum");
$row = @pg_fetch_row($result, 0);
$num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
$flags .= 'default_' . rawurlencode($num) . ' ';
}
} else {
$flags = '';
}
$result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
WHERE tab.relname = typ.typname
AND typ.typrelid = f.attrelid
AND f.attrelid = i.indrelid
AND f.attname = '$field_name'
AND tab.relname = '$table_name'");
$count = @pg_numrows($result);
 
for ($i = 0; $i < $count ; $i++) {
$row = @pg_fetch_row($result, $i);
$keys = explode(' ', $row[2]);
 
if (in_array($num_field + 1, $keys)) {
$flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
$flags .= ($row[1] == 't') ? 'primary_key ' : '';
if (count($keys) > 1)
$flags .= 'multiple_key ';
}
}
 
return trim($flags);
}
 
// }}}
// {{{ 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 c.relname AS "Name"'
. ' FROM pg_class c, pg_user u'
. ' WHERE c.relowner = u.usesysid'
. " AND c.relkind = 'r'"
. ' AND NOT EXISTS'
. ' (SELECT 1 FROM pg_views'
. ' WHERE viewname = c.relname)'
. " AND c.relname !~ '^(pg_|sql_)'"
. ' UNION'
. ' SELECT c.relname AS "Name"'
. ' FROM pg_class c'
. " WHERE c.relkind = 'r'"
. ' AND NOT EXISTS'
. ' (SELECT 1 FROM pg_views'
. ' WHERE viewname = c.relname)'
. ' AND NOT EXISTS'
. ' (SELECT 1 FROM pg_user'
. ' WHERE usesysid = c.relowner)'
. " AND c.relname !~ '^pg_'";
case 'schema.tables':
return "SELECT schemaname || '.' || tablename"
. ' AS "Name"'
. ' FROM pg_catalog.pg_tables'
. ' WHERE schemaname NOT IN'
. " ('pg_catalog', 'information_schema', 'pg_toast')";
case 'views':
// Table cols: viewname | viewowner | definition
return 'SELECT viewname from pg_views WHERE schemaname'
. " NOT IN ('information_schema', 'pg_catalog')";
case 'users':
// cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil
return 'SELECT usename FROM pg_user';
case 'databases':
return 'SELECT datname FROM pg_database';
case 'functions':
case 'procedures':
return 'SELECT proname FROM pg_proc WHERE proowner <> 1';
default:
return null;
}
}
 
// }}}
 
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/sybase.php
New file
0,0 → 1,907
<?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ônio Carlos Venâ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.2 2005-09-20 17:01:22 ddelon 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ônio Carlos Venâ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: @package_version@
* @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 = DB::isManip($query);
$this->last_query = $query;
if (!@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 @sybase_free_result($result);
}
 
// }}}
// {{{ 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 (DB::isManip($this->last_query)) {
$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 (!@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));
}
 
// }}}
// {{{ 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 (!@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 (!@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;
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,
);
}
 
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 (!@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;
 
// get unique/primary keys
$res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC);
 
if (!isset($res[0]['index_description'])) {
return '';
}
 
foreach ($res as $val) {
$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');
}
}
}
 
}
 
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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/fbsql.php
New file
0,0 → 1,770
<?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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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 (DB::isManip($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 @fbsql_free_result($result);
}
 
// }}}
// {{{ 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();
}
 
// }}}
// {{{ rollback()
 
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
@fbsql_rollback();
}
 
// }}}
// {{{ 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 (DB::isManip($this->last_query)) {
$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)) {
return preg_replace('/^([\s(])*SELECT/i',
"\\1SELECT TOP($count)", $query);
} else {
return preg_replace('/([\s(])*SELECT/i',
"\\1SELECT TOP($from, $count)", $query);
}
}
 
// }}}
// {{{ quoteSmart()
 
/**
* Formats input so it can be safely used in a query
*
* @param mixed $in the data to be formatted
*
* @return mixed the formatted data. The format depends on the input's
* PHP type:
* + null = the string <samp>NULL</samp>
* + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
* + integer or double = the unquoted number
* + other (including strings and numeric strings) =
* the data escaped according to FrontBase's settings
* then encapsulated between single quotes
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
function quoteSmart($in)
{
if (is_int($in) || is_double($in)) {
return $in;
} elseif (is_bool($in)) {
return $in ? 'TRUE' : 'FALSE';
} elseif (is_null($in)) {
return 'NULL';
} else {
return "'" . $this->escapeSimple($in) . "'";
}
}
 
// }}}
// {{{ 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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/odbc.php
New 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.2 2005-09-20 17:01:22 ddelon 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: @package_version@
* @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 (DB::isManip($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 @odbc_free_result($result);
}
 
// }}}
// {{{ 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:
*/
 
?>
/branches/v1.0-menes/api/pear/DB/common.php
New file
0,0 → 1,2157
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the DB_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 Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @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: common.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
* @link http://pear.php.net/package/DB
*/
 
/**
* Obtain the PEAR class so it can be extended from
*/
require_once 'PEAR.php';
 
/**
* DB_common is the base class from which each database driver class extends
*
* All common methods are declared here. If a given DBMS driver contains
* a particular method, that method will overload the one here.
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @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: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_common extends PEAR
{
// {{{ properties
 
/**
* The current default fetch mode
* @var integer
*/
var $fetchmode = DB_FETCHMODE_ORDERED;
 
/**
* The name of the class into which results should be fetched when
* DB_FETCHMODE_OBJECT is in effect
*
* @var string
*/
var $fetchmode_object_class = 'stdClass';
 
/**
* Was a connection present when the object was serialized()?
* @var bool
* @see DB_common::__sleep(), DB_common::__wake()
*/
var $was_connected = null;
 
/**
* The most recently executed query
* @var string
*/
var $last_query = '';
 
/**
* Run-time configuration options
*
* The 'optimize' option has been deprecated. Use the 'portability'
* option instead.
*
* @var array
* @see DB_common::setOption()
*/
var $options = array(
'result_buffering' => 500,
'persistent' => false,
'ssl' => false,
'debug' => 0,
'seqname_format' => '%s_seq',
'autofree' => false,
'portability' => DB_PORTABILITY_NONE,
'optimize' => 'performance', // Deprecated. Use 'portability'.
);
 
/**
* The parameters from the most recently executed query
* @var array
* @since Property available since Release 1.7.0
*/
var $last_parameters = array();
 
/**
* The elements from each prepared statement
* @var array
*/
var $prepare_tokens = array();
 
/**
* The data types of the various elements in each prepared statement
* @var array
*/
var $prepare_types = array();
 
/**
* The prepared queries
* @var array
*/
var $prepared_queries = array();
 
 
// }}}
// {{{ DB_common
 
/**
* This constructor calls <kbd>$this->PEAR('DB_Error')</kbd>
*
* @return void
*/
function DB_common()
{
$this->PEAR('DB_Error');
}
 
// }}}
// {{{ __sleep()
 
/**
* Automatically indicates which properties should be saved
* when PHP's serialize() function is called
*
* @return array the array of properties names that should be saved
*/
function __sleep()
{
if ($this->connection) {
// Don't disconnect(), people use serialize() for many reasons
$this->was_connected = true;
} else {
$this->was_connected = false;
}
if (isset($this->autocommit)) {
return array('autocommit',
'dbsyntax',
'dsn',
'features',
'fetchmode',
'fetchmode_object_class',
'options',
'was_connected',
);
} else {
return array('dbsyntax',
'dsn',
'features',
'fetchmode',
'fetchmode_object_class',
'options',
'was_connected',
);
}
}
 
// }}}
// {{{ __wakeup()
 
/**
* Automatically reconnects to the database when PHP's unserialize()
* function is called
*
* The reconnection attempt is only performed if the object was connected
* at the time PHP's serialize() function was run.
*
* @return void
*/
function __wakeup()
{
if ($this->was_connected) {
$this->connect($this->dsn, $this->options);
}
}
 
// }}}
// {{{ __toString()
 
/**
* Automatic string conversion for PHP 5
*
* @return string a string describing the current PEAR DB object
*
* @since Method available since Release 1.7.0
*/
function __toString()
{
$info = strtolower(get_class($this));
$info .= ': (phptype=' . $this->phptype .
', dbsyntax=' . $this->dbsyntax .
')';
if ($this->connection) {
$info .= ' [connected]';
}
return $info;
}
 
// }}}
// {{{ toString()
 
/**
* DEPRECATED: String conversion method
*
* @return string a string describing the current PEAR DB object
*
* @deprecated Method deprecated in Release 1.7.0
*/
function toString()
{
return $this->__toString();
}
 
// }}}
// {{{ quoteString()
 
/**
* DEPRECATED: Quotes a string so it can be safely used within string
* delimiters in a query
*
* @param string $string the string to be quoted
*
* @return string the quoted string
*
* @see DB_common::quoteSmart(), DB_common::escapeSimple()
* @deprecated Method deprecated some time before Release 1.2
*/
function quoteString($string)
{
$string = $this->quote($string);
if ($string{0} == "'") {
return substr($string, 1, -1);
}
return $string;
}
 
// }}}
// {{{ quote()
 
/**
* DEPRECATED: Quotes a string so it can be safely used in a query
*
* @param string $string the string to quote
*
* @return string the quoted string or the string <samp>NULL</samp>
* if the value submitted is <kbd>null</kbd>.
*
* @see DB_common::quoteSmart(), DB_common::escapeSimple()
* @deprecated Deprecated in release 1.6.0
*/
function quote($string = null)
{
return ($string === null) ? 'NULL'
: "'" . str_replace("'", "''", $string) . "'";
}
 
// }}}
// {{{ quoteIdentifier()
 
/**
* Quotes a string so it can be safely used as a table or column name
*
* Delimiting style depends on which database driver is being used.
*
* NOTE: just because you CAN use delimited identifiers doesn't mean
* you SHOULD use them. In general, they end up causing way more
* problems than they solve.
*
* Portability is broken by using the following characters inside
* delimited identifiers:
* + backtick (<kbd>`</kbd>) -- due to MySQL
* + double quote (<kbd>"</kbd>) -- due to Oracle
* + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
*
* Delimited identifiers are known to generally work correctly under
* the following drivers:
* + mssql
* + mysql
* + mysqli
* + oci8
* + odbc(access)
* + odbc(db2)
* + pgsql
* + sqlite
* + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime
* prior to use)
*
* InterBase doesn't seem to be able to use delimited identifiers
* via PHP 4. They work fine under PHP 5.
*
* @param string $str the identifier name to be quoted
*
* @return string the quoted identifier
*
* @since Method available since Release 1.6.0
*/
function quoteIdentifier($str)
{
return '"' . str_replace('"', '""', $str) . '"';
}
 
// }}}
// {{{ quoteSmart()
 
/**
* Formats input so it can be safely used in a query
*
* The output depends on the PHP data type of input and the database
* type being used.
*
* @param mixed $in the data to be formatted
*
* @return mixed the formatted data. The format depends on the input's
* PHP type:
* <ul>
* <li>
* <kbd>input</kbd> -> <samp>returns</samp>
* </li>
* <li>
* <kbd>null</kbd> -> the string <samp>NULL</samp>
* </li>
* <li>
* <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number
* </li>
* <li>
* <kbd>bool</kbd> -> output depends on the driver in use
* Most drivers return integers: <samp>1</samp> if
* <kbd>true</kbd> or <samp>0</samp> if
* <kbd>false</kbd>.
* Some return strings: <samp>TRUE</samp> if
* <kbd>true</kbd> or <samp>FALSE</samp> if
* <kbd>false</kbd>.
* Finally one returns strings: <samp>T</samp> if
* <kbd>true</kbd> or <samp>F</samp> if
* <kbd>false</kbd>. Here is a list of each DBMS,
* the values returned and the suggested column type:
* <ul>
* <li>
* <kbd>dbase</kbd> -> <samp>T/F</samp>
* (<kbd>Logical</kbd>)
* </li>
* <li>
* <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp>
* (<kbd>BOOLEAN</kbd>)
* </li>
* <li>
* <kbd>ibase</kbd> -> <samp>1/0</samp>
* (<kbd>SMALLINT</kbd>) [1]
* </li>
* <li>
* <kbd>ifx</kbd> -> <samp>1/0</samp>
* (<kbd>SMALLINT</kbd>) [1]
* </li>
* <li>
* <kbd>msql</kbd> -> <samp>1/0</samp>
* (<kbd>INTEGER</kbd>)
* </li>
* <li>
* <kbd>mssql</kbd> -> <samp>1/0</samp>
* (<kbd>BIT</kbd>)
* </li>
* <li>
* <kbd>mysql</kbd> -> <samp>1/0</samp>
* (<kbd>TINYINT(1)</kbd>)
* </li>
* <li>
* <kbd>mysqli</kbd> -> <samp>1/0</samp>
* (<kbd>TINYINT(1)</kbd>)
* </li>
* <li>
* <kbd>oci8</kbd> -> <samp>1/0</samp>
* (<kbd>NUMBER(1)</kbd>)
* </li>
* <li>
* <kbd>odbc</kbd> -> <samp>1/0</samp>
* (<kbd>SMALLINT</kbd>) [1]
* </li>
* <li>
* <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp>
* (<kbd>BOOLEAN</kbd>)
* </li>
* <li>
* <kbd>sqlite</kbd> -> <samp>1/0</samp>
* (<kbd>INTEGER</kbd>)
* </li>
* <li>
* <kbd>sybase</kbd> -> <samp>1/0</samp>
* (<kbd>TINYINT(1)</kbd>)
* </li>
* </ul>
* [1] Accommodate the lowest common denominator because not all
* versions of have <kbd>BOOLEAN</kbd>.
* </li>
* <li>
* other (including strings and numeric strings) ->
* the data with single quotes escaped by preceeding
* single quotes, backslashes are escaped by preceeding
* backslashes, then the whole string is encapsulated
* between single quotes
* </li>
* </ul>
*
* @see DB_common::escapeSimple()
* @since Method available since Release 1.6.0
*/
function quoteSmart($in)
{
if (is_int($in) || is_double($in)) {
return $in;
} elseif (is_bool($in)) {
return $in ? 1 : 0;
} elseif (is_null($in)) {
return 'NULL';
} else {
return "'" . $this->escapeSimple($in) . "'";
}
}
 
// }}}
// {{{ 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
*
* @see DB_common::quoteSmart()
* @since Method available since Release 1.6.0
*/
function escapeSimple($str)
{
return str_replace("'", "''", $str);
}
 
// }}}
// {{{ provides()
 
/**
* Tells whether the present driver supports a given feature
*
* @param string $feature the feature you're curious about
*
* @return bool whether this driver supports $feature
*/
function provides($feature)
{
return $this->features[$feature];
}
 
// }}}
// {{{ setFetchMode()
 
/**
* Sets the fetch mode that should be used by default for query results
*
* @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC
* or DB_FETCHMODE_OBJECT
* @param string $object_class the class name of the object to be returned
* by the fetch methods when the
* DB_FETCHMODE_OBJECT mode is selected.
* If no class is specified by default a cast
* to object from the assoc array row will be
* done. There is also the posibility to use
* and extend the 'DB_row' class.
*
* @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT
*/
function setFetchMode($fetchmode, $object_class = 'stdClass')
{
switch ($fetchmode) {
case DB_FETCHMODE_OBJECT:
$this->fetchmode_object_class = $object_class;
case DB_FETCHMODE_ORDERED:
case DB_FETCHMODE_ASSOC:
$this->fetchmode = $fetchmode;
break;
default:
return $this->raiseError('invalid fetchmode mode');
}
}
 
// }}}
// {{{ setOption()
 
/**
* Sets run-time configuration options for PEAR DB
*
* Options, their data types, default values and description:
* <ul>
* <li>
* <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp>
* <br />should results be freed automatically when there are no
* more rows?
* </li><li>
* <var>result_buffering</var> <kbd>integer</kbd> = <samp>500</samp>
* <br />how many rows of the result set should be buffered?
* <br />In mysql: mysql_unbuffered_query() is used instead of
* mysql_query() if this value is 0. (Release 1.7.0)
* <br />In oci8: this value is passed to ocisetprefetch().
* (Release 1.7.0)
* </li><li>
* <var>debug</var> <kbd>integer</kbd> = <samp>0</samp>
* <br />debug level
* </li><li>
* <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp>
* <br />should the connection be persistent?
* </li><li>
* <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp>
* <br />portability mode constant (see below)
* </li><li>
* <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp>
* <br />the sprintf() format string used on sequence names. This
* format is applied to sequence names passed to
* createSequence(), nextID() and dropSequence().
* </li><li>
* <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp>
* <br />use ssl to connect?
* </li>
* </ul>
*
* -----------------------------------------
*
* PORTABILITY MODES
*
* These modes are bitwised, so they can be combined using <kbd>|</kbd>
* and removed using <kbd>^</kbd>. See the examples section below on how
* to do this.
*
* <samp>DB_PORTABILITY_NONE</samp>
* turn off all portability features
*
* This mode gets automatically turned on if the deprecated
* <var>optimize</var> option gets set to <samp>performance</samp>.
*
*
* <samp>DB_PORTABILITY_LOWERCASE</samp>
* convert names of tables and fields to lower case when using
* <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd>
*
* This mode gets automatically turned on in the following databases
* if the deprecated option <var>optimize</var> gets set to
* <samp>portability</samp>:
* + oci8
*
*
* <samp>DB_PORTABILITY_RTRIM</samp>
* right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd>
*
*
* <samp>DB_PORTABILITY_DELETE_COUNT</samp>
* force reporting the number of rows deleted
*
* Some DBMS's don't count the number of rows deleted when performing
* simple <kbd>DELETE FROM tablename</kbd> queries. This portability
* mode tricks such DBMS's into telling the count by adding
* <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries.
*
* This mode gets automatically turned on in the following databases
* if the deprecated option <var>optimize</var> gets set to
* <samp>portability</samp>:
* + fbsql
* + mysql
* + mysqli
* + sqlite
*
*
* <samp>DB_PORTABILITY_NUMROWS</samp>
* enable hack that makes <kbd>numRows()</kbd> work in Oracle
*
* This mode gets automatically turned on in the following databases
* if the deprecated option <var>optimize</var> gets set to
* <samp>portability</samp>:
* + oci8
*
*
* <samp>DB_PORTABILITY_ERRORS</samp>
* makes certain error messages in certain drivers compatible
* with those from other DBMS's
*
* + mysql, mysqli: change unique/primary key constraints
* DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT
*
* + odbc(access): MS's ODBC driver reports 'no such field' as code
* 07001, which means 'too few parameters.' When this option is on
* that code gets mapped to DB_ERROR_NOSUCHFIELD.
* DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD
*
* <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp>
* convert null values to empty strings in data output by get*() and
* fetch*(). Needed because Oracle considers empty strings to be null,
* while most other DBMS's know the difference between empty and null.
*
*
* <samp>DB_PORTABILITY_ALL</samp>
* turn on all portability features
*
* -----------------------------------------
*
* Example 1. Simple setOption() example
* <code>
* $db->setOption('autofree', true);
* </code>
*
* Example 2. Portability for lowercasing and trimming
* <code>
* $db->setOption('portability',
* DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM);
* </code>
*
* Example 3. All portability options except trimming
* <code>
* $db->setOption('portability',
* DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM);
* </code>
*
* @param string $option option name
* @param mixed $value value for the option
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::$options
*/
function setOption($option, $value)
{
if (isset($this->options[$option])) {
$this->options[$option] = $value;
 
/*
* Backwards compatibility check for the deprecated 'optimize'
* option. Done here in case settings change after connecting.
*/
if ($option == 'optimize') {
if ($value == 'portability') {
switch ($this->phptype) {
case 'oci8':
$this->options['portability'] =
DB_PORTABILITY_LOWERCASE |
DB_PORTABILITY_NUMROWS;
break;
case 'fbsql':
case 'mysql':
case 'mysqli':
case 'sqlite':
$this->options['portability'] =
DB_PORTABILITY_DELETE_COUNT;
break;
}
} else {
$this->options['portability'] = DB_PORTABILITY_NONE;
}
}
 
return DB_OK;
}
return $this->raiseError("unknown option $option");
}
 
// }}}
// {{{ getOption()
 
/**
* Returns the value of an option
*
* @param string $option the option name you're curious about
*
* @return mixed the option's value
*/
function getOption($option)
{
if (isset($this->options[$option])) {
return $this->options[$option];
}
return $this->raiseError("unknown option $option");
}
 
// }}}
// {{{ prepare()
 
/**
* Prepares a query for multiple execution with execute()
*
* Creates a query that can be run multiple times. Each time it is run,
* the placeholders, if any, will be replaced by the contents of
* execute()'s $data argument.
*
* Three types of placeholders can be used:
* + <kbd>?</kbd> scalar value (i.e. strings, integers). The system
* will automatically quote and escape the data.
* + <kbd>!</kbd> value is inserted 'as is'
* + <kbd>&</kbd> requires a file name. The file's contents get
* inserted into the query (i.e. saving binary
* data in a db)
*
* Example 1.
* <code>
* $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
* $data = array(
* "John's text",
* "'it''s good'",
* 'filename.txt'
* );
* $res = $db->execute($sth, $data);
* </code>
*
* Use backslashes to escape placeholder characters if you don't want
* them to be interpreted as placeholders:
* <pre>
* "UPDATE foo SET col=? WHERE col='over \& under'"
* </pre>
*
* With some database backends, this is emulated.
*
* {@internal ibase and oci8 have their own prepare() methods.}}
*
* @param string $query the query to be prepared
*
* @return mixed DB statement resource on success. A DB_Error object
* on failure.
*
* @see DB_common::execute()
*/
function prepare($query)
{
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1,
PREG_SPLIT_DELIM_CAPTURE);
$token = 0;
$types = array();
$newtokens = array();
 
foreach ($tokens as $val) {
switch ($val) {
case '?':
$types[$token++] = DB_PARAM_SCALAR;
break;
case '&':
$types[$token++] = DB_PARAM_OPAQUE;
break;
case '!':
$types[$token++] = DB_PARAM_MISC;
break;
default:
$newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val);
}
}
 
$this->prepare_tokens[] = &$newtokens;
end($this->prepare_tokens);
 
$k = key($this->prepare_tokens);
$this->prepare_types[$k] = $types;
$this->prepared_queries[$k] = implode(' ', $newtokens);
 
return $k;
}
 
// }}}
// {{{ autoPrepare()
 
/**
* Automaticaly generates an insert or update query and pass it to prepare()
*
* @param string $table the table name
* @param array $table_fields the array of field names
* @param int $mode a type of query to make:
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
* @param string $where for update queries: the WHERE clause to
* append to the SQL statement. Don't
* include the "WHERE" keyword.
*
* @return resource the query handle
*
* @uses DB_common::prepare(), DB_common::buildManipSQL()
*/
function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT,
$where = false)
{
$query = $this->buildManipSQL($table, $table_fields, $mode, $where);
if (DB::isError($query)) {
return $query;
}
return $this->prepare($query);
}
 
// }}}
// {{{ autoExecute()
 
/**
* Automaticaly generates an insert or update query and call prepare()
* and execute() with it
*
* @param string $table the table name
* @param array $fields_values the associative array where $key is a
* field name and $value its value
* @param int $mode a type of query to make:
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
* @param string $where for update queries: the WHERE clause to
* append to the SQL statement. Don't
* include the "WHERE" keyword.
*
* @return mixed a new DB_result object for successful SELECT queries
* or DB_OK for successul data manipulation queries.
* A DB_Error object on failure.
*
* @uses DB_common::autoPrepare(), DB_common::execute()
*/
function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT,
$where = false)
{
$sth = $this->autoPrepare($table, array_keys($fields_values), $mode,
$where);
if (DB::isError($sth)) {
return $sth;
}
$ret =& $this->execute($sth, array_values($fields_values));
$this->freePrepared($sth);
return $ret;
 
}
 
// }}}
// {{{ buildManipSQL()
 
/**
* Produces an SQL query string for autoPrepare()
*
* Example:
* <pre>
* buildManipSQL('table_sql', array('field1', 'field2', 'field3'),
* DB_AUTOQUERY_INSERT);
* </pre>
*
* That returns
* <samp>
* INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?)
* </samp>
*
* NOTES:
* - This belongs more to a SQL Builder class, but this is a simple
* facility.
* - Be carefull! If you don't give a $where param with an UPDATE
* query, all the records of the table will be updated!
*
* @param string $table the table name
* @param array $table_fields the array of field names
* @param int $mode a type of query to make:
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
* @param string $where for update queries: the WHERE clause to
* append to the SQL statement. Don't
* include the "WHERE" keyword.
*
* @return string the sql query for autoPrepare()
*/
function buildManipSQL($table, $table_fields, $mode, $where = false)
{
if (count($table_fields) == 0) {
return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
}
$first = true;
switch ($mode) {
case DB_AUTOQUERY_INSERT:
$values = '';
$names = '';
foreach ($table_fields as $value) {
if ($first) {
$first = false;
} else {
$names .= ',';
$values .= ',';
}
$names .= $value;
$values .= '?';
}
return "INSERT INTO $table ($names) VALUES ($values)";
case DB_AUTOQUERY_UPDATE:
$set = '';
foreach ($table_fields as $value) {
if ($first) {
$first = false;
} else {
$set .= ',';
}
$set .= "$value = ?";
}
$sql = "UPDATE $table SET $set";
if ($where) {
$sql .= " WHERE $where";
}
return $sql;
default:
return $this->raiseError(DB_ERROR_SYNTAX);
}
}
 
// }}}
// {{{ execute()
 
/**
* Executes a DB statement prepared with prepare()
*
* Example 1.
* <code>
* $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
* $data = array(
* "John's text",
* "'it''s good'",
* 'filename.txt'
* );
* $res =& $db->execute($sth, $data);
* </code>
*
* @param resource $stmt a DB statement resource returned from prepare()
* @param mixed $data 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 mixed a new DB_result object for successful SELECT queries
* or DB_OK for successul data manipulation queries.
* A DB_Error object on failure.
*
* {@internal ibase and oci8 have their own execute() methods.}}
*
* @see DB_common::prepare()
*/
function &execute($stmt, $data = array())
{
$realquery = $this->executeEmulateQuery($stmt, $data);
if (DB::isError($realquery)) {
return $realquery;
}
$result = $this->simpleQuery($realquery);
 
if ($result === DB_OK || DB::isError($result)) {
return $result;
} else {
$tmp =& new DB_result($this, $result);
return $tmp;
}
}
 
// }}}
// {{{ executeEmulateQuery()
 
/**
* Emulates executing prepared statements if the DBMS not support them
*
* @param resource $stmt a DB statement resource returned from execute()
* @param mixed $data 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 mixed a string containing the real query run when emulating
* prepare/execute. A DB_Error object on failure.
*
* @access protected
* @see DB_common::execute()
*/
function executeEmulateQuery($stmt, $data = array())
{
$stmt = (int)$stmt;
$data = (array)$data;
$this->last_parameters = $data;
 
if (count($this->prepare_types[$stmt]) != count($data)) {
$this->last_query = $this->prepared_queries[$stmt];
return $this->raiseError(DB_ERROR_MISMATCH);
}
 
$realquery = $this->prepare_tokens[$stmt][0];
 
$i = 0;
foreach ($data as $value) {
if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) {
$realquery .= $this->quoteSmart($value);
} elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) {
$fp = @fopen($value, 'rb');
if (!$fp) {
return $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
}
$realquery .= $this->quoteSmart(fread($fp, filesize($value)));
fclose($fp);
} else {
$realquery .= $value;
}
 
$realquery .= $this->prepare_tokens[$stmt][++$i];
}
 
return $realquery;
}
 
// }}}
// {{{ executeMultiple()
 
/**
* Performs several execute() calls on the same statement handle
*
* $data must be an array indexed numerically
* from 0, one execute call is done for every "row" in the array.
*
* If an error occurs during execute(), executeMultiple() does not
* execute the unfinished rows, but rather returns that error.
*
* @param resource $stmt query handle from prepare()
* @param array $data numeric array containing the
* data to insert into the query
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::prepare(), DB_common::execute()
*/
function executeMultiple($stmt, $data)
{
foreach ($data as $value) {
$res =& $this->execute($stmt, $value);
if (DB::isError($res)) {
return $res;
}
}
return DB_OK;
}
 
// }}}
// {{{ freePrepared()
 
/**
* Frees the internal resources associated with a prepared query
*
* @param resource $stmt the prepared statement's PHP resource
* @param bool $free_resource should the PHP resource be freed too?
* Use false if you need to get data
* from the result set later.
*
* @return bool TRUE on success, FALSE if $result is invalid
*
* @see DB_common::prepare()
*/
function freePrepared($stmt, $free_resource = true)
{
$stmt = (int)$stmt;
if (isset($this->prepare_tokens[$stmt])) {
unset($this->prepare_tokens[$stmt]);
unset($this->prepare_types[$stmt]);
unset($this->prepared_queries[$stmt]);
return true;
}
return false;
}
 
// }}}
// {{{ modifyQuery()
 
/**
* Changes a query string for various DBMS specific reasons
*
* It is defined here to ensure all drivers have this method available.
*
* @param string $query the query string to modify
*
* @return string the modified query string
*
* @access protected
* @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(),
* DB_sqlite::modifyQuery()
*/
function modifyQuery($query)
{
return $query;
}
 
// }}}
// {{{ modifyLimitQuery()
 
/**
* Adds LIMIT clauses to a query string according to current DBMS standards
*
* It is defined here to assure that all implementations
* have this method defined.
*
* @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;
}
 
// }}}
// {{{ query()
 
/**
* Sends a query to the database server
*
* The query string can be either a normal statement to be sent directly
* to the server OR if <var>$params</var> are passed the query can have
* placeholders and it will be passed through prepare() and execute().
*
* @param string $query the SQL query or the statement to prepare
* @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 mixed a new DB_result object for successful SELECT queries
* or DB_OK for successul data manipulation queries.
* A DB_Error object on failure.
*
* @see DB_result, DB_common::prepare(), DB_common::execute()
*/
function &query($query, $params = array())
{
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
if (DB::isError($sth)) {
return $sth;
}
$ret =& $this->execute($sth, $params);
$this->freePrepared($sth, false);
return $ret;
} else {
$this->last_parameters = array();
$result = $this->simpleQuery($query);
if ($result === DB_OK || DB::isError($result)) {
return $result;
} else {
$tmp =& new DB_result($this, $result);
return $tmp;
}
}
}
 
// }}}
// {{{ limitQuery()
 
/**
* Generates and executes a LIMIT query
*
* @param string $query the query
* @param intr $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 mixed a new DB_result object for successful SELECT queries
* or DB_OK for successul data manipulation queries.
* A DB_Error object on failure.
*/
function &limitQuery($query, $from, $count, $params = array())
{
$query = $this->modifyLimitQuery($query, $from, $count, $params);
if (DB::isError($query)){
return $query;
}
$result =& $this->query($query, $params);
if (is_a($result, 'DB_result')) {
$result->setOption('limit_from', $from);
$result->setOption('limit_count', $count);
}
return $result;
}
 
// }}}
// {{{ getOne()
 
/**
* Fetches the first column of the first row from a query result
*
* Takes care of doing the query and freeing the results when finished.
*
* @param string $query the SQL query
* @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 mixed the returned value of the query.
* A DB_Error object on failure.
*/
function &getOne($query, $params = array())
{
$params = (array)$params;
// modifyLimitQuery() would be nice here, but it causes BC issues
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
if (DB::isError($sth)) {
return $sth;
}
$res =& $this->execute($sth, $params);
$this->freePrepared($sth);
} else {
$res =& $this->query($query);
}
 
if (DB::isError($res)) {
return $res;
}
 
$err = $res->fetchInto($row, DB_FETCHMODE_ORDERED);
$res->free();
 
if ($err !== DB_OK) {
return $err;
}
 
return $row[0];
}
 
// }}}
// {{{ getRow()
 
/**
* Fetches the first row of data returned from a query result
*
* Takes care of doing the query and freeing the results when finished.
*
* @param string $query the SQL query
* @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.
* @param int $fetchmode the fetch mode to use
*
* @return array the first row of results as an array.
* A DB_Error object on failure.
*/
function &getRow($query, $params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT)
{
// compat check, the params and fetchmode parameters used to
// have the opposite order
if (!is_array($params)) {
if (is_array($fetchmode)) {
if ($params === null) {
$tmp = DB_FETCHMODE_DEFAULT;
} else {
$tmp = $params;
}
$params = $fetchmode;
$fetchmode = $tmp;
} elseif ($params !== null) {
$fetchmode = $params;
$params = array();
}
}
// modifyLimitQuery() would be nice here, but it causes BC issues
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
if (DB::isError($sth)) {
return $sth;
}
$res =& $this->execute($sth, $params);
$this->freePrepared($sth);
} else {
$res =& $this->query($query);
}
 
if (DB::isError($res)) {
return $res;
}
 
$err = $res->fetchInto($row, $fetchmode);
 
$res->free();
 
if ($err !== DB_OK) {
return $err;
}
 
return $row;
}
 
// }}}
// {{{ getCol()
 
/**
* Fetches a single column from a query result and returns it as an
* indexed array
*
* @param string $query the SQL query
* @param mixed $col which column to return (integer [column number,
* starting at 0] or string [column name])
* @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 array the results as an array. A DB_Error object on failure.
*
* @see DB_common::query()
*/
function &getCol($query, $col = 0, $params = array())
{
$params = (array)$params;
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
 
if (DB::isError($sth)) {
return $sth;
}
 
$res =& $this->execute($sth, $params);
$this->freePrepared($sth);
} else {
$res =& $this->query($query);
}
 
if (DB::isError($res)) {
return $res;
}
 
$fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
 
if (!is_array($row = $res->fetchRow($fetchmode))) {
$ret = array();
} else {
if (!array_key_exists($col, $row)) {
$ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD);
} else {
$ret = array($row[$col]);
while (is_array($row = $res->fetchRow($fetchmode))) {
$ret[] = $row[$col];
}
}
}
 
$res->free();
 
if (DB::isError($row)) {
$ret = $row;
}
 
return $ret;
}
 
// }}}
// {{{ getAssoc()
 
/**
* Fetches an entire query result and returns it as an
* associative array using the first column as the key
*
* If the result set contains more than two columns, the value
* will be an array of the values from column 2-n. If the result
* set contains only two columns, the returned value will be a
* scalar with the value of the second column (unless forced to an
* array with the $force_array parameter). A DB error code is
* returned on errors. If the result set contains fewer than two
* columns, a DB_ERROR_TRUNCATED error is returned.
*
* For example, if the table "mytable" contains:
*
* <pre>
* ID TEXT DATE
* --------------------------------
* 1 'one' 944679408
* 2 'two' 944679408
* 3 'three' 944679408
* </pre>
*
* Then the call getAssoc('SELECT id,text FROM mytable') returns:
* <pre>
* array(
* '1' => 'one',
* '2' => 'two',
* '3' => 'three',
* )
* </pre>
*
* ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
* <pre>
* array(
* '1' => array('one', '944679408'),
* '2' => array('two', '944679408'),
* '3' => array('three', '944679408')
* )
* </pre>
*
* If the more than one row occurs with the same value in the
* first column, the last row overwrites all previous ones by
* default. Use the $group parameter if you don't want to
* overwrite like this. Example:
*
* <pre>
* getAssoc('SELECT category,id,name FROM mytable', false, null,
* DB_FETCHMODE_ASSOC, true) returns:
*
* array(
* '1' => array(array('id' => '4', 'name' => 'number four'),
* array('id' => '6', 'name' => 'number six')
* ),
* '9' => array(array('id' => '4', 'name' => 'number four'),
* array('id' => '6', 'name' => 'number six')
* )
* )
* </pre>
*
* Keep in mind that database functions in PHP usually return string
* values for results regardless of the database's internal type.
*
* @param string $query the SQL query
* @param bool $force_array used only when the query returns
* exactly two columns. If true, the values
* of the returned array will be one-element
* arrays instead of scalars.
* @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.
* @param int $fetchmode the fetch mode to use
* @param bool $group if true, the values of the returned array
* is wrapped in another array. If the same
* key value (in the first column) repeats
* itself, the values will be appended to
* this array instead of overwriting the
* existing values.
*
* @return array the associative array containing the query results.
* A DB_Error object on failure.
*/
function &getAssoc($query, $force_array = false, $params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT, $group = false)
{
$params = (array)$params;
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
 
if (DB::isError($sth)) {
return $sth;
}
 
$res =& $this->execute($sth, $params);
$this->freePrepared($sth);
} else {
$res =& $this->query($query);
}
 
if (DB::isError($res)) {
return $res;
}
if ($fetchmode == DB_FETCHMODE_DEFAULT) {
$fetchmode = $this->fetchmode;
}
$cols = $res->numCols();
 
if ($cols < 2) {
$tmp =& $this->raiseError(DB_ERROR_TRUNCATED);
return $tmp;
}
 
$results = array();
 
if ($cols > 2 || $force_array) {
// return array values
// XXX this part can be optimized
if ($fetchmode == DB_FETCHMODE_ASSOC) {
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) {
reset($row);
$key = current($row);
unset($row[key($row)]);
if ($group) {
$results[$key][] = $row;
} else {
$results[$key] = $row;
}
}
} elseif ($fetchmode == DB_FETCHMODE_OBJECT) {
while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) {
$arr = get_object_vars($row);
$key = current($arr);
if ($group) {
$results[$key][] = $row;
} else {
$results[$key] = $row;
}
}
} else {
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
// we shift away the first element to get
// indices running from 0 again
$key = array_shift($row);
if ($group) {
$results[$key][] = $row;
} else {
$results[$key] = $row;
}
}
}
if (DB::isError($row)) {
$results = $row;
}
} else {
// return scalar values
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
if ($group) {
$results[$row[0]][] = $row[1];
} else {
$results[$row[0]] = $row[1];
}
}
if (DB::isError($row)) {
$results = $row;
}
}
 
$res->free();
 
return $results;
}
 
// }}}
// {{{ getAll()
 
/**
* Fetches all of the rows from a query result
*
* @param string $query the SQL query
* @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.
* @param int $fetchmode the fetch mode to use:
* + DB_FETCHMODE_ORDERED
* + DB_FETCHMODE_ASSOC
* + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED
* + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED
*
* @return array the nested array. A DB_Error object on failure.
*/
function &getAll($query, $params = array(),
$fetchmode = DB_FETCHMODE_DEFAULT)
{
// compat check, the params and fetchmode parameters used to
// have the opposite order
if (!is_array($params)) {
if (is_array($fetchmode)) {
if ($params === null) {
$tmp = DB_FETCHMODE_DEFAULT;
} else {
$tmp = $params;
}
$params = $fetchmode;
$fetchmode = $tmp;
} elseif ($params !== null) {
$fetchmode = $params;
$params = array();
}
}
 
if (sizeof($params) > 0) {
$sth = $this->prepare($query);
 
if (DB::isError($sth)) {
return $sth;
}
 
$res =& $this->execute($sth, $params);
$this->freePrepared($sth);
} else {
$res =& $this->query($query);
}
 
if ($res === DB_OK || DB::isError($res)) {
return $res;
}
 
$results = array();
while (DB_OK === $res->fetchInto($row, $fetchmode)) {
if ($fetchmode & DB_FETCHMODE_FLIPPED) {
foreach ($row as $key => $val) {
$results[$key][] = $val;
}
} else {
$results[] = $row;
}
}
 
$res->free();
 
if (DB::isError($row)) {
$tmp =& $this->raiseError($row);
return $tmp;
}
return $results;
}
 
// }}}
// {{{ 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)
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ commit()
 
/**
* Commits the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function commit()
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ rollback()
 
/**
* Reverts the current transaction
*
* @return int DB_OK on success. A DB_Error object on failure.
*/
function rollback()
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ numRows()
 
/**
* Determines the number of rows in a query result
*
* @param resource $result the query result idenifier produced by PHP
*
* @return int the number of rows. A DB_Error object on failure.
*/
function numRows($result)
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ 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()
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ getSequenceName()
 
/**
* Generates the name used inside the database for a sequence
*
* The createSequence() docblock contains notes about storing sequence
* names.
*
* @param string $sqn the sequence's public name
*
* @return string the sequence's name in the backend
*
* @access protected
* @see DB_common::createSequence(), DB_common::dropSequence(),
* DB_common::nextID(), DB_common::setOption()
*/
function getSequenceName($sqn)
{
return sprintf($this->getOption('seqname_format'),
preg_replace('/[^a-z0-9_.]/i', '_', $sqn));
}
 
// }}}
// {{{ 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::createSequence(), DB_common::dropSequence(),
* DB_common::getSequenceName()
*/
function nextId($seq_name, $ondemand = true)
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ createSequence()
 
/**
* Creates a new sequence
*
* The name of a given sequence is determined by passing the string
* provided in the <var>$seq_name</var> argument through PHP's sprintf()
* function using the value from the <var>seqname_format</var> option as
* the sprintf()'s format argument.
*
* <var>seqname_format</var> is set via setOption().
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_common::nextID()
*/
function createSequence($seq_name)
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ 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::createSequence(), DB_common::getSequenceName(),
* DB_common::nextID()
*/
function dropSequence($seq_name)
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ raiseError()
 
/**
* Communicates an error and invoke error callbacks, etc
*
* Basically a wrapper for PEAR::raiseError without the message string.
*
* @param mixed integer error code, or a PEAR error object (all
* other parameters are ignored if this parameter is
* an object
* @param int error mode, see PEAR_Error docs
* @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the
* error level (E_USER_NOTICE etc). If error mode is
* PEAR_ERROR_CALLBACK, this is the callback function,
* either as a function name, or as an array of an
* object and method name. For other error modes this
* parameter is ignored.
* @param string extra debug information. Defaults to the last
* query and native error code.
* @param mixed native error code, integer or string depending the
* backend
*
* @return object the PEAR_Error object
*
* @see PEAR_Error
*/
function &raiseError($code = DB_ERROR, $mode = null, $options = null,
$userinfo = null, $nativecode = null)
{
// The error is yet a DB error object
if (is_object($code)) {
// because we the static PEAR::raiseError, our global
// handler should be used if it is set
if ($mode === null && !empty($this->_default_error_mode)) {
$mode = $this->_default_error_mode;
$options = $this->_default_error_options;
}
$tmp = PEAR::raiseError($code, null, $mode, $options,
null, null, true);
return $tmp;
}
 
if ($userinfo === null) {
$userinfo = $this->last_query;
}
 
if ($nativecode) {
$userinfo .= ' [nativecode=' . trim($nativecode) . ']';
} else {
$userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']';
}
 
$tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo,
'DB_Error', true);
return $tmp;
}
 
// }}}
// {{{ errorNative()
 
/**
* Gets the DBMS' native error code produced by the last query
*
* @return mixed the DBMS' error code. A DB_Error object on failure.
*/
function errorNative()
{
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ errorCode()
 
/**
* Maps native error codes to DB's portable ones
*
* Uses the <var>$errorcode_map</var> property defined in each driver.
*
* @param string|int $nativecode the error code returned by the DBMS
*
* @return int the portable DB error code. Return DB_ERROR if the
* current driver doesn't have a mapping for the
* $nativecode submitted.
*/
function errorCode($nativecode)
{
if (isset($this->errorcode_map[$nativecode])) {
return $this->errorcode_map[$nativecode];
}
// Fall back to DB_ERROR if there was no mapping.
return DB_ERROR;
}
 
// }}}
// {{{ errorMessage()
 
/**
* Maps a DB error code to a textual message
*
* @param integer $dbcode the DB error code
*
* @return string the error message corresponding to the error code
* submitted. FALSE if the error code is unknown.
*
* @see DB::errorMessage()
*/
function errorMessage($dbcode)
{
return DB::errorMessage($this->errorcode_map[$dbcode]);
}
 
// }}}
// {{{ tableInfo()
 
/**
* Returns information about a table or a result set
*
* The format of the resulting array depends on which <var>$mode</var>
* you select. The sample output below is based on this query:
* <pre>
* SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
* FROM tblFoo
* JOIN tblBar ON tblFoo.fldId = tblBar.fldId
* </pre>
*
* <ul>
* <li>
*
* <kbd>null</kbd> (default)
* <pre>
* [0] => Array (
* [table] => tblFoo
* [name] => fldId
* [type] => int
* [len] => 11
* [flags] => primary_key not_null
* )
* [1] => Array (
* [table] => tblFoo
* [name] => fldPhone
* [type] => string
* [len] => 20
* [flags] =>
* )
* [2] => Array (
* [table] => tblBar
* [name] => fldId
* [type] => int
* [len] => 11
* [flags] => primary_key not_null
* )
* </pre>
*
* </li><li>
*
* <kbd>DB_TABLEINFO_ORDER</kbd>
*
* <p>In addition to the information found in the default output,
* a notation of the number of columns is provided by the
* <samp>num_fields</samp> element while the <samp>order</samp>
* element provides an array with the column names as the keys and
* their location index number (corresponding to the keys in the
* the default output) as the values.</p>
*
* <p>If a result set has identical field names, the last one is
* used.</p>
*
* <pre>
* [num_fields] => 3
* [order] => Array (
* [fldId] => 2
* [fldTrans] => 1
* )
* </pre>
*
* </li><li>
*
* <kbd>DB_TABLEINFO_ORDERTABLE</kbd>
*
* <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more
* dimensions to the array in which the table names are keys and
* the field names are sub-keys. This is helpful for queries that
* join tables which have identical field names.</p>
*
* <pre>
* [num_fields] => 3
* [ordertable] => Array (
* [tblFoo] => Array (
* [fldId] => 0
* [fldPhone] => 1
* )
* [tblBar] => Array (
* [fldId] => 2
* )
* )
* </pre>
*
* </li>
* </ul>
*
* The <samp>flags</samp> element contains a space separated list
* of extra information about the field. This data is inconsistent
* between DBMS's due to the way each DBMS works.
* + <samp>primary_key</samp>
* + <samp>unique_key</samp>
* + <samp>multiple_key</samp>
* + <samp>not_null</samp>
*
* Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
* elements if <var>$result</var> is a table name. The following DBMS's
* provide full information from queries:
* + fbsql
* + mysql
*
* If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp>
* turned on, the names of tables and fields will be lowercased.
*
* @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 either unused or one of the tableInfo modes:
* <kbd>DB_TABLEINFO_ORDERTABLE</kbd>,
* <kbd>DB_TABLEINFO_ORDER</kbd> or
* <kbd>DB_TABLEINFO_FULL</kbd> (which does both).
* These are bitwise, so the first two can be
* combined using <kbd>|</kbd>.
*
* @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 the DB_<driver> class has a tableInfo() method, that one
* overrides this one. But, if the driver doesn't have one,
* this method runs and tells users about that fact.
*/
return $this->raiseError(DB_ERROR_NOT_CAPABLE);
}
 
// }}}
// {{{ getTables()
 
/**
* Lists the tables in the current database
*
* @return array the list of tables. A DB_Error object on failure.
*
* @deprecated Method deprecated some time before Release 1.2
*/
function getTables()
{
return $this->getListOf('tables');
}
 
// }}}
// {{{ getListOf()
 
/**
* Lists internal database information
*
* @param string $type type of information being sought.
* Common items being sought are:
* tables, databases, users, views, functions
* Each DBMS's has its own capabilities.
*
* @return array an array listing the items sought.
* A DB DB_Error object on failure.
*/
function getListOf($type)
{
$sql = $this->getSpecialQuery($type);
if ($sql === null) {
$this->last_query = '';
return $this->raiseError(DB_ERROR_UNSUPPORTED);
} elseif (is_int($sql) || DB::isError($sql)) {
// Previous error
return $this->raiseError($sql);
} elseif (is_array($sql)) {
// Already the result
return $sql;
}
// Launch this query
return $this->getCol($sql);
}
 
// }}}
// {{{ 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)
{
return $this->raiseError(DB_ERROR_UNSUPPORTED);
}
 
// }}}
// {{{ _rtrimArrayValues()
 
/**
* Right-trims all strings in an array
*
* @param array $array the array to be trimmed (passed by reference)
*
* @return void
*
* @access protected
*/
function _rtrimArrayValues(&$array)
{
foreach ($array as $key => $value) {
if (is_string($value)) {
$array[$key] = rtrim($value);
}
}
}
 
// }}}
// {{{ _convertNullArrayValuesToEmpty()
 
/**
* Converts all null values in an array to empty strings
*
* @param array $array the array to be de-nullified (passed by reference)
*
* @return void
*
* @access protected
*/
function _convertNullArrayValuesToEmpty(&$array)
{
foreach ($array as $key => $value) {
if (is_null($value)) {
$array[$key] = '';
}
}
}
 
// }}}
}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/HTTP.php
New file
0,0 → 1,353
<?php
// +----------------------------------------------------------------------+
// | PEAR :: HTTP |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is available at http://www.php.net/license/3_0.txt |
// | If you did not receive a copy of the PHP license and are unable |
// | to obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Stig Bakken <ssb@fast.no> |
// | Sterling Hughes <sterling@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | Richard Heyes <richard@php.net> |
// | Philippe Jausions <Philippe.Jausions@11abacus.com> |
// | Michael Wallner <mike@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: HTTP.php,v 1.1 2005-03-30 08:50:19 jpm Exp $
 
/**
* HTTP
*
* HTTP utility functions
*
* @package HTTP
* @category HTTP
* @license PHP License
* @access public
* @version $Revision: 1.1 $
*/
class HTTP
{
/**
* Date
*
* Format a RFC compliant GMT date HTTP header. This function honors the
* "y2k_compliance" php.ini directive and formats the GMT date corresponding
* to either RFC850 or RFC822.
*
* @static
* @access public
* @return mixed GMT date string, or false for an invalid $time parameter
* @param mixed $time unix timestamp or date (default = current time)
*/
function Date($time = null)
{
if (!isset($time)) {
$time = time();
} elseif (!is_numeric($time) && (-1 === $time = strtotime($time))) {
return false;
}
// RFC822 or RFC850
$format = ini_get('y2k_compliance') ? 'D, d M Y' : 'l, d-M-y';
return gmdate($format .' H:i:s \G\M\T', $time);
}
 
/**
* Negotiate Language
*
* Negotiate language with the user's browser through the Accept-Language
* HTTP header or the user's host address. Language codes are generally in
* the form "ll" for a language spoken in only one country, or "ll-CC" for a
* language spoken in a particular country. For example, U.S. English is
* "en-US", while British English is "en-UK". Portugese as spoken in
* Portugal is "pt-PT", while Brazilian Portugese is "pt-BR".
*
* Quality factors in the Accept-Language: header are supported, e.g.:
* Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8
*
* <code>
* require_once 'HTTP.php';
* $langs = array(
* 'en' => 'locales/en',
* 'en-US'=> 'locales/en',
* 'en-UK'=> 'locales/en',
* 'de' => 'locales/de',
* 'de-DE'=> 'locales/de',
* 'de-AT'=> 'locales/de',
* );
* $neg = HTTP::negotiateLanguage($langs);
* $dir = $langs[$neg];
* </code>
*
* @static
* @access public
* @return string The negotiated language result or the supplied default.
* @param array $supported An associative array of supported languages,
* whose values must evaluate to true.
* @param string $default The default language to use if none is found.
*/
function negotiateLanguage($supported, $default = 'en-US')
{
$supp = array();
foreach ($supported as $lang => $isSupported) {
if ($isSupported) {
$supp[strToLower($lang)] = $lang;
}
}
if (!count($supp)) {
return $default;
}
 
$matches = array();
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
$lang = array_map('trim', explode(';', $lang));
if (isset($lang[1])) {
$l = strtolower($lang[0]);
$q = (float) str_replace('q=', '', $lang[1]);
} else {
$l = strtolower($lang[0]);
$q = null;
}
if (isset($supp[$l])) {
$matches[$l] = isset($q) ? $q : 1000 - count($matches);
}
}
}
 
if (count($matches)) {
asort($matches, SORT_NUMERIC);
return $supp[array_pop(array_keys($matches))];
}
if (isset($_SERVER['REMOTE_HOST'])) {
$lang = strtolower(array_pop(explode('.', $_SERVER['REMOTE_HOST'])));
if (isset($supp[$lang])) {
return $supp[$lang];
}
}
 
return $default;
}
 
/**
* Head
*
* Sends a "HEAD" HTTP command to a server and returns the headers
* as an associative array. Example output could be:
* <code>
* Array
* (
* [response_code] => 200 // The HTTP response code
* [response] => HTTP/1.1 200 OK // The full HTTP response string
* [Date] => Fri, 11 Jan 2002 01:41:44 GMT
* [Server] => Apache/1.3.20 (Unix) PHP/4.1.1
* [X-Powered-By] => PHP/4.1.1
* [Connection] => close
* [Content-Type] => text/html
* )
* </code>
*
* @see HTTP_Client::head()
* @see HTTP_Request
*
* @static
* @access public
* @return mixed Returns associative array of response headers on success
* or PEAR error on failure.
* @param string $url A valid URL, e.g.: http://pear.php.net/credits.php
* @param integer $timeout Timeout in seconds (default = 10)
*/
function head($url, $timeout = 10)
{
$p = parse_url($url);
if (!isset($p['scheme'])) {
$p = parse_url(HTTP::absoluteURI($url));
} elseif ($p['scheme'] != 'http') {
return HTTP::raiseError('Unsupported protocol: '. $p['scheme']);
}
 
$port = isset($p['port']) ? $p['port'] : 80;
 
if (!$fp = @fsockopen($p['host'], $port, $eno, $estr, $timeout)) {
return HTTP::raiseError("Connection error: $estr ($eno)");
}
 
$path = !empty($p['path']) ? $p['path'] : '/';
$path .= !empty($p['query']) ? '?' . $p['query'] : '';
 
fputs($fp, "HEAD $path HTTP/1.0\r\n");
fputs($fp, 'Host: ' . $p['host'] . ':' . $port . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
 
$response = rtrim(fgets($fp, 4096));
if (preg_match("|^HTTP/[^\s]*\s(.*?)\s|", $response, $status)) {
$headers['response_code'] = $status[1];
}
$headers['response'] = $response;
 
while ($line = fgets($fp, 4096)) {
if (!trim($line)) {
break;
}
if (($pos = strpos($line, ':')) !== false) {
$header = substr($line, 0, $pos);
$value = trim(substr($line, $pos + 1));
$headers[$header] = $value;
}
}
fclose($fp);
return $headers;
}
 
/**
* Redirect
*
* This function redirects the client. This is done by issuing
* a "Location" header and exiting if wanted. If you set $rfc2616 to true
* HTTP will output a hypertext note with the location of the redirect.
*
* @static
* @access public
* @return mixed Returns true on succes (or exits) or false if headers
* have already been sent.
* @param string $url URL where the redirect should go to.
* @param bool $exit Whether to exit immediately after redirection.
* @param bool $rfc2616 Wheter to output a hypertext note where we're
* redirecting to (Redirecting to <a href="...">...</a>.)
*/
function redirect($url, $exit = true, $rfc2616 = false)
{
if (headers_sent()) {
return false;
}
$url = HTTP::absoluteURI($url);
header('Location: '. $url);
if ( $rfc2616 && isset($_SERVER['REQUEST_METHOD']) &&
$_SERVER['REQUEST_METHOD'] != 'HEAD') {
printf('Redirecting to: <a href="%s">%s</a>.', $url, $url);
}
if ($exit) {
exit;
}
return true;
}
 
/**
* Absolute URI
*
* This function returns the absolute URI for the partial URL passed.
* The current scheme (HTTP/HTTPS), host server, port, current script
* location are used if necessary to resolve any relative URLs.
*
* Offsets potentially created by PATH_INFO are taken care of to resolve
* relative URLs to the current script.
*
* You can choose a new protocol while resolving the URI. This is
* particularly useful when redirecting a web browser using relative URIs
* and to switch from HTTP to HTTPS, or vice-versa, at the same time.
*
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
* @static
* @access public
* @return string The absolute URI.
* @param string $url Absolute or relative URI the redirect should go to.
* @param string $protocol Protocol to use when redirecting URIs.
* @param integer $port A new port number.
*/
function absoluteURI($url = null, $protocol = null, $port = null)
{
// filter CR/LF
$url = str_replace(array("\r", "\n"), ' ', $url);
// Mess around with already absolute URIs
if (preg_match('!^([a-z0-9]+)://!i', $url)) {
if (empty($protocol) && empty($port)) {
return $url;
}
if (!empty($protocol)) {
$url = $protocol .':'. array_pop(explode(':', $url, 2));
}
if (!empty($port)) {
$url = preg_replace('!^(([a-z0-9]+)://[^/:]+)(:[\d]+)?!i',
'\1:'. $port, $url);
}
return $url;
}
$host = 'localhost';
if (!empty($_SERVER['HTTP_HOST'])) {
list($host) = explode(':', $_SERVER['HTTP_HOST']);
} elseif (!empty($_SERVER['SERVER_NAME'])) {
list($host) = explode(':', $_SERVER['SERVER_NAME']);
}
 
if (empty($protocol)) {
if (isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'], 'on')) {
$protocol = 'https';
} else {
$protocol = 'http';
}
if (!isset($port) || $port != intval($port)) {
$port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
}
}
if ($protocol == 'http' && $port == 80) {
unset($port);
}
if ($protocol == 'https' && $port == 443) {
unset($port);
}
 
$server = $protocol .'://'. $host . (isset($port) ? ':'. $port : '');
if (!strlen($url)) {
$url = isset($_SERVER['REQUEST_URI']) ?
$_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF'];
}
if ($url{0} == '/') {
return $server . $url;
}
// Check for PATH_INFO
if (isset($_SERVER['PATH_INFO']) && $_SERVER['PHP_SELF'] != $_SERVER['PATH_INFO']) {
$path = dirname(substr($_SERVER['PHP_SELF'], 0, -strlen($_SERVER['PATH_INFO'])));
} else {
$path = dirname($_SERVER['PHP_SELF']);
}
if (substr($path = strtr($path, '\\', '/'), -1) != '/') {
$path .= '/';
}
return $server . $path . $url;
}
 
/**
* Raise Error
*
* Lazy raising of PEAR_Errors.
*
* @static
* @access protected
* @return object PEAR_Error
* @param mixed $error
* @param int $code
*/
function raiseError($error = null, $code = null)
{
require_once 'PEAR.php';
return PEAR::raiseError($error, $code);
}
}
?>
/branches/v1.0-menes/api/pear/Net/FTP/Observer.php
New file
0,0 → 1,101
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Net_FTP observer.
*
* This class implements the Observer part of a Subject-Observer
* design pattern. It listens to the events sent by a Net_FTP instance.
* This module had many influences from the Log_observer code.
*
* 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 Networking
* @package FTP
* @author Tobias Schlitt <toby@php.net>
* @author Laurent Laville <pear@laurent-laville.org>
* @author Chuck Hagenbuch <chuck@horde.org>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Observer.php,v 1.1 2005-03-30 08:50:33 jpm Exp $
* @link http://pear.php.net/package/Net_FTP
* @since File available since Release 0.0.1
*/
 
/**
* This class implements the Observer part of a Subject-Observer
* design pattern. It listens to the events sent by a Net_FTP instance.
* This module had many influences from the Log_observer code.
*
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @category Networking
* @package FTP
* @author Laurent Laville <pear@laurent-laville.org>
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Tobias Schlitt <toby@php.net>
* @copyright 1997-2005 The PHP Group
* @version Release: 1.3.0
* @link http://pear.php.net/package/Net_FTP
* @since 1.3.0.0
* @access public
*
* @example observer_upload.php An example of Net_FTP_Observer implementation.
*/
class Net_FTP_Observer
{
/**
* Instance-specific unique identification number.
*
* @var integer
* @since 1.3.0
* @access private
*/
var $_id;
 
/**
* Creates a new basic Net_FTP_Observer instance.
*
* @since 1.3.0
* @access public
*/
function Net_FTP_Observer()
{
$this->_id = md5(microtime());
}
 
/**
* Returns the listener's identifier
*
* @return string
* @since 1.3.0
* @access public
*/
function getId()
{
return $this->_id;
}
 
/**
* This is a stub method to make sure that Net_FTP_Observer classes do
* something when they are notified of a message. The default behavior
* is to just do nothing.
* You should override this method.
*
* @param mixed $event A hash describing the net event.
*
* @since 1.3.0
* @access public
*/
function notify($event)
{
return;
}
}
?>
/branches/v1.0-menes/api/pear/Net/SMTP.php
New file
0,0 → 1,970
<?php
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Chuck Hagenbuch <chuck@horde.org> |
// | Jon Parise <jon@php.net> |
// | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> |
// +----------------------------------------------------------------------+
 
require_once 'PEAR.php';
require_once 'Net/Socket.php';
 
/**
* Provides an implementation of the SMTP protocol using PEAR's
* Net_Socket:: class.
*
* @package Net_SMTP
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@php.net>
* @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
*
* @example basic.php A basic implementation of the Net_SMTP package.
*/
class Net_SMTP
{
/**
* The server to connect to.
* @var string
* @access public
*/
var $host = 'localhost';
 
/**
* The port to connect to.
* @var int
* @access public
*/
var $port = 25;
 
/**
* The value to give when sending EHLO or HELO.
* @var string
* @access public
*/
var $localhost = 'localhost';
 
/**
* List of supported authentication methods, in preferential order.
* @var array
* @access public
*/
var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN');
 
/**
* Should debugging output be enabled?
* @var boolean
* @access private
*/
var $_debug = false;
 
/**
* The socket resource being used to connect to the SMTP server.
* @var resource
* @access private
*/
var $_socket = null;
 
/**
* The most recent server response code.
* @var int
* @access private
*/
var $_code = -1;
 
/**
* The most recent server response arguments.
* @var array
* @access private
*/
var $_arguments = array();
 
/**
* Stores detected features of the SMTP server.
* @var array
* @access private
*/
var $_esmtp = array();
 
/**
* Instantiates a new Net_SMTP object, overriding any defaults
* with parameters that are passed in.
*
* @param string The server to connect to.
* @param int The port to connect to.
* @param string The value to give when sending EHLO or HELO.
*
* @access public
* @since 1.0
*/
function Net_SMTP($host = null, $port = null, $localhost = null)
{
if (isset($host)) $this->host = $host;
if (isset($port)) $this->port = $port;
if (isset($localhost)) $this->localhost = $localhost;
 
$this->_socket = new Net_Socket();
 
/*
* Include the Auth_SASL package. If the package is not available,
* we disable the authentication methods that depend upon it.
*/
if ((@include_once 'Auth/SASL.php') === false) {
$pos = array_search('DIGEST-MD5', $this->auth_methods);
unset($this->auth_methods[$pos]);
$pos = array_search('CRAM-MD5', $this->auth_methods);
unset($this->auth_methods[$pos]);
}
}
 
/**
* Set the value of the debugging flag.
*
* @param boolean $debug New value for the debugging flag.
*
* @access public
* @since 1.1.0
*/
function setDebug($debug)
{
$this->_debug = $debug;
}
 
/**
* Send the given string of data to the server.
*
* @param string $data The string of data to send.
*
* @return mixed True on success or a PEAR_Error object on failure.
*
* @access private
* @since 1.1.0
*/
function _send($data)
{
if ($this->_debug) {
echo "DEBUG: Send: $data\n";
}
 
if (PEAR::isError($error = $this->_socket->write($data))) {
return new PEAR_Error('Failed to write to socket: ' .
$error->getMessage());
}
 
return true;
}
 
/**
* Send a command to the server with an optional string of arguments.
* A carriage return / linefeed (CRLF) sequence will be appended to each
* command string before it is sent to the SMTP server.
*
* @param string $command The SMTP command to send to the server.
* @param string $args A string of optional arguments to append
* to the command.
*
* @return mixed The result of the _send() call.
*
* @access private
* @since 1.1.0
*/
function _put($command, $args = '')
{
if (!empty($args)) {
return $this->_send($command . ' ' . $args . "\r\n");
}
 
return $this->_send($command . "\r\n");
}
 
/**
* Read a reply from the SMTP server. The reply consists of a response
* code and a response message.
*
* @param mixed $valid The set of valid response codes. These
* may be specified as an array of integer
* values or as a single integer value.
*
* @return mixed True if the server returned a valid response code or
* a PEAR_Error object is an error condition is reached.
*
* @access private
* @since 1.1.0
*
* @see getResponse
*/
function _parseResponse($valid)
{
$this->_code = -1;
$this->_arguments = array();
 
while ($line = $this->_socket->readLine()) {
if ($this->_debug) {
echo "DEBUG: Recv: $line\n";
}
 
/* If we receive an empty line, the connection has been closed. */
if (empty($line)) {
$this->disconnect();
return new PEAR_Error("Connection was unexpectedly closed");
}
 
/* Read the code and store the rest in the arguments array. */
$code = substr($line, 0, 3);
$this->_arguments[] = trim(substr($line, 4));
 
/* Check the syntax of the response code. */
if (is_numeric($code)) {
$this->_code = (int)$code;
} else {
$this->_code = -1;
break;
}
 
/* If this is not a multiline response, we're done. */
if (substr($line, 3, 1) != '-') {
break;
}
}
 
/* Compare the server's response code with the valid code. */
if (is_int($valid) && ($this->_code === $valid)) {
return true;
}
 
/* If we were given an array of valid response codes, check each one. */
if (is_array($valid)) {
foreach ($valid as $valid_code) {
if ($this->_code === $valid_code) {
return true;
}
}
}
 
return new PEAR_Error("Invalid response code received from server");
}
 
/**
* Return a 2-tuple containing the last response from the SMTP server.
*
* @return array A two-element array: the first element contains the
* response code as an integer and the second element
* contains the response's arguments as a string.
*
* @access public
* @since 1.1.0
*/
function getResponse()
{
return array($this->_code, join("\n", $this->_arguments));
}
 
/**
* Attempt to connect to the SMTP server.
*
* @param int $timeout The timeout value (in seconds) for the
* socket connection.
* @param bool $persistent Should a persistent socket connection
* be used?
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function connect($timeout = null, $persistent = false)
{
$result = $this->_socket->connect($this->host, $this->port,
$persistent, $timeout);
if (PEAR::isError($result)) {
return new PEAR_Error('Failed to connect socket: ' .
$result->getMessage());
}
 
if (PEAR::isError($error = $this->_parseResponse(220))) {
return $error;
}
if (PEAR::isError($error = $this->_negotiate())) {
return $error;
}
 
return true;
}
 
/**
* Attempt to disconnect from the SMTP server.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function disconnect()
{
if (PEAR::isError($error = $this->_put('QUIT'))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(221))) {
return $error;
}
if (PEAR::isError($error = $this->_socket->disconnect())) {
return new PEAR_Error('Failed to disconnect socket: ' .
$error->getMessage());
}
 
return true;
}
 
/**
* Attempt to send the EHLO command and obtain a list of ESMTP
* extensions available, and failing that just send HELO.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
*
* @access private
* @since 1.1.0
*/
function _negotiate()
{
if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) {
return $error;
}
 
if (PEAR::isError($this->_parseResponse(250))) {
/* If we receive a 503 response, we're already authenticated. */
if ($this->_code === 503) {
return true;
}
 
/* If the EHLO failed, try the simpler HELO command. */
if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) {
return $error;
}
if (PEAR::isError($this->_parseResponse(250))) {
return new PEAR_Error('HELO was not accepted: ', $this->_code);
}
 
return true;
}
 
foreach ($this->_arguments as $argument) {
$verb = strtok($argument, ' ');
$arguments = substr($argument, strlen($verb) + 1,
strlen($argument) - strlen($verb) - 1);
$this->_esmtp[$verb] = $arguments;
}
 
return true;
}
 
/**
* Returns the name of the best authentication method that the server
* has advertised.
*
* @return mixed Returns a string containing the name of the best
* supported authentication method or a PEAR_Error object
* if a failure condition is encountered.
* @access private
* @since 1.1.0
*/
function _getBestAuthMethod()
{
$available_methods = explode(' ', $this->_esmtp['AUTH']);
 
foreach ($this->auth_methods as $method) {
if (in_array($method, $available_methods)) {
return $method;
}
}
 
return new PEAR_Error('No supported authentication methods');
}
 
/**
* Attempt to do SMTP authentication.
*
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @param string The requested authentication method. If none is
* specified, the best supported method will be used.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function auth($uid, $pwd , $method = '')
{
if (empty($this->_esmtp['AUTH'])) {
return new PEAR_Error('SMTP server does no support authentication');
}
 
/*
* If no method has been specified, get the name of the best supported
* method advertised by the SMTP server.
*/
if (empty($method)) {
if (PEAR::isError($method = $this->_getBestAuthMethod())) {
/* Return the PEAR_Error object from _getBestAuthMethod(). */
return $method;
}
} else {
$method = strtoupper($method);
if (!in_array($method, $this->auth_methods)) {
return new PEAR_Error("$method is not a supported authentication method");
}
}
 
switch ($method) {
case 'DIGEST-MD5':
$result = $this->_authDigest_MD5($uid, $pwd);
break;
case 'CRAM-MD5':
$result = $this->_authCRAM_MD5($uid, $pwd);
break;
case 'LOGIN':
$result = $this->_authLogin($uid, $pwd);
break;
case 'PLAIN':
$result = $this->_authPlain($uid, $pwd);
break;
default:
$result = new PEAR_Error("$method is not a supported authentication method");
break;
}
 
/* If an error was encountered, return the PEAR_Error object. */
if (PEAR::isError($result)) {
return $result;
}
 
/* RFC-2554 requires us to re-negotiate ESMTP after an AUTH. */
if (PEAR::isError($error = $this->_negotiate())) {
return $error;
}
 
return true;
}
 
/**
* Authenticates the user using the DIGEST-MD5 method.
*
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access private
* @since 1.1.0
*/
function _authDigest_MD5($uid, $pwd)
{
if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
/* 503: Error: already authenticated */
if ($this->_code === 503) {
return true;
}
return $error;
}
 
$challenge = base64_decode($this->_arguments[0]);
$digest = &Auth_SASL::factory('digestmd5');
$auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
$this->host, "smtp"));
 
if (PEAR::isError($error = $this->_put($auth_str))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
return $error;
}
 
/*
* We don't use the protocol's third step because SMTP doesn't allow
* subsequent authentication, so we just silently ignore it.
*/
if (PEAR::isError($error = $this->_put(' '))) {
return $error;
}
/* 235: Authentication successful */
if (PEAR::isError($error = $this->_parseResponse(235))) {
return $error;
}
}
 
/**
* Authenticates the user using the CRAM-MD5 method.
*
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access private
* @since 1.1.0
*/
function _authCRAM_MD5($uid, $pwd)
{
if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
/* 503: Error: already authenticated */
if ($this->_code === 503) {
return true;
}
return $error;
}
 
$challenge = base64_decode($this->_arguments[0]);
$cram = &Auth_SASL::factory('crammd5');
$auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
 
if (PEAR::isError($error = $this->_put($auth_str))) {
return $error;
}
 
/* 235: Authentication successful */
if (PEAR::isError($error = $this->_parseResponse(235))) {
return $error;
}
}
 
/**
* Authenticates the user using the LOGIN method.
*
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access private
* @since 1.1.0
*/
function _authLogin($uid, $pwd)
{
if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
/* 503: Error: already authenticated */
if ($this->_code === 503) {
return true;
}
return $error;
}
 
if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
return $error;
}
 
if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
return $error;
}
 
/* 235: Authentication successful */
if (PEAR::isError($error = $this->_parseResponse(235))) {
return $error;
}
 
return true;
}
 
/**
* Authenticates the user using the PLAIN method.
*
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access private
* @since 1.1.0
*/
function _authPlain($uid, $pwd)
{
if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->_parseResponse(334))) {
/* 503: Error: already authenticated */
if ($this->_code === 503) {
return true;
}
return $error;
}
 
$auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
 
if (PEAR::isError($error = $this->_put($auth_str))) {
return $error;
}
 
/* 235: Authentication successful */
if (PEAR::isError($error = $this->_parseResponse(235))) {
return $error;
}
 
return true;
}
 
/**
* Send the HELO command.
*
* @param string The domain name to say we are.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function helo($domain)
{
if (PEAR::isError($error = $this->_put('HELO', $domain))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Send the MAIL FROM: command.
*
* @param string The sender (reverse path) to set.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function mailFrom($sender)
{
if (PEAR::isError($error = $this->_put('MAIL', "FROM:<$sender>"))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Send the RCPT TO: command.
*
* @param string The recipient (forward path) to add.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function rcptTo($recipient)
{
if (PEAR::isError($error = $this->_put('RCPT', "TO:<$recipient>"))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(array(250, 251)))) {
return $error;
}
 
return true;
}
 
/**
* Quote the data so that it meets SMTP standards.
*
* This is provided as a separate public function to facilitate easier
* overloading for the cases where it is desirable to customize the
* quoting behavior.
*
* @param string The message text to quote. The string must be passed
* by reference, and the text will be modified in place.
*
* @access public
* @since 1.2
*/
function quotedata(&$data)
{
/*
* Change Unix (\n) and Mac (\r) linefeeds into Internet-standard CRLF
* (\r\n) linefeeds.
*/
$data = preg_replace("/([^\r]{1})\n/", "\\1\r\n", $data);
$data = preg_replace("/\n\n/", "\n\r\n", $data);
 
/*
* Because a single leading period (.) signifies an end to the data,
* legitimate leading periods need to be "doubled" (e.g. '..').
*/
$data = preg_replace("/\n\./", "\n..", $data);
}
 
/**
* Send the DATA command.
*
* @param string The message body to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function data($data)
{
/*
* RFC 1870, section 3, subsection 3 states "a value of zero indicates
* that no fixed maximum message size is in force". Furthermore, it
* says that if "the parameter is omitted no information is conveyed
* about the server's fixed maximum message size".
*/
if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) {
if (strlen($data) >= $this->_esmtp['SIZE']) {
$this->disconnect();
return new PEAR_Error('Message size excedes the server limit');
}
}
 
/* Quote the data based on the SMTP standards. */
$this->quotedata($data);
 
if (PEAR::isError($error = $this->_put('DATA'))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(354))) {
return $error;
}
 
if (PEAR::isError($this->_send($data . "\r\n.\r\n"))) {
return new PEAR_Error('write to socket failed');
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Send the SEND FROM: command.
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.2.6
*/
function sendFrom($path)
{
if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Backwards-compatibility wrapper for sendFrom().
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
*
* @access public
* @since 1.0
* @deprecated 1.2.6
*/
function send_from($path)
{
return sendFrom($path);
}
 
/**
* Send the SOML FROM: command.
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.2.6
*/
function somlFrom($path)
{
if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Backwards-compatibility wrapper for somlFrom().
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
*
* @access public
* @since 1.0
* @deprecated 1.2.6
*/
function soml_from($path)
{
return somlFrom($path);
}
 
/**
* Send the SAML FROM: command.
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.2.6
*/
function samlFrom($path)
{
if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Backwards-compatibility wrapper for samlFrom().
*
* @param string The reverse path to send.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
*
* @access public
* @since 1.0
* @deprecated 1.2.6
*/
function saml_from($path)
{
return samlFrom($path);
}
 
/**
* Send the RSET command.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function rset()
{
if (PEAR::isError($error = $this->_put('RSET'))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Send the VRFY command.
*
* @param string The string to verify
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function vrfy($string)
{
/* Note: 251 is also a valid response code */
if (PEAR::isError($error = $this->_put('VRFY', $string))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Send the NOOP command.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @access public
* @since 1.0
*/
function noop()
{
if (PEAR::isError($error = $this->_put('NOOP'))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
 
return true;
}
 
/**
* Backwards-compatibility method. identifySender()'s functionality is
* now handled internally.
*
* @return boolean This method always return true.
*
* @access public
* @since 1.0
*/
function identifySender()
{
return true;
}
}
 
?>
/branches/v1.0-menes/api/pear/Net/Socket.php
New 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.1 2005-03-30 08:50:33 jpm 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;
}
 
}
/branches/v1.0-menes/api/pear/Net/FTP.php
New file
0,0 → 1,2148
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Net_FTP main file.
*
* This file must be included to use the Net_FTP package.
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Networking
* @package FTP
* @author Tobias Schlitt <toby@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: FTP.php,v 1.2 2006-10-05 08:55:35 florian Exp $
* @link http://pear.php.net/package/Net_FTP
* @since File available since Release 0.0.1
*/
 
require_once 'PEAR.php';
 
/**
* Option to let the ls() method return only files.
*
* @since 1.3
* @name NET_FTP_FILES_ONLY
* @see Net_FTP::ls()
*/
define('NET_FTP_FILES_ONLY', 0, true);
 
/**
* Option to let the ls() method return only directories.
*
* @since 1.3
* @name NET_FTP_DIRS_ONLY
* @see Net_FTP::ls()
*/
define('NET_FTP_DIRS_ONLY', 1, true);
 
/**
* Option to let the ls() method return directories and files (default).
*
* @since 1.3
* @name NET_FTP_DIRS_FILES
* @see Net_FTP::ls()
*/
define('NET_FTP_DIRS_FILES', 2, true);
 
/**
* Option to let the ls() method return the raw directory listing from ftp_rawlist().
*
* @since 1.3
* @name NET_FTP_RAWLIST
* @see Net_FTP::ls()
*/
define('NET_FTP_RAWLIST', 3, true);
 
 
/**
* Error code to indicate a failed connection
* This error code indicates, that the connection you tryed to set up
* could not be established. Check your connection settings (host & port)!
*
* @since 1.3
* @name NET_FTP_ERR_CONNECT_FAILED
* @see Net_FTP::connect()
*/
define('NET_FTP_ERR_CONNECT_FAILED', -1);
 
/**
* Error code to indicate a failed login
* This error code indicates, that the login to the FTP server failed. Check
* your user data (username & password).
*
* @since 1.3
* @name NET_FTP_ERR_LOGIN_FAILED
* @see Net_FTP::login()
*/
define('NET_FTP_ERR_LOGIN_FAILED', -2);
 
/**
* Error code to indicate a failed directory change
* The cd() method failed. Ensure that the directory you wanted to access exists.
*
* @since 1.3
* @name NET_FTP_ERR_DIRCHANGE_FAILED
* @see Net_FTP::cd()
*/
define('NET_FTP_ERR_DIRCHANGE_FAILED', 2); // Compatibillity reasons!
 
/**
* Error code to indicate that Net_FTP could not determine the current path
* The cwd() method failed and could not determine the path you currently reside
* in on the FTP server.
*
* @since 1.3
* @name NET_FTP_ERR_DETERMINEPATH_FAILED
* @see Net_FTP::pwd()
*/
define('NET_FTP_ERR_DETERMINEPATH_FAILED', 4); // Compatibillity reasons!
 
/**
* Error code to indicate that the creation of a directory failed
* The directory you tryed to create could not be created. Check the
* access rights on the parent directory!
*
* @since 1.3
* @name NET_FTP_ERR_CREATEDIR_FAILED
* @see Net_FTP::mkdir()
*/
define('NET_FTP_ERR_CREATEDIR_FAILED', -4);
 
/**
* Error code to indicate that the EXEC execution failed.
* The execution of a command using EXEC failed. Ensure, that your
* FTP server supports the EXEC command.
*
* @since 1.3
* @name NET_FTP_ERR_EXEC_FAILED
* @see Net_FTP::execute()
*/
define('NET_FTP_ERR_EXEC_FAILED', -5);
 
/**
* Error code to indicate that the SITE command failed.
* The execution of a command using SITE failed. Ensure, that your
* FTP server supports the SITE command.
*
* @since 1.3
* @name NET_FTP_ERR_SITE_FAILED
* @see Net_FTP::site()
*/
define('NET_FTP_ERR_SITE_FAILED', -6);
 
/**
* Error code to indicate that the CHMOD command failed.
* The execution of CHMOD failed. Ensure, that your
* FTP server supports the CHMOD command and that you have the appropriate
* access rights to use CHMOD.
*
* @since 1.3
* @name NET_FTP_ERR_CHMOD_FAILED
* @see Net_FTP::chmod()
*/
define('NET_FTP_ERR_CHMOD_FAILED', -7);
 
/**
* Error code to indicate that a file rename failed
* The renaming of a file on the server failed. Ensure that you have the
* appropriate access rights to rename the file.
*
* @since 1.3
* @name NET_FTP_ERR_RENAME_FAILED
* @see Net_FTP::rename()
*/
define('NET_FTP_ERR_RENAME_FAILED', -8);
 
/**
* Error code to indicate that the MDTM command failed
* The MDTM command is not supported for directories. Ensure that you gave
* a file path to the mdtm() method, not a directory path.
*
* @since 1.3
* @name NET_FTP_ERR_MDTMDIR_UNSUPPORTED
* @see Net_FTP::mdtm()
*/
define('NET_FTP_ERR_MDTMDIR_UNSUPPORTED', -9);
 
/**
* Error code to indicate that the MDTM command failed
* The MDTM command failed. Ensure that your server supports the MDTM command.
*
* @since 1.3
* @name NET_FTP_ERR_MDTM_FAILED
* @see Net_FTP::mdtm()
*/
define('NET_FTP_ERR_MDTM_FAILED', -10);
 
/**
* Error code to indicate that a date returned by the server was misformated
* A date string returned by your server seems to be missformated and could not be
* parsed. Check that the server is configured correctly. If you're sure, please
* send an email to the auhtor with a dumped output of $ftp->ls('./', NET_FTP_RAWLIST);
* to get the date format supported.
*
* @since 1.3
* @name NET_FTP_ERR_DATEFORMAT_FAILED
* @see Net_FTP::mdtm(), Net_FTP::ls()
*/
define('NET_FTP_ERR_DATEFORMAT_FAILED', -11);
 
/**
* Error code to indicate that the SIZE command failed
* The determination of the filesize of a file failed. Ensure that your server supports the
* SIZE command.
*
* @since 1.3
* @name NET_FTP_ERR_SIZE_FAILED
* @see Net_FTP::size()
*/
define('NET_FTP_ERR_SIZE_FAILED', -12);
 
/**
* Error code to indicate that a local file could not be overwritten
* You specified not to overwrite files. Therefore the local file has not been
* overwriten. If you want to get the file overwriten, please set the option to
* do so.
*
* @since 1.3
* @name NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN
* @see Net_FTP::get(), Net_FTP::getRecursive()
*/
define('NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN', -13);
 
/**
* Error code to indicate that a local file could not be overwritten
* Also you specified to overwrite the local file you want to download to,
* it has not been possible to do so. Check that you have the appropriate access
* rights on the local file to overwrite it.
*
* @since 1.3
* @name NET_FTP_ERR_OVERWRITELOCALFILE_FAILED
* @see Net_FTP::get(), Net_FTP::getRecursive()
*/
define('NET_FTP_ERR_OVERWRITELOCALFILE_FAILED', -14);
 
/**
* Error code to indicate that the file you wanted to upload does not exist
* The file you tried to upload does not exist. Ensure that it exists.
*
* @since 1.3
* @name NET_FTP_ERR_LOCALFILENOTEXIST
* @see Net_FTP::put(), Net_FTP::putRecursive()
*/
define('NET_FTP_ERR_LOCALFILENOTEXIST', -15);
 
/**
* Error code to indicate that a remote file could not be overwritten
* You specified not to overwrite files. Therefore the remote file has not been
* overwriten. If you want to get the file overwriten, please set the option to
* do so.
*
* @since 1.3
* @name NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN
* @see Net_FTP::put(), Net_FTP::putRecursive()
*/
define('NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN', -16);
 
/**
* Error code to indicate that the upload of a file failed
* The upload you tried failed. Ensure that you have appropriate access rights
* to upload the desired file.
*
* @since 1.3
* @name NET_FTP_ERR_UPLOADFILE_FAILED
* @see Net_FTP::put(), Net_FTP::putRecursive()
*/
define('NET_FTP_ERR_UPLOADFILE_FAILED', -17);
 
/**
* Error code to indicate that you specified an incorrect directory path
* The remote path you specified seems not to be a directory. Ensure that
* the path you specify is a directory and that the path string ends with
* a /.
*
* @since 1.3
* @name NET_FTP_ERR_REMOTEPATHNODIR
* @see Net_FTP::putRecursive(), Net_FTP::getRecursive()
*/
define('NET_FTP_ERR_REMOTEPATHNODIR', -18);
 
/**
* Error code to indicate that you specified an incorrect directory path
* The local path you specified seems not to be a directory. Ensure that
* the path you specify is a directory and that the path string ends with
* a /.
*
* @since 1.3
* @name NET_FTP_ERR_LOCALPATHNODIR
* @see Net_FTP::putRecursive(), Net_FTP::getRecursive()
*/
define('NET_FTP_ERR_LOCALPATHNODIR', -19);
 
/**
* Error code to indicate that a local directory failed to be created
* You tried to create a local directory through getRecursive() method,
* which has failed. Ensure that you have the appropriate access rights
* to create it.
*
* @since 1.3
* @name NET_FTP_ERR_CREATELOCALDIR_FAILED
* @see Net_FTP::getRecursive()
*/
define('NET_FTP_ERR_CREATELOCALDIR_FAILED', -20);
 
/**
* Error code to indicate that the provided hostname was incorrect
* The hostname you provided was invalid. Ensure to provide either a
* full qualified domain name or an IP address.
*
* @since 1.3
* @name NET_FTP_ERR_HOSTNAMENOSTRING
* @see Net_FTP::setHostname()
*/
define('NET_FTP_ERR_HOSTNAMENOSTRING', -21);
 
/**
* Error code to indicate that the provided port was incorrect
* The port number you provided was invalid. Ensure to provide either a
* a numeric port number greater zero.
*
* @since 1.3
* @name NET_FTP_ERR_PORTLESSZERO
* @see Net_FTP::setPort()
*/
define('NET_FTP_ERR_PORTLESSZERO', -22);
 
/**
* Error code to indicate that you provided an invalid mode constant
* The mode constant you provided was invalid. You may only provide
* FTP_ASCII or FTP_BINARY.
*
* @since 1.3
* @name NET_FTP_ERR_NOMODECONST
* @see Net_FTP::setMode()
*/
define('NET_FTP_ERR_NOMODECONST', -23);
 
/**
* Error code to indicate that you provided an invalid timeout
* The timeout you provided was invalid. You have to provide a timeout greater
* or equal to zero.
*
* @since 1.3
* @name NET_FTP_ERR_TIMEOUTLESSZERO
* @see Net_FTP::Net_FTP(), Net_FTP::setTimeout()
*/
define('NET_FTP_ERR_TIMEOUTLESSZERO', -24);
 
/**
* Error code to indicate that you provided an invalid timeout
* An error occured while setting the timeout. Ensure that you provide a
* valid integer for the timeount and that your PHP installation works
* correctly.
*
* @since 1.3
* @name NET_FTP_ERR_SETTIMEOUT_FAILED
* @see Net_FTP::Net_FTP(), Net_FTP::setTimeout()
*/
define('NET_FTP_ERR_SETTIMEOUT_FAILED', -25);
 
/**
* Error code to indicate that the provided extension file doesn't exist
* The provided extension file does not exist. Ensure to provided an
* existant extension file.
*
* @since 1.3
* @name NET_FTP_ERR_EXTFILENOTEXIST
* @see Net_FTP::getExtensionFile()
*/
define('NET_FTP_ERR_EXTFILENOTEXIST', -26);
 
/**
* Error code to indicate that the provided extension file is not readable
* The provided extension file is not readable. Ensure to have sufficient
* access rights for it.
*
* @since 1.3
* @name NET_FTP_ERR_EXTFILEREAD_FAILED
* @see Net_FTP::getExtensionFile()
*/
define('NET_FTP_ERR_EXTFILEREAD_FAILED', -27);
 
/**
* Error code to indicate that the deletion of a file failed
* The specified file could not be deleted. Ensure to have sufficient
* access rights to delete the file.
*
* @since 1.3
* @name NET_FTP_ERR_EXTFILEREAD_FAILED
* @see Net_FTP::rm()
*/
define('NET_FTP_ERR_DELETEFILE_FAILED', -28);
 
/**
* Error code to indicate that the deletion of a directory faild
* The specified file could not be deleted. Ensure to have sufficient
* access rights to delete the file.
*
* @since 1.3
* @name NET_FTP_ERR_EXTFILEREAD_FAILED
* @see Net_FTP::rm()
*/
define('NET_FTP_ERR_DELETEDIR_FAILED', -29);
 
/**
* Error code to indicate that the directory listing failed
* PHP could not list the directory contents on the server. Ensure
* that your server is configured appropriate.
*
* @since 1.3
* @name NET_FTP_ERR_RAWDIRLIST_FAILED
* @see Net_FTP::ls()
*/
define('NET_FTP_ERR_RAWDIRLIST_FAILED', -30);
 
/**
* Error code to indicate that the directory listing failed
* The directory listing format your server uses seems not to
* be supported by Net_FTP. Please send the output of the
* call ls('./', NET_FTP_RAWLIST); to the author of this
* class to get it supported.
*
* @since 1.3
* @name NET_FTP_ERR_DIRLIST_UNSUPPORTED
* @see Net_FTP::ls()
*/
define('NET_FTP_ERR_DIRLIST_UNSUPPORTED', -31);
 
/**
* Error code to indicate failed disconnecting
* This error code indicates, that disconnection was not possible.
*
* @since 1.3
* @name NET_FTP_ERR_DISCONNECT_FAILED
* @see Net_FTP::disconnect()
*/
define('NET_FTP_ERR_DISCONNECT_FAILED', -32);
 
/**
* Error code to indicate that the username you provided was invalid.
* Check that you provided a non-empty string as the username.
*
* @since 1.3
* @name NET_FTP_ERR_USERNAMENOSTRING
* @see Net_FTP::setUsername()
*/
define('NET_FTP_ERR_USERNAMENOSTRING', -33);
 
/**
* Error code to indicate that the username you provided was invalid.
* Check that you provided a non-empty string as the username.
*
* @since 1.3
* @name NET_FTP_ERR_PASSWORDNOSTRING
* @see Net_FTP::setPassword()
*/
define('NET_FTP_ERR_PASSWORDNOSTRING', -33);
 
/**
* Class for comfortable FTP-communication
*
* This class provides comfortable communication with FTP-servers. You may do everything
* enabled by the PHP-FTP-extension and further functionalities, like recursive-deletion,
* -up- and -download. Another feature is to create directories recursively.
*
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @category Networking
* @package FTP
* @author Tobias Schlitt <toby@php.net>
* @copyright 1997-2005 The PHP Group
* @version Release: @package_version@
* @link http://pear.php.net/package/Net_FTP
* @since 0.0.1
* @access public
*/
class Net_FTP extends PEAR
{
/**
* The host to connect to
*
* @access private
* @var string
*/
var $_hostname;
 
/**
* The port for ftp-connection (standard is 21)
*
* @access private
* @var int
*/
var $_port = 21;
 
/**
* The username for login
*
* @access private
* @var string
*/
var $_username;
 
/**
* The password for login
*
* @access private
* @var string
*/
var $_password;
 
/**
* Determine whether to use passive-mode (true) or active-mode (false)
*
* @access private
* @var bool
*/
var $_passv;
 
/**
* The standard mode for ftp-transfer
*
* @access private
* @var int
*/
var $_mode = FTP_BINARY;
 
/**
* This holds the handle for the ftp-connection
*
* @access private
* @var resource
*/
var $_handle;
 
/**
* Contains the timeout for FTP operations
*
* @access private
* @var int
* @since 1.3
*/
var $_timeout = 90;
/**
* Saves file-extensions for ascii- and binary-mode
*
* The array contains 2 sub-arrays ("ascii" and "binary"), which both contain
* file-extensions without the "." (".php" = "php").
*
* @access private
* @var array
*/
var $_file_extensions;
 
/**
* ls match
* Matches the ls entries against a regex and maps the resulting array to speaking names
*
* @access private
* @var array
* @since 1.3
*/
var $_ls_match = array(
'unix' => array(
'pattern' => '/(?:(d)|.)([rwxt-]+)\s+(\w+)\s+([\w\d-]+)\s+([\w\d-]+)\s+(\w+)\s+(\S+\s+\S+\s+\S+)\s+(.+)/',
'map' => array(
'is_dir' => 1,
'rights' => 2,
'files_inside' => 3,
'user' => 4,
'group' => 5,
'size' => 6,
'date' => 7,
'name' => 8,
)
),
'windows' => array(
'pattern' => '/(.+)\s+(.+)\s+((<DIR>)|[0-9]+)\s+(.+)/',
'map' => array(
'name' => 5,
'date' => 1,
'size' => 3,
'is_dir' => 4,
)
)
);
/**
* matcher
* Stores the matcher for the current connection
*
* @access private
* @var array
* @since 1.3
*/
var $_matcher = null;
/**
* Holds all Net_FTP_Observer objects
* that wish to be notified of new messages.
*
* @var array
* @access private
* @since 1.3
*/
var $_listeners = array();
 
/**
* This generates a new FTP-Object. The FTP-connection will not be established, yet.
* You can leave $host and $port blank, if you want. The $host will not be set
* and the $port will be left at 21. You have to set the $host manualy before
* trying to connect or with the connect() method.
*
* @access public
* @param string $host (optional) The hostname
* @param int $port (optional) The port
* @param int $timeout (optional) Sets the standard timeout
* @return void
* @see Net_FTP::setHostname(), Net_FTP::setPort(), Net_FTP::connect()
*/
function Net_FTP($host = null, $port = null, $timeout = 90)
{
$this->PEAR();
if (isset($host)) {
$this->setHostname($host);
}
if (isset($port)) {
$this->setPort($port);
}
$this->_timeout = $timeout;
$this->_file_extensions[FTP_ASCII] = array();
$this->_file_extensions[FTP_BINARY] = array();
}
 
/**
* This function generates the FTP-connection. You can optionally define a
* hostname and/or a port. If you do so, this data is stored inside the object.
*
* @access public
* @param string $host (optional) The Hostname
* @param int $port (optional) The Port
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_CONNECT_FAILED
*/
function connect($host = null, $port = null)
{
$this->_matcher = null;
if (isset($host)) {
$this->setHostname($host);
}
if (isset($port)) {
$this->setPort($port);
}
$handle = @ftp_connect($this->getHostname(), $this->getPort(), $this->_timeout);
if (!$handle) {
return $this->raiseError("Connection to host failed", NET_FTP_ERR_CONNECT_FAILED);
} else {
$this->_handle =& $handle;
return true;
}
}
 
/**
* This function close the FTP-connection
*
* @access public
* @return bool|PEAR_Error Returns true on success, PEAR_Error on failure
*/
function disconnect()
{
$res = @ftp_close($this->_handle);
if (!$res) {
return PEAR::raiseError('Disconnect failed.', NET_FTP_ERR_DISCONNECT_FAILED);
}
return true;
}
 
/**
* This logges you into the ftp-server. You are free to specify username and password
* in this method. If you specify it, the values will be taken into the corresponding
* attributes, if do not specify, the attributes are taken.
*
* @access public
* @param string $username (optional) The username to use
* @param string $password (optional) The password to use
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_LOGIN_FAILED
*/
function login($username = null, $password = null)
{
if (!isset($username)) {
$username = $this->getUsername();
} else {
$this->setUsername($username);
}
 
if (!isset($password)) {
$password = $this->getPassword();
} else {
$this->setPassword($password);
}
 
$res = @ftp_login($this->_handle, $username, $password);
 
if (!$res) {
return $this->raiseError("Unable to login", NET_FTP_ERR_LOGIN_FAILED);
} else {
return true;
}
}
 
/**
* This changes the currently used directory. You can use either an absolute
* directory-path (e.g. "/home/blah") or a relative one (e.g. "../test").
*
* @access public
* @param string $dir The directory to go to.
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DIRCHANGE_FAILED
*/
function cd($dir)
{
$erg = @ftp_chdir($this->_handle, $dir);
if (!$erg) {
return $this->raiseError("Directory change failed", NET_FTP_ERR_DIRCHANGE_FAILED);
} else {
return true;
}
}
 
/**
* Show's you the actual path on the server
* This function questions the ftp-handle for the actual selected path and returns it.
*
* @access public
* @return mixed The actual path or PEAR::Error
* @see NET_FTP_ERR_DETERMINEPATH_FAILED
*/
function pwd()
{
$res = @ftp_pwd($this->_handle);
if (!$res) {
return $this->raiseError("Could not determine the actual path.", NET_FTP_ERR_DETERMINEPATH_FAILED);
} else {
return $res;
}
}
 
/**
* This works similar to the mkdir-command on your local machine. You can either give
* it an absolute or relative path. The relative path will be completed with the actual
* selected server-path. (see: pwd())
*
* @access public
* @param string $dir Absolute or relative dir-path
* @param bool $recursive (optional) Create all needed directories
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_CREATEDIR_FAILED
*/
function mkdir($dir, $recursive = false)
{
$dir = $this->_construct_path($dir);
$savedir = $this->pwd();
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$e = $this->cd($dir);
$this->popErrorHandling();
if ($e === true) {
$this->cd($savedir);
return true;
}
$this->cd($savedir);
if ($recursive === false){
$res = @ftp_mkdir($this->_handle, $dir);
if (!$res) {
return $this->raiseError("Creation of '$dir' failed", NET_FTP_ERR_CREATEDIR_FAILED);
} else {
return true;
}
} else {
if(strpos($dir, '/') === false) {
return $this->mkdir($dir,false);
}
$pos = 0;
$res = $this->mkdir(dirname($dir), true);
$res = $this->mkdir($dir, false);
if ($res !== true) {
return $res;
}
return true;
}
}
 
/**
* This method tries executing a command on the ftp, using SITE EXEC.
*
* @access public
* @param string $command The command to execute
* @return mixed The result of the command (if successfull), otherwise PEAR::Error
* @see NET_FTP_ERR_EXEC_FAILED
*/
function execute($command)
{
$res = @ftp_exec($this->_handle, $command);
if (!$res) {
return $this->raiseError("Execution of command '$command' failed.", NET_FTP_ERR_EXEC_FAILED);
} else {
return $res;
}
}
 
/**
* Execute a SITE command on the server
* This method tries to execute a SITE command on the ftp server.
*
* @access public
* @param string $command The command with parameters to execute
* @return mixed True if successful, otherwise PEAR::Error
* @see NET_FTP_ERR_SITE_FAILED
*/
function site($command)
{
$res = @ftp_site($this->_handle, $command);
if (!$res) {
return $this->raiseError("Execution of SITE command '$command' failed.", NET_FTP_ERR_SITE_FAILED);
} else {
return $res;
}
}
 
/**
* This method will try to chmod the file specified on the server
* Currently, you must give a number as the the permission argument (777 or
* similar). The file can be either a relative or absolute path.
* NOTE: Some servers do not support this feature. In that case, you will
* get a PEAR error object returned. If successful, the method returns true
*
* @access public
* @param mixed $target The file or array of files to set permissions for
* @param integer $permissions The mode to set the file permissions to
* @return mixed True if successful, otherwise PEAR::Error
* @see NET_FTP_ERR_CHMOD_FAILED
*/
function chmod($target, $permissions)
{
// If $target is an array: Loop through it.
if (is_array($target)) {
 
for ($i = 0; $i < count($target); $i++) {
$res = $this->chmod($target[$i], $permissions);
if (PEAR::isError($res)) {
return $res;
} // end if isError
} // end for i < count($target)
 
} else {
 
$res = $this->site("CHMOD " . $permissions . " " . $target);
if (!$res) {
return PEAR::raiseError("CHMOD " . $permissions . " " . $target . " failed", NET_FTP_ERR_CHMOD_FAILED);
} else {
return $res;
}
 
} // end if is_array
 
} // end method chmod
 
/**
* This method will try to chmod a folder and all of its contents
* on the server. The target argument must be a folder or an array of folders
* and the permissions argument have to be an integer (i.e. 777).
* The file can be either a relative or absolute path.
* NOTE: Some servers do not support this feature. In that case, you
* will get a PEAR error object returned. If successful, the method
* returns true
*
* @access public
* @param mixed $target The folder or array of folders to
* set permissions for
* @param integer $permissions The mode to set the folder
* and file permissions to
* @return mixed True if successful, otherwise PEAR::Error
* @see NET_FTP_ERR_CHMOD_FAILED, NET_FTP_ERR_DETERMINEPATH_FAILED, NET_FTP_ERR_RAWDIRLIST_FAILED, NET_FTP_ERR_DIRLIST_UNSUPPORTED
*/
function chmodRecursive($target, $permissions)
{
static $dir_permissions;
 
if(!isset($dir_permissions)){ // Making directory specific permissions
$dir_permissions = $this->_makeDirPermissions($permissions);
}
 
// If $target is an array: Loop through it
if (is_array($target)) {
 
for ($i = 0; $i < count($target); $i++) {
$res = $this->chmodRecursive($target[$i], $permissions);
if (PEAR::isError($res)) {
return $res;
} // end if isError
} // end for i < count($target)
 
} else {
 
$remote_path = $this->_construct_path($target);
 
// Chmod the directory itself
$result = $this->chmod($remote_path, $dir_permissions);
 
if (PEAR::isError($result)) {
return $result;
}
 
// If $remote_path last character is not a slash, add one
if (substr($remote_path, strlen($remote_path)-1) != "/") {
 
$remote_path .= "/";
}
 
$dir_list = array();
$mode = NET_FTP_DIRS_ONLY;
$dir_list = $this->ls($remote_path, $mode);
foreach ($dir_list as $dir_entry) {
if ($dir_entry == '.' || $dir_entry == '..') {;
continue;
}
$remote_path_new = $remote_path.$dir_entry["name"]."/";
 
// Chmod the directory we're about to enter
$result = $this->chmod($remote_path_new, $dir_permissions);
 
if (PEAR::isError($result)) {
return $result;
}
 
$result = $this->chmodRecursive($remote_path_new, $permissions);
 
if (PEAR::isError($result)) {
return $result;
}
 
} // end foreach dir_list as dir_entry
 
$file_list = array();
$mode = NET_FTP_FILES_ONLY;
$file_list = $this->ls($remote_path, $mode);
 
foreach ($file_list as $file_entry) {
 
$remote_file = $remote_path.$file_entry["name"];
 
$result = $this->chmod($remote_file, $permissions);
 
if (PEAR::isError($result)) {
return $result;
}
 
} // end foreach $file_list
 
} // end if is_array
 
return true; // No errors
 
} // end method chmodRecursive
 
/**
* Rename or move a file or a directory from the ftp-server
*
* @access public
* @param string $remote_from The remote file or directory original to rename or move
* @param string $remote_to The remote file or directory final to rename or move
* @return bool $res True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_RENAME_FAILED
*/
 
function rename ($remote_from, $remote_to)
{
$res = @ftp_rename($this->_handle, $remote_from, $remote_to);
if(!$res) {
return $this->raiseError("Could not rename ".$remote_from." to ".$remote_to." !", NET_FTP_ERR_RENAME_FAILED);
}
return true;
}
 
/**
* This will return logical permissions mask for directory.
* if directory have to be writeable it have also be executable
*
* @access private
* @param string $permissions File permissions in digits for file (i.e. 666)
* @return string File permissions in digits for directory (i.e. 777)
*/
 
function _makeDirPermissions($permissions){
$permissions = (string)$permissions;
 
for($i = 0; $i < strlen($permissions); $i++){ // going through (user, group, world)
if((int)$permissions{$i} & 4 and !((int)$permissions{$i} & 1)){ // Read permission is set
// but execute not yet
(int)$permissions{$i} = (int)$permissions{$i} + 1; // Adding execute flag
}
}
 
return (string)$permissions;
}
 
/**
* This will return the last modification-time of a file. You can either give this
* function a relative or an absolute path to the file to check.
* NOTE: Some servers will not support this feature and the function works
* only on files, not directories! When successful,
* it will return the last modification-time as a unix-timestamp or, when $format is
* specified, a preformated timestring.
*
* @access public
* @param string $file The file to check
* @param string $format (optional) The format to give the date back
* if not set, it will return a Unix timestamp
* @return mixed Unix timestamp, a preformated date-string or PEAR::Error
* @see NET_FTP_ERR_MDTMDIR_UNSUPPORTED, NET_FTP_ERR_MDTM_FAILED, NET_FTP_ERR_DATEFORMAT_FAILED
*/
function mdtm($file, $format = null)
{
$file = $this->_construct_path($file);
if ($this->_check_dir($file)) {
return $this->raiseError("Filename '$file' seems to be a directory.", NET_FTP_ERR_MDTMDIR_UNSUPPORTED);
}
$res = @ftp_mdtm($this->_handle, $file);
if ($res == -1) {
return $this->raiseError("Could not get last-modification-date of '$file'.", NET_FTP_ERR_MDTM_FAILED);
}
if (isset($format)) {
$res = date($format, $res);
if (!$res) {
return $this->raiseError("Date-format failed on timestamp '$res'.", NET_FTP_ERR_DATEFORMAT_FAILED);
}
}
return $res;
}
 
/**
* This will return the size of a given file in bytes. You can either give this function
* a relative or an absolute file-path. NOTE: Some servers do not support this feature!
*
* @access public
* @param string $file The file to check
* @return mixed Size in bytes or PEAR::Error
* @see NET_FTP_ERR_SIZE_FAILED
*/
function size($file)
{
$file = $this->_construct_path($file);
$res = @ftp_size($this->_handle, $file);
if ($res == -1) {
return $this->raiseError("Could not determine filesize of '$file'.", NET_FTP_ERR_SIZE_FAILED);
} else {
return $res;
}
}
 
/**
* This method returns a directory-list of the current directory or given one.
* To display the current selected directory, simply set the first parameter to null
* or leave it blank, if you do not want to use any other parameters.
* <BR><BR>
* There are 4 different modes of listing directories. Either to list only
* the files (using NET_FTP_FILES_ONLY), to list only directories (using
* NET_FTP_DIRS_ONLY) or to show both (using NET_FTP_DIRS_FILES, which is default).
* <BR><BR>
* The 4th one is the NET_FTP_RAWLIST, which returns just the array created by the
* ftp_rawlist()-function build into PHP.
* <BR><BR>
* The other function-modes will return an array containing the requested data.
* The files and dirs are listed in human-sorted order, but if you select
* NET_FTP_DIRS_FILES the directories will be added above the files,
* but although both sorted.
* <BR><BR>
* All elements in the arrays are associative arrays themselves. The have the following
* structure:
* <BR><BR>
* Dirs:<BR>
* ["name"] => string The name of the directory<BR>
* ["rights"] => string The rights of the directory (in style "rwxr-xr-x")<BR>
* ["user"] => string The owner of the directory<BR>
* ["group"] => string The group-owner of the directory<BR>
* ["files_inside"]=> string The number of files/dirs inside the directory
* excluding "." and ".."<BR>
* ["date"] => int The creation-date as Unix timestamp<BR>
* ["is_dir"] => bool true, cause this is a dir<BR>
* <BR><BR>
* Files:<BR>
* ["name"] => string The name of the file<BR>
* ["size"] => int Size in bytes<BR>
* ["rights"] => string The rights of the file (in style "rwxr-xr-x")<BR>
* ["user"] => string The owner of the file<BR>
* ["group"] => string The group-owner of the file<BR>
* ["date"] => int The creation-date as Unix timestamp<BR>
* ["is_dir"] => bool false, cause this is a file<BR>
*
* @access public
* @param string $dir (optional) The directory to list or null, when listing the current directory.
* @param int $mode (optional) The mode which types to list (files, directories or both).
* @return mixed The directory list as described above or PEAR::Error on failure.
* @see NET_FTP_DIRS_FILES, NET_FTP_DIRS_ONLY, NET_FTP_FILES_ONLY, NET_FTP_RAWLIST, NET_FTP_ERR_DETERMINEPATH_FAILED, NET_FTP_ERR_RAWDIRLIST_FAILED, NET_FTP_ERR_DIRLIST_UNSUPPORTED
*/
function ls($dir = null, $mode = NET_FTP_DIRS_FILES)
{
if (!isset($dir)) {
$dir = @ftp_pwd($this->_handle);
if (!$dir) {
return $this->raiseError("Could not retrieve current directory", NET_FTP_ERR_DETERMINEPATH_FAILED);
}
}
if (($mode != NET_FTP_FILES_ONLY) && ($mode != NET_FTP_DIRS_ONLY) && ($mode != NET_FTP_RAWLIST)) {
$mode = NET_FTP_DIRS_FILES;
}
 
switch ($mode) {
case NET_FTP_DIRS_FILES: $res = $this->_ls_both ( $dir );
break;
case NET_FTP_DIRS_ONLY: $res = $this->_ls_dirs ( $dir );
break;
case NET_FTP_FILES_ONLY: $res = $this->_ls_files ( $dir );
break;
case NET_FTP_RAWLIST: $res = @ftp_rawlist($this->_handle, $dir);
break;
}
 
return $res;
}
 
/**
* This method will delete the given file or directory ($path) from the server
* (maybe recursive).
*
* Whether the given string is a file or directory is only determined by the last
* sign inside the string ("/" or not).
*
* If you specify a directory, you can optionally specify $recursive as true,
* to let the directory be deleted recursive (with all sub-directories and files
* inherited).
*
* You can either give a absolute or relative path for the file / dir. If you choose to
* use the relative path, it will be automatically completed with the actual
* selected directory.
*
* @access public
* @param string $path The absolute or relative path to the file / directory.
* @param bool $recursive (optional)
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DELETEFILE_FAILED, NET_FTP_ERR_DELETEDIR_FAILED, NET_FTP_ERR_REMOTEPATHNODIR
*/
function rm($path, $recursive = false)
{
$path = $this->_construct_path($path);
 
if ($this->_check_dir($path)) {
if ($recursive) {
return $this->_rm_dir_recursive($path);
} else {
return $this->_rm_dir($path);
}
} else {
return $this->_rm_file($path);
}
}
 
/**
* This function will download a file from the ftp-server. You can either spcify a absolute
* path to the file (beginning with "/") or a relative one, which will be completed
* with the actual directory you selected on the server. You can specify
* the path to which the file will be downloaded on the local
* maschine, if the file should be overwritten if it exists (optionally, default is
* no overwriting) and in which mode (FTP_ASCII or FTP_BINARY) the file should be
* downloaded (if you do not specify this, the method tries to determine it automatically
* from the mode-directory or uses the default-mode, set by you). If you give a relative
* path to the local-file, the script-path is used as basepath.
*
* @access public
* @param string $remote_file The absolute or relative path to the file to download
* @param string $local_file The local file to put the downloaded in
* @param bool $overwrite (optional) Whether to overwrite existing file
* @param int $mode (optional) Either FTP_ASCII or FTP_BINARY
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED
*/
function get($remote_file, $local_file, $overwrite = false, $mode = null)
{
if (!isset($mode)) {
$mode = $this->checkFileExtension($remote_file);
}
 
$remote_file = $this->_construct_path($remote_file);
 
if (@file_exists($local_file) && !$overwrite) {
return $this->raiseError("Local file '$local_file' exists and may not be overwriten.", NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN);
}
if (@file_exists($local_file) && !@is_writeable($local_file) && $overwrite) {
return $this->raiseError("Local file '$local_file' is not writeable. Can not overwrite.", NET_FTP_ERR_OVERWRITELOCALFILE_FAILED);
}
 
if (@function_exists('ftp_nb_get')){
$res = @ftp_nb_get($this->_handle, $local_file, $remote_file, $mode);
while ($res == FTP_MOREDATA) {
$this->_announce('nb_get');
$res = @ftp_nb_continue ($this->_handle);
}
} else {
$res = @ftp_get($this->_handle, $local_file, $remote_file, $mode);
}
if (!$res) {
return $this->raiseError("File '$remote_file' could not be downloaded to '$local_file'.", NET_FTP_ERR_OVERWRITELOCALFILE_FAILED);
} else {
return true;
}
}
 
/**
* This function will upload a file to the ftp-server. You can either specify a absolute
* path to the remote-file (beginning with "/") or a relative one, which will be completed
* with the actual directory you selected on the server. You can specify
* the path from which the file will be uploaded on the local
* maschine, if the file should be overwritten if it exists (optionally, default is
* no overwriting) and in which mode (FTP_ASCII or FTP_BINARY) the file should be
* downloaded (if you do not specify this, the method tries to determine it automatically
* from the mode-directory or uses the default-mode, set by you). If you give a relative
* path to the local-file, the script-path is used as basepath.
*
* @access public
* @param string $local_file The local file to upload
* @param string $remote_file The absolute or relative path to the file to upload to
* @param bool $overwrite (optional) Whether to overwrite existing file
* @param int $mode (optional) Either FTP_ASCII or FTP_BINARY
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_LOCALFILENOTEXIST, NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN, NET_FTP_ERR_UPLOADFILE_FAILED
*/
function put($local_file, $remote_file, $overwrite = false, $mode = null)
{
if (!isset($mode)) {
$mode = $this->checkFileExtension($local_file);
}
$remote_file = $this->_construct_path($remote_file);
 
if (!@file_exists($local_file)) {
return $this->raiseError("Local file '$local_file' does not exist.", NET_FTP_ERR_LOCALFILENOTEXIST);
}
if ((@ftp_size($this->_handle, $remote_file) != -1) && !$overwrite) {
return $this->raiseError("Remote file '$remote_file' exists and may not be overwriten.", NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN);
}
 
if (function_exists('ftp_nb_put')){
$res = @ftp_nb_put($this->_handle, $remote_file, $local_file, $mode);
while ($res == FTP_MOREDATA) {
$this->_announce('nb_put');
$res = @ftp_nb_continue($this->_handle);
}
 
} else {
$res = @ftp_put($this->_handle, $remote_file, $local_file, $mode);
}
if (!$res) {
return $this->raiseError("File '$local_file' could not be uploaded to '$remote_file'.", NET_FTP_ERR_UPLOADFILE_FAILED);
} else {
return true;
}
}
 
/**
* This functionality allows you to transfer a whole directory-structure from the
* remote-ftp to your local host. You have to give a remote-directory (ending with
* '/') and the local directory (ending with '/') where to put the files you download.
* The remote path is automatically completed with the current-remote-dir, if you give
* a relative path to this function. You can give a relative path for the $local_path,
* too. Then the script-basedir will be used for comletion of the path.
* The parameter $overwrite will determine, whether to overwrite existing files or not.
* Standard for this is false. Fourth you can explicitly set a mode for all transfer-
* actions done. If you do not set this, the method tries to determine the transfer-
* mode by checking your mode-directory for the file-extension. If the extension is not
* inside the mode-directory, it will get your default-mode.
*
* @access public
* @param string $remote_path The path to download
* @param string $local_path The path to download to
* @param bool $overwrite (optional) Whether to overwrite existing files (true) or not (false, standard).
* @param int $mode (optional) The transfermode (either FTP_ASCII or FTP_BINARY).
* @return mixed True on succes, otherwise PEAR::Error
* @see NET_FTP_ERR_OVERWRITELOCALFILE_FORBIDDEN, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_OVERWRITELOCALFILE_FAILED, NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_LOCALPATHNODIR,NET_FTP_ERR_CREATELOCALDIR_FAILED
*/
function getRecursive($remote_path, $local_path, $overwrite = false, $mode = null)
{
$remote_path = $this->_construct_path($remote_path);
if (!$this->_check_dir($remote_path)) {
return $this->raiseError("Given remote-path '$remote_path' seems not to be a directory.", NET_FTP_ERR_REMOTEPATHNODIR);
}
if (!$this->_check_dir($local_path)) {
return $this->raiseError("Given local-path '$local_path' seems not to be a directory.", NET_FTP_ERR_LOCALPATHNODIR);
}
 
if (!@is_dir($local_path)) {
$res = @mkdir($local_path);
if (!$res) {
return $this->raiseError("Could not create dir '$local_path'", NET_FTP_ERR_CREATELOCALDIR_FAILED);
}
}
$dir_list = array();
$dir_list = $this->ls($remote_path, NET_FTP_DIRS_ONLY);
foreach ($dir_list as $dir_entry) {
if ($dir_entry['name'] != '.' && $dir_entry['name'] != '..') {
$remote_path_new = $remote_path.$dir_entry["name"]."/";
$local_path_new = $local_path.$dir_entry["name"]."/";
$result = $this->getRecursive($remote_path_new, $local_path_new, $overwrite, $mode);
if ($this->isError($result)) {
return $result;
}
}
}
$file_list = array();
$file_list = $this->ls($remote_path, NET_FTP_FILES_ONLY);
foreach ($file_list as $file_entry) {
$remote_file = $remote_path.$file_entry["name"];
$local_file = $local_path.$file_entry["name"];
$result = $this->get($remote_file, $local_file, $overwrite, $mode);
if ($this->isError($result)) {
return $result;
}
}
return true;
}
 
/**
* This functionality allows you to transfer a whole directory-structure from your
* local host to the remote-ftp. You have to give a remote-directory (ending with
* '/') and the local directory (ending with '/') where to put the files you download.
* The remote path is automatically completed with the current-remote-dir, if you give
* a relative path to this function. You can give a relative path for the $local_path,
* too. Then the script-basedir will be used for comletion of the path.
* The parameter $overwrite will determine, whether to overwrite existing files or not.
* Standard for this is false. Fourth you can explicitly set a mode for all transfer-
* actions done. If you do not set this, the method tries to determine the transfer-
* mode by checking your mode-directory for the file-extension. If the extension is not
* inside the mode-directory, it will get your default-mode.
*
* @access public
* @param string $remote_path The path to download
* @param string $local_path The path to download to
* @param bool $overwrite (optional) Whether to overwrite existing files (true) or not (false, standard).
* @param int $mode (optional) The transfermode (either FTP_ASCII or FTP_BINARY).
* @return mixed True on succes, otherwise PEAR::Error
* @see NET_FTP_ERR_LOCALFILENOTEXIST, NET_FTP_ERR_OVERWRITEREMOTEFILE_FORBIDDEN, NET_FTP_ERR_UPLOADFILE_FAILED, NET_FTP_ERR_LOCALPATHNODIR, NET_FTP_ERR_REMOTEPATHNODIR
*/
function putRecursive($local_path, $remote_path, $overwrite = false, $mode = null)
{
$remote_path = $this->_construct_path($remote_path);
if (!$this->_check_dir($local_path) || !is_dir($local_path)) {
return $this->raiseError("Given local-path '$local_path' seems not to be a directory.", NET_FTP_ERR_LOCALPATHNODIR);
}
if (!$this->_check_dir($remote_path)) {
return $this->raiseError("Given remote-path '$remote_path' seems not to be a directory.", NET_FTP_ERR_REMOTEPATHNODIR);
}
$old_path = $this->pwd();
if ($this->isError($this->cd($remote_path))) {
$res = $this->mkdir($remote_path);
if ($this->isError($res)) {
return $res;
}
}
$this->cd($old_path);
$dir_list = $this->_ls_local($local_path);
foreach ($dir_list["dirs"] as $dir_entry) {
$remote_path_new = $remote_path.$dir_entry."/";
$local_path_new = $local_path.$dir_entry."/";
$result = $this->putRecursive($local_path_new, $remote_path_new, $overwrite, $mode);
if ($this->isError($result)) {
return $result;
}
}
 
foreach ($dir_list["files"] as $file_entry) {
$remote_file = $remote_path.$file_entry;
$local_file = $local_path.$file_entry;
$result = $this->put($local_file, $remote_file, $overwrite, $mode);
if ($this->isError($result)) {
return $result;
}
}
return true;
}
 
/**
* This checks, whether a file should be transfered in ascii- or binary-mode
* by it's file-extension. If the file-extension is not set or
* the extension is not inside one of the extension-dirs, the actual set
* transfer-mode is returned.
*
* @access public
* @param string $filename The filename to be checked
* @return int Either FTP_ASCII or FTP_BINARY
*/
function checkFileExtension($filename)
{
$pattern = "/\.(.*)$/";
$has_extension = preg_match($pattern, $filename, $eregs);
if (!$has_extension) {
return $this->_mode;
} else {
$ext = $eregs[1];
}
 
if (!empty($this->_file_extensions[$ext])) {
return $this->_file_extensions[$ext];
}
 
return $this->_mode;
}
 
/**
* Set the Hostname
*
* @access public
* @param string $host The Hostname to set
* @return bool True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_HOSTNAMENOSTRING
*/
function setHostname($host)
{
if (!is_string($host)) {
return PEAR::raiseError("Hostname must be a string.", NET_FTP_ERR_HOSTNAMENOSTRING);
}
$this->_hostname = $host;
return true;
}
 
/**
* Set the Port
*
* @access public
* @param int $port The Port to set
* @return bool True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_PORTLESSZERO
*/
function setPort($port)
{
if (!is_int($port) || ($port < 0)) {
PEAR::raiseError("Invalid port. Has to be integer >= 0", NET_FTP_ERR_PORTLESSZERO);
}
$this->_port = $port;
return true;
}
 
/**
* Set the Username
*
* @access public
* @param string $user The Username to set
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_USERNAMENOSTRING
*/
function setUsername($user)
{
if (empty($user) || !is_string($user)) {
return PEAR::raiseError('Username $user invalid.', NET_FTP_ERR_USERNAMENOSTRING);
}
$this->_username = $user;
}
 
/**
* Set the Password
*
* @access private
* @param string $password The Password to set
* @return void
* @see NET_FTP_ERR_PASSWORDNOSTRING
*/
function setPassword($password)
{
if (empty($password) || !is_string($password)) {
return PEAR::raiseError('Password xxx invalid.', NET_FTP_ERR_PASSWORDNOSTRING);
}
$this->_password = $password;
}
 
/**
* Set the transfer-mode. You can use the predefined constants
* FTP_ASCII or FTP_BINARY. The mode will be stored for any further transfers.
*
* @access public
* @param int $mode The mode to set
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_NOMODECONST
*/
function setMode($mode)
{
if (($mode == FTP_ASCII) || ($mode == FTP_BINARY)) {
$this->_mode = $mode;
return true;
} else {
return $this->raiseError('FTP-Mode has either to be FTP_ASCII or FTP_BINARY', NET_FTP_ERR_NOMODECONST);
}
}
 
/**
* Set the transfer-method to passive mode
*
* @access public
* @return void
*/
function setPassive()
{
$this->_passv = true;
@ftp_pasv($this->_handle, true);
}
 
/**
* Set the transfer-method to active mode
*
* @access public
* @return void
*/
function setActive()
{
$this->_passv = false;
@ftp_pasv($this->_handle, false);
}
 
/**
* Set the timeout for FTP operations
* Use this method to set a timeout for FTP operation. Timeout has to be an integer.
*
* @acess public
* @param int $timeout the timeout to use
* @return bool True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_TIMEOUTLESSZERO, NET_FTP_ERR_SETTIMEOUT_FAILED
*/
function setTimeout ( $timeout = 0 )
{
if (!is_int($timeout) || ($timeout < 0)) {
return PEAR::raiseError("Timeout $timeout is invalid, has to be an integer >= 0", NET_FTP_ERR_TIMEOUTLESSZERO);
}
$this->_timeout = $timeout;
if (isset($this->_handle) && is_resource($this->_handle)) {
$res = @ftp_set_option($this->_handle, FTP_TIMEOUT_SEC, $timeout);
} else {
$res = true;
}
if (!$res) {
return PEAR::raiseError("Set timeout failed.", NET_FTP_ERR_SETTIMEOUT_FAILED);
}
return true;
}
/**
* Adds an extension to a mode-directory
* The mode-directory saves file-extensions coresponding to filetypes
* (ascii e.g.: 'php', 'txt', 'htm',...; binary e.g.: 'jpg', 'gif', 'exe',...).
* The extensions have to be saved without the '.'. And
* can be predefined in an external file (see: getExtensionsFile()).
*
* The array is build like this: 'php' => FTP_ASCII, 'png' => FTP_BINARY
*
* To change the mode of an extension, just add it again with the new mode!
*
* @access public
* @param int $mode Either FTP_ASCII or FTP_BINARY
* @param string $ext Extension
* @return void
*/
function addExtension($mode, $ext)
{
$this->_file_extensions[$ext] = $mode;
}
 
/**
* This function removes an extension from the mode-directories
* (described above).
*
* @access public
* @param string $ext The extension to remove
* @return void
*/
function removeExtension($ext)
{
unset($this->_file_extensions[$ext]);
}
 
/**
* This get's both (ascii- and binary-mode-directories) from the given file.
* Beware, if you read a file into the mode-directory, all former set values
* will be unset!
*
* @access public
* @param string $filename The file to get from
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_EXTFILENOTEXIST, NET_FTP_ERR_EXTFILEREAD_FAILED
*/
function getExtensionsFile($filename)
{
if (!file_exists($filename)) {
return $this->raiseError("Extensions-file '$filename' does not exist", NET_FTP_ERR_EXTFILENOTEXIST);
}
 
if (!is_readable($filename)) {
return $this->raiseError("Extensions-file '$filename' is not readable", NET_FTP_ERR_EXTFILEREAD_FAILED);
}
 
$this->_file_extension = @parse_ini_file($filename);
return true;
}
 
/**
* Returns the Hostname
*
* @access public
* @return string The Hostname
*/
function getHostname()
{
return $this->_hostname;
}
 
/**
* Returns the Port
*
* @access public
* @return int The Port
*/
function getPort()
{
return $this->_port;
}
 
/**
* Returns the Username
*
* @access public
* @return string The Username
*/
function getUsername()
{
return $this->_username;
}
 
/**
* Returns the Password
*
* @access public
* @return string The Password
*/
function getPassword()
{
return $this->_password;
}
 
/**
* Returns the Transfermode
*
* @access public
* @return int The transfermode, either FTP_ASCII or FTP_BINARY.
*/
function getMode()
{
return $this->_mode;
}
 
/**
* Returns, whether the connection is set to passive mode or not
*
* @access public
* @return bool True if passive-, false if active-mode
*/
function isPassive()
{
return $this->_passv;
}
 
/**
* Returns the mode set for a file-extension
*
* @access public
* @param string $ext The extension you wanna ask for
* @return int Either FTP_ASCII, FTP_BINARY or NULL (if not set a mode for it)
*/
function getExtensionMode($ext)
{
return @$this->_file_extensions[$ext];
}
 
/**
* Get the currently set timeout.
* Returns the actual timeout set.
*
* @access public
* @return int The actual timeout
*/
function getTimeout ( )
{
return ftp_get_option($this->_handle, FTP_TIMEOUT_SEC);
}
 
/**
* Adds a Net_FTP_Observer instance to the list of observers
* that are listening for messages emitted by this Net_FTP instance.
*
* @param object $observer The Net_FTP_Observer instance to attach
* as a listener.
* @return boolean True if the observer is successfully attached.
* @access public
* @since 1.3
*/
function attach(&$observer)
{
if (!is_a($observer, 'Net_FTP_Observer')) {
return false;
}
 
$this->_listeners[$observer->getId()] = &$observer;
return true;
}
 
/**
* Removes a Net_FTP_Observer instance from the list of observers.
*
* @param object $observer The Net_FTP_Observer instance to detach
* from the list of listeners.
* @return boolean True if the observer is successfully detached.
* @access public
* @since 1.3
*/
function detach($observer)
{
if (!is_a($observer, 'Net_FTP_Observer') ||
!isset($this->_listeners[$observer->getId()])) {
return false;
}
 
unset($this->_listeners[$observer->getId()]);
return true;
}
 
/**
* Informs each registered observer instance that a new message has been
* sent.
*
* @param mixed $event A hash describing the net event.
* @access private
* @since 1.3
*/
function _announce($event)
{
foreach ($this->_listeners as $id => $listener) {
$this->_listeners[$id]->notify($event);
}
}
/**
* Rebuild the path, if given relative
*
* @access private
* @param string $path The path to check and construct
* @return string The build path
*/
function _construct_path($path)
{
if ((substr($path, 0, 1) != "/") && (substr($path, 0, 2) != "./")) {
$actual_dir = @ftp_pwd($this->_handle);
if (substr($actual_dir, (strlen($actual_dir) - 2), 1) != "/") {
$actual_dir .= "/";
}
$path = $actual_dir.$path;
}
return $path;
}
 
/**
* Checks, whether a given string is a directory-path (ends with "/") or not.
*
* @access private
* @param string $path Path to check
* @return bool True if $path is a directory, otherwise false
*/
function _check_dir($path)
{
if (!empty($path) && substr($path, (strlen($path) - 1), 1) == "/") {
return true;
} else {
return false;
}
}
 
/**
* This will remove a file
*
* @access private
* @param string $file The file to delete
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DELETEFILE_FAILED
*/
function _rm_file($file)
{
if (substr($file, 0, 1) != "/") {
$actual_dir = @ftp_pwd($this->_handle);
if (substr($actual_dir, (strlen($actual_dir) - 2), 1) != "/") {
$actual_dir .= "/";
}
$file = $actual_dir.$file;
}
$res = @ftp_delete($this->_handle, $file);
if (!$res) {
return $this->raiseError("Could not delete file '$file'.", NET_FTP_ERR_DELETEFILE_FAILED);
} else {
return true;
}
}
 
/**
* This will remove a dir
*
* @access private
* @param string $dir The dir to delete
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_DELETEDIR_FAILED
*/
function _rm_dir($dir)
{
if (substr($dir, (strlen($dir) - 1), 1) != "/") {
return $this->raiseError("Directory name '$dir' is invalid, has to end with '/'", NET_FTP_ERR_REMOTEPATHNODIR);
}
$res = @ftp_rmdir($this->_handle, $dir);
if (!$res) {
return $this->raiseError("Could not delete directory '$dir'.", NET_FTP_ERR_DELETEDIR_FAILED);
} else {
return true;
}
}
 
/**
* This will remove a dir and all subdirs and -files
*
* @access private
* @param string $file The dir to delete recursively
* @return mixed True on success, otherwise PEAR::Error
* @see NET_FTP_ERR_REMOTEPATHNODIR, NET_FTP_ERR_DELETEDIR_FAILED
*/
function _rm_dir_recursive($dir)
{
if (substr($dir, (strlen($dir) - 1), 1) != "/") {
return $this->raiseError("Directory name '$dir' is invalid, has to end with '/'", NET_FTP_ERR_REMOTEPATHNODIR);
}
$file_list = $this->_ls_files($dir);
foreach ($file_list as $file) {
$file = $dir.$file["name"];
$res = $this->rm($file);
if ($this->isError($res)) {
return $res;
}
}
$dir_list = $this->_ls_dirs($dir);
foreach ($dir_list as $new_dir) {
if ($new_dir == '.' || $new_dir == '..') {
continue;
}
$new_dir = $dir.$new_dir["name"]."/";
$res = $this->_rm_dir_recursive($new_dir);
if ($this->isError($res)) {
return $res;
}
}
$res = $this->_rm_dir($dir);
if (PEAR::isError($res)) {
return $res;
} else {
return true;
}
}
 
/**
* Lists up files and directories
*
* @access private
* @param string $dir The directory to list up
* @return array An array of dirs and files
*/
function _ls_both($dir)
{
$list_splitted = $this->_list_and_parse($dir);
if (PEAR::isError($list_splitted)) {
return $list_splitted;
}
if (!is_array($list_splitted["files"])) {
$list_splitted["files"] = array();
}
if (!is_array($list_splitted["dirs"])) {
$list_splitted["dirs"] = array();
}
$res = array();
@array_splice($res, 0, 0, $list_splitted["files"]);
@array_splice($res, 0, 0, $list_splitted["dirs"]);
return $res;
}
 
/**
* Lists up directories
*
* @access private
* @param string $dir The directory to list up
* @return array An array of dirs
*/
function _ls_dirs($dir)
{
$list = $this->_list_and_parse($dir);
if (PEAR::isError($list)) {
return $list;
}
return $list["dirs"];
}
 
/**
* Lists up files
*
* @access private
* @param string $dir The directory to list up
* @return array An array of files
*/
function _ls_files($dir)
{
$list = $this->_list_and_parse($dir);
if (PEAR::isError($list)) {
return $list;
}
return $list["files"];
}
 
/**
* This lists up the directory-content and parses the items into well-formated arrays
* The results of this array are sorted (dirs on top, sorted by name;
* files below, sorted by name).
*
* @access private
* @param string $dir The directory to parse
* @return array Lists of dirs and files
* @see NET_FTP_ERR_RAWDIRLIST_FAILED
*/
function _list_and_parse($dir)
{
$dirs_list = array();
$files_list = array();
$dir_list = @ftp_rawlist($this->_handle, $dir);
if (!is_array($dir_list)) {
return PEAR::raiseError('Could not get raw directory listing.', NET_FTP_ERR_RAWDIRLIST_FAILED);
}
// Handle empty directories
if (count($dir_list) == 0) {
return array('dirs' => $dirs_list, 'files' => $files_list);
}
 
// Exception for some FTP servers seem to return this wiered result instead of an empty list
if (count($dirs_list) == 1 && $dirs_list[0] == 'total 0') {
return array('dirs' => array(), 'files' => $files_list);
}
if (!isset($this->_matcher) || PEAR::isError($this->_matcher)) {
$this->_matcher = $this->_determine_os_match($dir_list);
if (PEAR::isError($this->_matcher)) {
return $this->_matcher;
}
}
foreach ($dir_list as $entry) {
if (!preg_match($this->_matcher['pattern'], $entry, $m)) {
continue;
}
$entry = array();
foreach ($this->_matcher['map'] as $key=>$val) {
$entry[$key] = $m[$val];
}
$entry['stamp'] = $this->_parse_Date($entry['date']);
 
if ($entry['is_dir']) {
$dirs_list[] = $entry;
} else {
$files_list[] = $entry;
}
}
@usort($dirs_list, array("Net_FTP", "_nat_sort"));
@usort($files_list, array("Net_FTP", "_nat_sort"));
$res["dirs"] = (is_array($dirs_list)) ? $dirs_list : array();
$res["files"] = (is_array($files_list)) ? $files_list : array();
return $res;
}
/**
* Determine server OS
* This determines the server OS and returns a valid regex to parse
* ls() output.
*
* @access private
* @param array $dir_list The raw dir list to parse
* @return mixed An array of 'pattern' and 'map' on success, otherwise PEAR::Error
* @see NET_FTP_ERR_DIRLIST_UNSUPPORTED
*/
function _determine_os_match(&$dir_list) {
foreach ($dir_list as $entry) {
foreach ($this->_ls_match as $os => $match) {
if (preg_match($match['pattern'], $entry)) {
return $match;
}
}
}
$error = 'The list style of your server seems not to be supported. Please email a "$ftp->ls(NET_FTP_RAWLIST);" output plus info on the server to the maintainer of this package to get it supported! Thanks for your help!';
return PEAR::raiseError($error, NET_FTP_ERR_DIRLIST_UNSUPPORTED);
}
/**
* Lists a local directory
*
* @access private
* @param string $dir_path The dir to list
* @return array The list of dirs and files
*/
function _ls_local($dir_path)
{
$dir = dir($dir_path);
$dir_list = array();
$file_list = array();
while (false !== ($entry = $dir->read())) {
if (($entry != '.') && ($entry != '..')) {
if (is_dir($dir_path.$entry)) {
$dir_list[] = $entry;
} else {
$file_list[] = $entry;
}
}
}
$dir->close();
$res['dirs'] = $dir_list;
$res['files'] = $file_list;
return $res;
}
 
/**
* Function for use with usort().
* Compares the list-array-elements by name.
*
* @access private
*/
function _nat_sort($item_1, $item_2)
{
return strnatcmp($item_1['name'], $item_2['name']);
}
 
/**
* Parse dates to timestamps
*
* @access private
* @param string $date Date
* @return int Timestamp
* @see NET_FTP_ERR_DATEFORMAT_FAILED
*/
function _parse_Date($date)
{
// Sep 10 22:06 => Sep 10, <year> 22:06
if (preg_match('/([A-Za-z]+)[ ]+([0-9]+)[ ]+([0-9]+):([0-9]+)/', $date, $res)) {
$year = date('Y');
$month = $res[1];
$day = $res[2];
$hour = $res[3];
$minute = $res[4];
$date = "$month $day, $year $hour:$minute";
$tmpDate = strtotime($date);
if ($tmpDate > time()) {
$year--;
$date = "$month $day, $year $hour:$minute";
}
}
// 09-10-04 => 09/10/04
elseif (preg_match('/^\d\d-\d\d-\d\d/',$date)) {
$date = str_replace('-','/',$date);
}
$res = strtotime($date);
if (!$res) {
return $this->raiseError('Dateconversion failed.', NET_FTP_ERR_DATEFORMAT_FAILED);
}
return $res;
}
}
?>
/branches/v1.0-menes/api/pear/Net/URL.php
New file
0,0 → 1,411
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2004, Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard at php net> |
// +-----------------------------------------------------------------------+
//
// $Id: URL.php,v 1.2 2006-03-13 21:00:48 ddelon Exp $
//
// Net_URL Class
 
class Net_URL
{
/**
* Full url
* @var string
*/
var $url;
 
/**
* Protocol
* @var string
*/
var $protocol;
 
/**
* Username
* @var string
*/
var $username;
 
/**
* Password
* @var string
*/
var $password;
 
/**
* Host
* @var string
*/
var $host;
 
/**
* Port
* @var integer
*/
var $port;
 
/**
* Path
* @var string
*/
var $path;
 
/**
* Query string
* @var array
*/
var $querystring;
 
/**
* Anchor
* @var string
*/
var $anchor;
 
/**
* Whether to use []
* @var bool
*/
var $useBrackets;
 
/**
* PHP4 Constructor
*
* @see __construct()
*/
function Net_URL($url = null, $useBrackets = true)
{
$this->__construct($url, $useBrackets);
}
 
/**
* PHP5 Constructor
*
* Parses the given url and stores the various parts
* Defaults are used in certain cases
*
* @param string $url Optional URL
* @param bool $useBrackets Whether to use square brackets when
* multiple querystrings with the same name
* exist
*/
function __construct($url = null, $useBrackets = true)
{
$HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
 
$this->useBrackets = $useBrackets;
$this->url = $url;
$this->user = '';
$this->pass = '';
$this->host = '';
$this->port = 80;
$this->path = '';
$this->querystring = array();
$this->anchor = '';
 
// Only use defaults if not an absolute URL given
if (!preg_match('/^[a-z0-9]+:\/\//i', $url)) {
 
$this->protocol = 'http';
 
/**
* Figure out host/port
*/
if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) AND preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches)) {
$host = $matches[1];
if (!empty($matches[3])) {
$port = $matches[3];
} else {
$port = $this->getStandardPort($this->protocol);
}
}
 
$this->user = '';
$this->pass = '';
$this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
$this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
$this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
$this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
$this->anchor = '';
}
 
// Parse the url and store the various parts
if (!empty($url)) {
$urlinfo = parse_url($url);
 
// Default querystring
$this->querystring = array();
 
foreach ($urlinfo as $key => $value) {
switch ($key) {
case 'scheme':
$this->protocol = $value;
$this->port = $this->getStandardPort($value);
break;
 
case 'user':
case 'pass':
case 'host':
case 'port':
$this->$key = $value;
break;
 
case 'path':
if ($value{0} == '/') {
$this->path = $value;
} else {
$path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
$this->path = sprintf('%s/%s', $path, $value);
}
break;
 
case 'query':
$this->querystring = $this->_parseRawQueryString($value);
break;
 
case 'fragment':
$this->anchor = $value;
break;
}
}
}
}
 
/**
* Returns full url
*
* @return string Full url
* @access public
*/
function getURL()
{
$querystring = $this->getQueryString();
 
$this->url = $this->protocol . '://'
. $this->user . (!empty($this->pass) ? ':' : '')
. $this->pass . (!empty($this->user) ? '@' : '')
. $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
. $this->path
. (!empty($querystring) ? '?' . $querystring : '')
. (!empty($this->anchor) ? '#' . $this->anchor : '');
 
return $this->url;
}
 
/**
* Adds a querystring item
*
* @param string $name Name of item
* @param string $value Value of item
* @param bool $preencoded Whether value is urlencoded or not, default = not
* @access public
*/
function addQueryString($name, $value, $preencoded = false)
{
if ($preencoded) {
$this->querystring[$name] = $value;
} else {
$this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
}
}
 
/**
* Removes a querystring item
*
* @param string $name Name of item
* @access public
*/
function removeQueryString($name)
{
if (isset($this->querystring[$name])) {
unset($this->querystring[$name]);
}
}
 
/**
* Sets the querystring to literally what you supply
*
* @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc
* @access public
*/
function addRawQueryString($querystring)
{
$this->querystring = $this->_parseRawQueryString($querystring);
}
 
/**
* Returns flat querystring
*
* @return string Querystring
* @access public
*/
function getQueryString()
{
if (!empty($this->querystring)) {
foreach ($this->querystring as $name => $value) {
if (is_array($value)) {
foreach ($value as $k => $v) {
$querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
}
} elseif (!is_null($value)) {
$querystring[] = $name . '=' . $value;
} else {
$querystring[] = $name;
}
}
$querystring = implode(ini_get('arg_separator.output'), $querystring);
} else {
$querystring = '';
}
 
return $querystring;
}
 
/**
* Parses raw querystring and returns an array of it
*
* @param string $querystring The querystring to parse
* @return array An array of the querystring data
* @access private
*/
function _parseRawQuerystring($querystring)
{
$parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
$return = array();
 
foreach ($parts as $part) {
if (strpos($part, '=') !== false) {
$value = substr($part, strpos($part, '=') + 1);
$key = substr($part, 0, strpos($part, '='));
} else {
$value = null;
$key = $part;
}
if (substr($key, -2) == '[]') {
$key = substr($key, 0, -2);
if (@!is_array($return[$key])) {
$return[$key] = array();
$return[$key][] = $value;
} else {
$return[$key][] = $value;
}
} elseif (!$this->useBrackets AND !empty($return[$key])) {
$return[$key] = (array)$return[$key];
$return[$key][] = $value;
} else {
$return[$key] = $value;
}
}
 
return $return;
}
 
/**
* Resolves //, ../ and ./ from a path and returns
* the result. Eg:
*
* /foo/bar/../boo.php => /foo/boo.php
* /foo/bar/../../boo.php => /boo.php
* /foo/bar/.././/boo.php => /foo/boo.php
*
* This method can also be called statically.
*
* @param string $url URL path to resolve
* @return string The result
*/
function resolvePath($path)
{
$path = explode('/', str_replace('//', '/', $path));
 
for ($i=0; $i<count($path); $i++) {
if ($path[$i] == '.') {
unset($path[$i]);
$path = array_values($path);
$i--;
 
} elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
unset($path[$i]);
unset($path[$i-1]);
$path = array_values($path);
$i -= 2;
 
} elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
unset($path[$i]);
$path = array_values($path);
$i--;
 
} else {
continue;
}
}
 
return implode('/', $path);
}
 
/**
* Returns the standard port number for a protocol
*
* @param string $scheme The protocol to lookup
* @return integer Port number or NULL if no scheme matches
*
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
*/
function getStandardPort($scheme)
{
switch (strtolower($scheme)) {
case 'http': return 80;
case 'https': return 443;
case 'ftp': return 21;
case 'imap': return 143;
case 'imaps': return 993;
case 'pop3': return 110;
case 'pop3s': return 995;
default: return null;
}
}
 
/**
* Forces the URL to a particular protocol
*
* @param string $protocol Protocol to force the URL to
* @param integer $port Optional port (standard port is used by default)
*/
function setProtocol($protocol, $port = null)
{
$this->protocol = $protocol;
$this->port = is_null($port) ? $this->getStandardPort() : $port;
}
 
}
?>
/branches/v1.0-menes/api/pear/Auth.php
New file
0,0 → 1,869
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Martin Jansen <mj@php.net> |
// +----------------------------------------------------------------------+
//
// $Id: Auth.php,v 1.1 2005-03-30 08:50:19 jpm Exp $
//
 
require_once 'PEAR.php';
 
define('AUTH_IDLED', -1);
define('AUTH_EXPIRED', -2);
define('AUTH_WRONG_LOGIN', -3);
 
/**
* PEAR::Auth
*
* The PEAR::Auth class provides methods for creating an
* authentication system using PHP.
*
* @author Martin Jansen <mj@php.net>
* @package Auth
* @version $Revision: 1.1 $
*/
class Auth {
 
/**
* Auth lifetime in seconds
*
* If this variable is set to 0, auth never expires
*
* @var integer
* @see setExpire(), checkAuth()
*/
var $expire = 0;
 
/**
* Has the auth session expired?
*
* @var bool
* @see checkAuth(), drawLogin()
*/
var $expired = false;
 
/**
* Maximum time of idleness in seconds
*
* The difference to $expire is, that the idletime gets
* refreshed each time, checkAuth() is called. If this
* variable is set to 0, idle time is never checked.
*
* @var integer
* @see setIdle(), checkAuth()
*/
var $idle = 0;
 
/**
* Is the maximum idletime over?
*
* @var boolean
* @see checkAuth(), drawLogin();
*/
var $idled = false;
 
/**
* Storage object
*
* @var object
* @see Auth(), validateLogin()
*/
var $storage = '';
 
/**
* Function defined by the user, that creates the login screen
*
* @var string
*/
var $loginFunction = '';
 
/**
* Should the login form be displayed?
*
* @var bool
* @see setShowlogin()
*/
var $showLogin = true;
 
/**
* Current authentication status
*
* @var string
*/
var $status = '';
 
/**
* Username
*
* @var string
*/
var $username = '';
 
/**
* Password
*
* @var string
*/
var $password = '';
 
/**
* Login callback function name
*
* @var string
* @see setLoginCallback()
*/
var $loginCallback = '';
 
/**
* Failed Login callback function name
*
* @var string
* @see setLoginFailedCallback()
*/
var $loginFailedCallback = '';
 
/**
* Logout callback function name
*
* @var string
* @see setLogoutCallback()
*/
var $logoutCallback = '';
 
/**
* Auth session-array name
*
* @var string
*/
var $_sessionName = '_authsession';
/**
* Package Version
*
* @var string
*/
var $version = "1.2.3";
 
// {{{ Constructor
 
/**
* Constructor
*
* Set up the storage driver.
*
* @param string Type of the storage driver
* @param mixed Additional options for the storage driver
* (example: if you are using DB as the storage
* driver, you have to pass the dsn string here)
*
* @param string Name of the function that creates the login form
* @param boolean Should the login form be displayed if neccessary?
* @return void
*/
function Auth($storageDriver, $options = '', $loginFunction = '', $showLogin = true)
{
if (!empty($options['sessionName'])) {
$this->_sessionName = $options['sessionName'];
unset($options['sessionName']);
}
 
if ($loginFunction != '' && is_callable($loginFunction)) {
$this->loginFunction = $loginFunction;
}
 
if (is_bool($showLogin)) {
$this->showLogin = $showLogin;
}
 
if (is_object($storageDriver)) {
$this->storage =& $storageDriver;
} else {
$this->storage = $this->_factory($storageDriver, $options);
}
// Pass a reference to auth to the container, ugly but works
// this is used by the DB container to use method setAuthData not staticaly.
$this->storage->_auth_obj =& $this;
}
 
// }}}
// {{{ _factory()
 
/**
* Return a storage driver based on $driver and $options
*
* @access private
* @static
* @param string $driver Type of storage class to return
* @param string $options Optional parameters for the storage class
* @return object Object Storage object
*/
function _factory($driver, $options = '')
{
$storage_path = 'Auth/Container/' . $driver . '.php';
$storage_class = 'Auth_Container_' . $driver;
 
require_once $storage_path;
 
return new $storage_class($options);
}
 
// }}}
// {{{ assignData()
 
/**
* Assign data from login form to internal values
*
* This function takes the values for username and password
* from $HTTP_POST_VARS and assigns them to internal variables.
* If you wish to use another source apart from $HTTP_POST_VARS,
* you have to derive this function.
*
* @access private
* @global $HTTP_POST_VARS
* @see Auth
* @return void
*/
function assignData()
{
$post = &$this->_importGlobalVariable('post');
 
if (isset($post['username']) && $post['username'] != '') {
$this->username = (get_magic_quotes_gpc() == 1 ? stripslashes($post['username']) : $post['username']);
}
 
if (isset($post['password']) && $post['password'] != '') {
$this->password = (get_magic_quotes_gpc() == 1 ? stripslashes($post['password']) : $post['password'] );
}
 
}
 
// }}}
// {{{ start()
 
/**
* Start new auth session
*
* @access public
* @return void
*/
function start()
{
$this->assignData();
 
@session_start();
 
if (!$this->checkAuth()) {
$this->login();
}
}
 
// }}}
// {{{ login()
 
/**
* Login function
*
* @access private
* @return void
*/
function login()
{
$login_ok = false;
 
/**
* When the user has already entered a username,
* we have to validate it.
*/
if (!empty($this->username)) {
if (true === $this->storage->fetchData($this->username, $this->password)) {
$login_ok = true;
} else {
if (is_callable($this->loginFailedCallback)) {
call_user_func($this->loginFailedCallback,$this->username, $this);
}
}
}
 
if (!empty($this->username) && $login_ok) {
$this->setAuth($this->username);
if (is_callable($this->loginCallback)) {
call_user_func($this->loginCallback,$this->username, $this);
}
}
 
/**
* If the login failed or the user entered no username,
* output the login screen again.
*/
if (!empty($this->username) && !$login_ok) {
$this->status = AUTH_WRONG_LOGIN;
}
 
if ((empty($this->username) || !$login_ok) && $this->showLogin) {
$this->drawLogin($this->storage->activeUser);
return;
}
}
 
// }}}
// {{{ setExpire()
 
/**
* Set the maximum expire time
*
* @access public
* @param integer time in seconds
* @param bool add time to current expire time or not
* @return void
*/
function setExpire($time, $add = false)
{
if ($add) {
$this->expire += $time;
} else {
$this->expire = $time;
}
}
 
// }}}
// {{{ setIdle()
 
/**
* Set the maximum idle time
*
* @access public
* @param integer time in seconds
* @param bool add time to current maximum idle time or not
* @return void
*/
function setIdle($time, $add = false)
{
if ($add) {
$this->idle += $time;
} else {
$this->idle = $time;
}
}
 
// }}}
// {{{ setSessionname()
 
/**
* Set name of the session to a customized value.
*
* If you are using multiple instances of PEAR::Auth
* on the same domain, you can change the name of
* session per application via this function.
*
* @access public
* @param string New name for the session
* @return void
*/
function setSessionname($name = 'PHPSESSID')
{
@session_name($name);
}
 
// }}}
// {{{ setShowLogin()
 
/**
* Should the login form be displayed if neccessary?
*
* @access public
* @param bool show login form or not
* @return void
*/
function setShowLogin($showLogin = true)
{
$this->showLogin = $showLogin;
}
 
/**
* Register a callback function to be called on user login.
* The function will receive two parameters, the username and a reference to the auth object.
*
* @access public
* @param string callback function name
* @return void
* @see setLogoutCallback()
*/
function setLoginCallback($loginCallback)
{
$this->loginCallback = $loginCallback;
}
 
/**
* Register a callback function to be called on failed user login.
* The function will receive a single parameter, the username and a reference to the auth object.
*
* @access public
* @param string callback function name
* @return void
*/
function setFailedLoginCallback($loginFailedCallback)
{
$this->loginFailedCallback = $loginFailedCallback;
}
 
/**
* Register a callback function to be called on user logout.
* The function will receive three parameters, the username and a reference to the auth object.
*
* @access public
* @param string callback function name
* @return void
* @see setLoginCallback()
*/
function setLogoutCallback($logoutCallback)
{
$this->logoutCallback = $logoutCallback;
}
 
// }}}
// {{{ setAuthData()
 
/**
* Register additional information that is to be stored
* in the session.
*
* @access public
* @param string Name of the data field
* @param mixed Value of the data field
* @param boolean Should existing data be overwritten? (default
* is true)
* @return void
*/
function setAuthData($name, $value, $overwrite = true)
{
$session = &Auth::_importGlobalVariable('session');
 
if (!empty($session[$this->_sessionName]['data'][$name]) && $overwrite == false) {
return;
}
$session[$this->_sessionName]['data'][$name] = $value;
}
 
// }}}
// {{{ getAuthData()
 
/**
* Get additional information that is stored in the session.
*
* If no value for the first parameter is passed, the method will
* return all data that is currently stored.
*
* @access public
* @param string Name of the data field
* @return mixed Value of the data field.
*/
function getAuthData($name = null)
{
$session = &Auth::_importGlobalVariable('session');
if(!isset($session[$this->_sessionName]['data'])){
return(null);
}
 
if (is_null($name)) {
if(isset($session[$this->_sessionName]['data'])) {
return $session[$this->_sessionName]['data'];
} else {
return null;
}
}
if (isset($session[$this->_sessionName]['data'][$name])) {
return $session[$this->_sessionName]['data'][$name];
} else {
return null;
}
}
 
// }}}
// {{{ setAuth()
 
/**
* Register variable in a session telling that the user
* has logged in successfully
*
* @access public
* @param string Username
* @return void
*/
function setAuth($username)
{
$session = &Auth::_importGlobalVariable('session');
 
if (!isset($session[$this->_sessionName]) && !isset($_SESSION)) {
session_register($this->_sessionName);
}
 
if (!isset($session[$this->_sessionName]) || !is_array($session[$this->_sessionName])) {
$session[$this->_sessionName] = array();
}
 
if(!isset($session[$this->_sessionName]['data'])){
$session[$this->_sessionName]['data'] = array();
}
$session[$this->_sessionName]['registered'] = true;
$session[$this->_sessionName]['username'] = $username;
$session[$this->_sessionName]['timestamp'] = time();
$session[$this->_sessionName]['idle'] = time();
}
 
// }}}
// {{{ checkAuth()
 
/**
* Checks if there is a session with valid auth information.
*
* @access private
* @return boolean Whether or not the user is authenticated.
*/
function checkAuth()
{
$session = &$this->_importGlobalVariable('session');
 
if (isset($session[$this->_sessionName])) {
// Check if authentication session is expired
if ($this->expire > 0 &&
isset($session[$this->_sessionName]['timestamp']) &&
($session[$this->_sessionName]['timestamp'] + $this->expire) < time()) {
 
$this->logout();
$this->expired = true;
$this->status = AUTH_EXPIRED;
 
return false;
}
 
// Check if maximum idle time is reached
if ($this->idle > 0 &&
isset($session[$this->_sessionName]['idle']) &&
($session[$this->_sessionName]['idle'] + $this->idle) < time()) {
 
$this->logout();
$this->idled = true;
$this->status = AUTH_IDLED;
 
return false;
}
 
if (isset($session[$this->_sessionName]['registered']) &&
isset($session[$this->_sessionName]['username']) &&
$session[$this->_sessionName]['registered'] == true &&
$session[$this->_sessionName]['username'] != '') {
 
Auth::updateIdle();
 
return true;
}
}
 
return false;
}
 
// }}}
// {{{ getAuth()
 
/**
* Has the user been authenticated?
*
* @access public
* @return bool True if the user is logged in, otherwise false.
*/
function getAuth()
{
$session = &$this->_importGlobalVariable('session');
 
if (!empty($session) &&
(isset($session[$this->_sessionName]['registered']) &&
$session[$this->_sessionName]['registered'] === true))
{
return true;
} else {
return false;
}
}
 
// }}}
// {{{ drawLogin()
 
/**
* Draw the login form
*
* Normally you will not use this output in your application,
* because you can pass a different function name to the
* constructor. For more information on this, please
* consult the documentation.
*
* @access private
* @param string Username if already entered
* @return void
*/
function drawLogin($username = '')
{
if (is_callable($this->loginFunction)) {
call_user_func($this->loginFunction, $username, $this->status, $this);
} else {
$server = &$this->_importGlobalVariable('server');
 
echo '<center>'."\n";
 
if (!empty($this->status) && $this->status == AUTH_EXPIRED) {
echo '<i>Your session expired. Please login again!</i>'."\n";
} else if (!empty($this->status) && $this->status == AUTH_IDLED) {
echo '<i>You have been idle for too long. Please login again!</i>'."\n";
} else if (!empty ($this->status) && $this->status == AUTH_WRONG_LOGIN) {
echo '<i>Wrong login data!</i>'."\n";
}
 
PEAR::raiseError('You are using the built-in login screen of PEAR::Auth.<br />See the <a href="http://pear.php.net/manual/">manual</a> for details on how to create your own login function.', null);
 
echo '<form method="post" action="' . $server['PHP_SELF'] . '">'."\n";
echo '<table border="0" cellpadding="2" cellspacing="0" summary="login form">'."\n";
echo '<tr>'."\n";
echo ' <td colspan="2" bgcolor="#eeeeee"><b>Login:</b></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo ' <td>Username:</td>'."\n";
echo ' <td><input type="text" name="username" value="' . $username . '" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo ' <td>Password:</td>'."\n";
echo ' <td><input type="password" name="password" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo ' <td colspan="2" bgcolor="#eeeeee"><input type="submit" /></td>'."\n";
echo '</tr>'."\n";
echo '</table>'."\n";
echo '</form>'."\n";
echo '</center>'."\n\n";
}
}
 
// }}}
// {{{ logout()
 
/**
* Logout function
*
* This function clears any auth tokens in the currently
* active session and executes the logout callback function,
* if any
*
* @access public
* @return void
*/
function logout()
{
$session = &$this->_importGlobalVariable('session');
 
if (is_callable($this->logoutCallback)) {
call_user_func($this->logoutCallback, $session[$this->_sessionName]['username'], $this);
}
 
$this->username = '';
$this->password = '';
 
$session[$this->_sessionName] = array();
if (isset($_SESSION)) {
unset($session[$this->_sessionName]);
} else {
session_unregister($this->_sessionName);
}
}
 
// }}}
// {{{ updateIdle()
 
/**
* Update the idletime
*
* @access private
* @return void
*/
function updateIdle()
{
$session = &$this->_importGlobalVariable('session');
$session[$this->_sessionName]['idle'] = time();
}
 
// }}}
// {{{ getUsername()
 
/**
* Get the username
*
* @access public
* @return string
*/
function getUsername()
{
$session = &$this->_importGlobalVariable('session');
if (!isset($session[$this->_sessionName]['username'])) {
return '';
}
return $session[$this->_sessionName]['username'];
}
 
// }}}
// {{{ getStatus()
 
/**
* Get the current status
*
* @access public
* @return string
*/
function getStatus()
{
return $this->status;
}
 
// }}}
// {{{ sessionValidThru()
 
/**
* Returns the time up to the session is valid
*
* @access public
* @return integer
*/
function sessionValidThru()
{
$session = &$this->_importGlobalVariable('session');
if (!isset($session[$this->_sessionName]['idle'])) {
return 0;
}
return ($session[$this->_sessionName]['idle'] + $this->idle);
}
 
// }}}
// {{{ listUsers()
 
/**
* List all users that are currently available in the storage
* container
*
* @access public
* @return array
*/
function listUsers()
{
return $this->storage->listUsers();
}
 
// }}}
// {{{ addUser()
 
/**
* Add user to the storage container
*
* @access public
* @param string Username
* @param string Password
* @param mixed Additional parameters
* @return mixed True on success, PEAR error object on error
* and AUTH_METHOD_NOT_SUPPORTED otherwise.
*/
function addUser($username, $password, $additional = '')
{
return $this->storage->addUser($username, $password, $additional);
}
 
// }}}
// {{{ removeUser()
 
/**
* Remove user from the storage container
*
* @access public
* @param string Username
* @return mixed True on success, PEAR error object on error
* and AUTH_METHOD_NOT_SUPPORTED otherwise.
*/
function removeUser($username)
{
return $this->storage->removeUser($username);
}
 
// }}}
// {{{ _importGlobalVariable()
 
/**
* Import variables from special namespaces.
*
* @access private
* @param string Type of variable (server, session, post)
* @return array
*/
function &_importGlobalVariable($variable)
{
$var = null;
 
switch (strtolower($variable)) {
 
case 'server' :
if (isset($_SERVER)) {
$var = &$_SERVER;
} else {
$var = &$GLOBALS['HTTP_SERVER_VARS'];
}
break;
 
case 'session' :
if (isset($_SESSION)) {
$var = &$_SESSION;
} else {
$var = &$GLOBALS['HTTP_SESSION_VARS'];
}
break;
 
case 'post' :
if (isset($_POST)) {
$var = &$_POST;
} else {
$var = &$GLOBALS['HTTP_POST_VARS'];
}
break;
 
case 'cookie' :
if (isset($_COOKIE)) {
$var = &$_COOKIE;
} else {
$var = &$GLOBALS['HTTP_COOKIE_VARS'];
}
break;
 
case 'get' :
if (isset($_GET)) {
$var = &$_GET;
} else {
$var = &$GLOBALS['HTTP_GET_VARS'];
}
break;
 
default:
break;
 
}
 
return $var;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Mail.php
New file
0,0 → 1,211
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: Mail.php,v 1.1 2005-11-24 16:15:46 florian Exp $
 
require_once 'PEAR.php';
 
/**
* PEAR's Mail:: interface. Defines the interface for implementing
* mailers under the PEAR hierarchy, and provides supporting functions
* useful in multiple mailer backends.
*
* @access public
* @version $Revision: 1.1 $
* @package Mail
*/
class Mail
{
/**
* Line terminator used for separating header lines.
* @var string
*/
var $sep = "\r\n";
 
/**
* Provides an interface for generating Mail:: objects of various
* types
*
* @param string $driver The kind of Mail:: object to instantiate.
* @param array $params The parameters to pass to the Mail:: object.
* @return object Mail a instance of the driver class or if fails a PEAR Error
* @access public
*/
function &factory($driver, $params = array())
{
$driver = strtolower($driver);
@include_once 'Mail/' . $driver . '.php';
$class = 'Mail_' . $driver;
if (class_exists($class)) {
$mailer = new $class($params);
return $mailer;
} else {
return PEAR::raiseError('Unable to find class for driver ' . $driver);
}
}
 
/**
* Implements Mail::send() function using php's built-in mail()
* command.
*
* @param mixed $recipients Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid. This may contain recipients not
* specified in the headers, for Bcc:, resending
* messages, etc.
*
* @param array $headers The array of headers to send with the mail, in an
* associative array, where the array key is the
* header name (ie, 'Subject'), and the array value
* is the header value (ie, 'test'). The header
* produced from those values would be 'Subject:
* test'.
*
* @param string $body The full text of the message body, including any
* Mime parts, etc.
*
* @return mixed Returns true on success, or a PEAR_Error
* containing a descriptive error message on
* failure.
* @access public
* @deprecated use Mail_mail::send instead
*/
function send($recipients, $headers, $body)
{
// if we're passed an array of recipients, implode it.
if (is_array($recipients)) {
$recipients = implode(', ', $recipients);
}
 
// get the Subject out of the headers array so that we can
// pass it as a seperate argument to mail().
$subject = '';
if (isset($headers['Subject'])) {
$subject = $headers['Subject'];
unset($headers['Subject']);
}
 
// flatten the headers out.
list(,$text_headers) = Mail::prepareHeaders($headers);
 
return mail($recipients, $subject, $body, $text_headers);
 
}
 
/**
* Take an array of mail headers and return a string containing
* text usable in sending a message.
*
* @param array $headers The array of headers to prepare, in an associative
* array, where the array key is the header name (ie,
* 'Subject'), and the array value is the header
* value (ie, 'test'). The header produced from those
* values would be 'Subject: test'.
*
* @return mixed Returns false if it encounters a bad address,
* otherwise returns an array containing two
* elements: Any From: address found in the headers,
* and the plain text version of the headers.
* @access private
*/
function prepareHeaders($headers)
{
$lines = array();
$from = null;
 
foreach ($headers as $key => $value) {
if (strcasecmp($key, 'From') === 0) {
include_once 'Mail/RFC822.php';
$parser = &new Mail_RFC822();
$addresses = $parser->parseAddressList($value, 'localhost', false);
if (PEAR::isError($addresses)) {
return $addresses;
}
 
$from = $addresses[0]->mailbox . '@' . $addresses[0]->host;
 
// Reject envelope From: addresses with spaces.
if (strstr($from, ' ')) {
return false;
}
 
$lines[] = $key . ': ' . $value;
} elseif (strcasecmp($key, 'Received') === 0) {
$received = array();
if (is_array($value)) {
foreach ($value as $line) {
$received[] = $key . ': ' . $line;
}
}
else {
$received[] = $key . ': ' . $value;
}
// Put Received: headers at the top. Spam detectors often
// flag messages with Received: headers after the Subject:
// as spam.
$lines = array_merge($received, $lines);
} else {
// If $value is an array (i.e., a list of addresses), convert
// it to a comma-delimited string of its elements (addresses).
if (is_array($value)) {
$value = implode(', ', $value);
}
$lines[] = $key . ': ' . $value;
}
}
 
return array($from, join($this->sep, $lines) . $this->sep);
}
 
/**
* Take a set of recipients and parse them, returning an array of
* bare addresses (forward paths) that can be passed to sendmail
* or an smtp server with the rcpt to: command.
*
* @param mixed Either a comma-seperated list of recipients
* (RFC822 compliant), or an array of recipients,
* each RFC822 valid.
*
* @return array An array of forward paths (bare addresses).
* @access private
*/
function parseRecipients($recipients)
{
include_once 'Mail/RFC822.php';
 
// if we're passed an array, assume addresses are valid and
// implode them before parsing.
if (is_array($recipients)) {
$recipients = implode(', ', $recipients);
}
 
// Parse recipients, leaving out all personal info. This is
// for smtp recipients, etc. All relevant personal information
// should already be in the headers.
$addresses = Mail_RFC822::parseAddressList($recipients, 'localhost', false);
$recipients = array();
if (is_array($addresses)) {
foreach ($addresses as $ob) {
$recipients[] = $ob->mailbox . '@' . $ob->host;
}
}
 
return $recipients;
}
 
}
/branches/v1.0-menes/api/pear/A_LIRE.txt
New file
0,0 → 1,16
Liste des packages PEAR :
==============================
Package Version State
Auth 1.2.3 stable
Calendar 0.5.2 beta
DB 1.7.6 stable
HTML_Common 1.2.1 stable
HTML_QuickForm 3.2.5 stable
HTML_Table 1.5 stable
HTTP 1.3.5 stable
Net_FTP 1.3.0 stable
Net_SMTP 1.2.6 stable
Net_Socket 1.0.6 stable
Net_URL 1.0.14 stable
PEAR 1.3.5 stable
Text_Wiki 1.0.0 stable
/branches/v1.0-menes/api/pear/Calendar/Week.php
New file
0,0 → 1,410
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Week.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Week.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Week and builds Days in tabular format<br>
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Week.php';
* $Week = & new Calendar_Week(2003, 10, 1); Oct 2003, 1st tabular week
* echo '<tr>';
* while ($Day = & $Week->fetch()) {
* if ($Day->isEmpty()) {
* echo '<td>&nbsp;</td>';
* } else {
* echo '<td>'.$Day->thisDay().'</td>';
* }
* }
* echo '</tr>';
* </code>
* @package Calendar
* @access public
*/
class Calendar_Week extends Calendar
{
/**
* Instance of Calendar_Table_Helper
* @var Calendar_Table_Helper
* @access private
*/
var $tableHelper;
 
/**
* Stores the timestamp of the first day of this week
* @access private
* @var object
*/
var $thisWeek;
 
/**
* Stores the timestamp of first day of previous week
* @access private
* @var object
*/
var $prevWeek;
 
/**
* Stores the timestamp of first day of next week
* @access private
* @var object
*/
var $nextWeek;
 
/**
* Used by build() to set empty days
* @access private
* @var boolean
*/
var $firstWeek = false;
 
/**
* Used by build() to set empty days
* @access private
* @var boolean
*/
var $lastWeek = false;
 
/**
* First day of the week (0=sunday, 1=monday...)
* @access private
* @var boolean
*/
var $firstDay = 1;
 
/**
* Constructs Week
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int a day of the desired week
* @param int (optional) first day of week (e.g. 0 for Sunday, 2 for Tuesday etc.)
* @access public
*/
function Calendar_Week($y, $m, $d, $firstDay=false)
{
require_once CALENDAR_ROOT.'Table'.DIRECTORY_SEPARATOR.'Helper.php';
Calendar::Calendar($y, $m, $d);
if ($firstDay !== false) {
$this->firstDay = $firstDay;
}
$this->tableHelper = & new Calendar_Table_Helper($this, $firstDay);
$this->thisWeek = $this->tableHelper->getWeekStart($y, $m, $d, $firstDay);
$this->prevWeek = $this->tableHelper->getWeekStart($y, $m, $d - $this->cE->getDaysInWeek(
$this->thisYear(),
$this->thisMonth(),
$this->thisDay()), $firstDay);
$this->nextWeek = $this->tableHelper->getWeekStart($y, $m, $d + $this->cE->getDaysInWeek(
$this->thisYear(),
$this->thisMonth(),
$this->thisDay()), $firstDay);
}
 
/**
* Defines the calendar by a timestamp (Unix or ISO-8601), replacing values
* passed to the constructor
* @param int|string Unix or ISO-8601 timestamp
* @return void
* @access public
*/
function setTimestamp($ts)
{
+
+ $this->thisWeek = $this->tableHelper->getWeekStart(
+ $this->year, $this->month, $this->day, $this->firstDay
+
+ $this->prevWeek = $this->tableHelper->getWeekStart(
+ $this->year, $this->month, $this->day - $this->cE->getDaysInWeek(
+ $this->thisYear(),
+ $this->thisMonth(),
+ $this->thisDay()), $this->firstDay
+
+ $this->nextWeek = $this->tableHelper->getWeekStart(
+ $this->year, $this->month, $this->day + $this->cE->getDaysInWeek(
+ $this->thisYear(),
+ $this->thisMonth(),
+ $this->thisDay()), $this->firstDay
+ );
+ }
+
+ /**
+ * Builds Calendar_Day objects for this Week
+ * @param array (optional) Calendar_Day objects representing selected dates
+ * @return boolean
+ * @access public
+ */
+ function build($sDates = array())
+ {
+ require_once CALENDAR_ROOT.'Day.php';
+ $year = $this->cE->stampToYear($this->thisWeek);
+ $month = $this->cE->stampToMonth($this->thisWeek);
+ $day = $this->cE->stampToDay($this->thisWeek);
+ $end = $this->cE->getDaysInWeek(
+ $this->thisYear(),
+ $this->thisMonth(),
+ $this->thisDay()
+ );
+
+ for ($i=1; $i <= $end; $i++) {
+ $stamp = $this->cE->dateToStamp($year, $month, $day++);
+ $this->children[$i] = new Calendar_Day(
+ $this->cE->stampToYear($stamp),
+ $this->cE->stampToMonth($stamp),
+ $this->cE->stampToDay($stamp));
+ }
+
+ //set empty days (@see Calendar_Month_Weeks::build())
+ if ($this->firstWeek) {
+ $eBefore = $this->tableHelper->getEmptyDaysBefore();
+ for ($i=1; $i <= $eBefore; $i++) {
+ $this->children[$i]->setEmpty();
+ }
+ }
+ if ($this->lastWeek) {
+ $eAfter = $this->tableHelper->getEmptyDaysAfterOffset();
+ for ($i = $eAfter+1; $i <= $end; $i++) {
+ $this->children[$i]->setEmpty();
+ }
+ }
+
+ if (count($sDates) > 0) {
+ $this->setSelection($sDates);
+ }
+ return true;
+ }
+
+ /**
+ * @param boolean
+ * @return void
+ * @access private
+ */
+ function setFirst($state=true)
+ {
+ $this->firstWeek = $state;
+ }
+
+ /**
+ * @param boolean
+ * @return void
+ * @access private
+ */
+ function setLast($state=true)
+ {
+ $this->lastWeek = $state;
+ }
+
+ /**
+ * Called from build()
+ * @param array
+ * @return void
+ * @access private
+ */
+ function setSelection($sDates)
+ {
+
+
+
+
+ $child->thisYear() == $sDate->thisYear()
+
+
+
+
+
+
+
+ }
+
+ /**
+ * Gets the value of the previous week, according to the requested format
+ *
+ * @param string $format ['timestamp' | 'n_in_month' | 'n_in_year' | 'array']
+ * @return mixed
+ * @access public
+ */
+ function prevWeek($format = 'n_in_month')
+ {
+ switch (strtolower($format)) {
+ case 'int':
+ case 'n_in_month':
+ return ($this->firstWeek) ? null : $this->thisWeek('n_in_month') -1;
+ break;
+ case 'n_in_year':
+ return $this->cE->getWeekNInYear(
+ $this->cE->stampToYear($this->prevWeek),
+ $this->cE->stampToMonth($this->prevWeek),
+ $this->cE->stampToDay($this->prevWeek));
+ break;
+ case 'array':
+ return $this->toArray($this->prevWeek);
+ break;
+ case 'object':
+ require_once CALENDAR_ROOT.'Factory.php';
+ return Calendar_Factory::createByTimestamp('Week',$this->prevWeek);
+ break;
+ case 'timestamp':
+ default:
+ return $this->prevWeek;
+ break;
+ }
+ }
+
+ /**
+ * Gets the value of the current week, according to the requested format
+ *
+ * @param string $format ['timestamp' | 'n_in_month' | 'n_in_year' | 'array']
+ * @return mixed
+ * @access public
+ */
+ function thisWeek($format = 'n_in_month')
+ {
+ switch (strtolower($format)) {
+ case 'int':
+ case 'n_in_month':
+ if ($this->firstWeek) {
+ return 1;
+ }
+ if ($this->lastWeek) {
+ return $this->cE->getWeeksInMonth(
+ $this->cE->stampToYear($this->thisWeek),
+ $this->cE->stampToMonth($this->thisWeek),
+ $this->firstDay);
+ }
+ return $this->cE->getWeekNInMonth(
+ $this->cE->stampToYear($this->thisWeek),
+ $this->cE->stampToMonth($this->thisWeek),
+ $this->cE->stampToDay($this->thisWeek),
+ $this->firstDay);
+ break;
+ case 'n_in_year':
+ return $this->cE->getWeekNInYear(
+ $this->cE->stampToYear($this->thisWeek),
+ $this->cE->stampToMonth($this->thisWeek),
+ $this->cE->stampToDay($this->thisWeek));
+ break;
+ case 'array':
+ return $this->toArray($this->thisWeek);
+ break;
+ case 'object':
+ require_once CALENDAR_ROOT.'Factory.php';
+ return Calendar_Factory::createByTimestamp('Week',$this->thisWeek);
+ break;
+ case 'timestamp':
+ default:
+ return $this->thisWeek;
+ break;
+ }
+ }
+
+ /**
+ * Gets the value of the following week, according to the requested format
+ *
+ * @param string $format ['timestamp' | 'n_in_month' | 'n_in_year' | 'array']
+ * @return mixed
+ * @access public
+ */
+ function nextWeek($format = 'n_in_month')
+ {
+ switch (strtolower($format)) {
+ case 'int':
+ case 'n_in_month':
+ return ($this->lastWeek) ? null : $this->thisWeek('n_in_month') +1;
+ break;
+ case 'n_in_year':
+ return $this->cE->getWeekNInYear(
+ $this->cE->stampToYear($this->nextWeek),
+ $this->cE->stampToMonth($this->nextWeek),
+ $this->cE->stampToDay($this->nextWeek));
+ break;
+ case 'array':
+ return $this->toArray($this->nextWeek);
+ break;
+ case 'object':
+ require_once CALENDAR_ROOT.'Factory.php';
+ return Calendar_Factory::createByTimestamp('Week',$this->nextWeek);
+ break;
+ case 'timestamp':
+ default:
+ return $this->nextWeek;
+ break;
+ }
+ }
+
+ /**
+ * Returns the instance of Calendar_Table_Helper.
+ * Called from Calendar_Validator::isValidWeek
+ * @return Calendar_Table_Helper
+ * @access protected
+ */
+ function & getHelper()
+ {
+ return $this->tableHelper;
+ }
+
+ /**
+ * Makes sure theres a value for $this->day
+ * @return void
+ * @access private
+ */
+ function findFirstDay()
+ {
+ if (!count($this->children) > 0) {
+ $this->build();
+ foreach ($this->children as $Day) {
+ if (!$Day->isEmpty()) {
+ $this->day = $Day->thisDay();
+ break;
+ }
+ }
+ }
+ }
+}
+?>
\ No newline at end of file
/branches/v1.0-menes/api/pear/Calendar/Decorator/Textual.php
New file
0,0 → 1,169
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Textual.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Textual.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar decorator base class
*/
require_once CALENDAR_ROOT.'Decorator.php';
 
/**
* Load the Uri utility
*/
require_once CALENDAR_ROOT.'Util'.DIRECTORY_SEPARATOR.'Textual.php';
 
/**
* Decorator to help with fetching textual representations of months and
* days of the week.
* <b>Note:</b> for performance you should prefer Calendar_Util_Textual unless you
* have a specific need to use a decorator
* @package Calendar
* @access public
*/
class Calendar_Decorator_Textual extends Calendar_Decorator
{
/**
* Constructs Calendar_Decorator_Textual
* @param object subclass of Calendar
* @access public
*/
function Calendar_Decorator_Textual(&$Calendar)
{
parent::Calendar_Decorator($Calendar);
}
 
/**
* Returns an array of 12 month names (first index = 1)
* @param string (optional) format of returned months (one,two,short or long)
* @return array
* @access public
* @static
*/
function monthNames($format='long')
{
return Calendar_Util_Textual::monthNames($format);
}
 
/**
* Returns an array of 7 week day names (first index = 0)
* @param string (optional) format of returned days (one,two,short or long)
* @return array
* @access public
* @static
*/
function weekdayNames($format='long')
{
return Calendar_Util_Textual::weekdayNames($format);
}
 
/**
* Returns textual representation of the previous month of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function prevMonthName($format='long')
{
return Calendar_Util_Textual::prevMonthName($this->calendar,$format);
}
 
/**
* Returns textual representation of the month of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function thisMonthName($format='long')
{
return Calendar_Util_Textual::thisMonthName($this->calendar,$format);
}
 
/**
* Returns textual representation of the next month of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function nextMonthName($format='long')
{
return Calendar_Util_Textual::nextMonthName($this->calendar,$format);
}
 
/**
* Returns textual representation of the previous day of week of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function prevDayName($format='long')
{
return Calendar_Util_Textual::prevDayName($this->calendar,$format);
}
 
/**
* Returns textual representation of the day of week of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function thisDayName($format='long')
{
return Calendar_Util_Textual::thisDayName($this->calendar,$format);
}
 
/**
* Returns textual representation of the next day of week of the decorated calendar object
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
*/
function nextDayName($format='long')
{
return Calendar_Util_Textual::nextDayName($this->calendar,$format);
}
 
/**
* Returns the days of the week using the order defined in the decorated
* calendar object. Only useful for Calendar_Month_Weekdays, Calendar_Month_Weeks
* and Calendar_Week. Otherwise the returned array will begin on Sunday
* @param string (optional) format of returned months (one,two,short or long)
* @return array ordered array of week day names
* @access public
*/
function orderedWeekdays($format='long')
{
return Calendar_Util_Textual::orderedWeekdays($this->calendar,$format);
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Decorator/Weekday.php
New file
0,0 → 1,148
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Weekday.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Weekday.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar decorator base class
*/
require_once CALENDAR_ROOT.'Decorator.php';
 
/**
* Load a Calendar_Day
*/
require_once CALENDAR_ROOT.'Day.php';
/**
* Decorator for fetching the day of the week
* <code>
* $Day = new Calendar_Day(2003, 10, 23);
* $Weekday = & new Calendar_Decorator_Weekday($Day);
* $Weekday->setFirstDay(0); // Set first day of week to Sunday (default Mon)
* echo $Weekday->thisWeekDay(); // Displays 5 - fifth day of week relative to Sun
* </code>
* @package Calendar
* @access public
*/
class Calendar_Decorator_Weekday extends Calendar_Decorator
{
/**
* First day of week
* @var int (default = 1 for Monday)
* @access private
*/
var $firstDay = 1;
 
/**
* Constructs Calendar_Decorator_Weekday
* @param object subclass of Calendar
* @access public
*/
function Calendar_Decorator_Weekday(& $Calendar)
{
parent::Calendar_Decorator($Calendar);
}
 
/**
* Sets the first day of the week (0 = Sunday, 1 = Monday (default) etc)
* @param int first day of week
* @return void
* @access public
*/
function setFirstDay($firstDay) {
$this->firstDay = (int)$firstDay;
}
 
/**
* Returns the previous weekday
* @param string (default = 'int') return value format
* @return int numeric day of week or timestamp
* @access public
*/
function prevWeekDay($format = 'int')
{
$ts = $this->calendar->prevDay('timestamp');
$Day = new Calendar_Day(2000,1,1);
$Day->setTimeStamp($ts);
$day = $this->calendar->cE->getDayOfWeek($Day->thisYear(),$Day->thisMonth(),$Day->thisDay());
$day = $this->adjustWeekScale($day);
return $this->returnValue('Day', $format, $ts, $day);
}
 
/**
* Returns the current weekday
* @param string (default = 'int') return value format
* @return int numeric day of week or timestamp
* @access public
*/
function thisWeekDay($format = 'int')
{
$ts = $this->calendar->thisDay('timestamp');
$day = $this->calendar->cE->getDayOfWeek($this->calendar->year,$this->calendar->month,$this->calendar->day);
$day = $this->adjustWeekScale($day);
return $this->returnValue('Day', $format, $ts, $day);
}
 
/**
* Returns the next weekday
* @param string (default = 'int') return value format
* @return int numeric day of week or timestamp
* @access public
*/
function nextWeekDay($format = 'int')
{
$ts = $this->calendar->nextDay('timestamp');
$Day = new Calendar_Day(2000,1,1);
$Day->setTimeStamp($ts);
$day = $this->calendar->cE->getDayOfWeek($Day->thisYear(),$Day->thisMonth(),$Day->thisDay());
$day = $this->adjustWeekScale($day);
return $this->returnValue('Day', $format, $ts, $day);
}
 
/**
* Adjusts the day of the week relative to the first day of the week
* @param int day of week calendar from Calendar_Engine
* @return int day of week adjusted to first day
* @access private
*/
function adjustWeekScale($dayOfWeek) {
$dayOfWeek = $dayOfWeek - $this->firstDay;
if ( $dayOfWeek >= 0 ) {
return $dayOfWeek;
} else {
return $this->calendar->cE->getDaysInWeek(
$this->calendar->year,$this->calendar->month,$this->calendar->day
) + $dayOfWeek;
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Decorator/Uri.php
New file
0,0 → 1,151
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Uri.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Uri.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar decorator base class
*/
require_once CALENDAR_ROOT.'Decorator.php';
 
/**
* Load the Uri utility
*/
require_once CALENDAR_ROOT.'Util'.DIRECTORY_SEPARATOR.'Uri.php';
 
/**
* Decorator to help with building HTML links for navigating the calendar<br />
* <b>Note:</b> for performance you should prefer Calendar_Util_Uri unless you
* have a specific need to use a decorator
* <code>
* $Day = new Calendar_Day(2003, 10, 23);
* $Uri = & new Calendar_Decorator_Uri($Day);
* $Uri->setFragments('year', 'month', 'day');
* echo $Uri->getPrev(); // Displays year=2003&month=10&day=22
* </code>
* @see Calendar_Util_Uri
* @package Calendar
* @access public
*/
class Calendar_Decorator_Uri extends Calendar_Decorator
{
 
/**
* @var Calendar_Util_Uri
* @access private
*/
var $Uri;
 
/**
* Constructs Calendar_Decorator_Uri
* @param object subclass of Calendar
* @access public
*/
function Calendar_Decorator_Uri(&$Calendar)
{
parent::Calendar_Decorator($Calendar);
}
 
/**
* Sets the URI fragment names
* @param string URI fragment for year
* @param string (optional) URI fragment for month
* @param string (optional) URI fragment for day
* @param string (optional) URI fragment for hour
* @param string (optional) URI fragment for minute
* @param string (optional) URI fragment for second
* @return void
* @access public
*/
function setFragments($y, $m=null, $d=null, $h=null, $i=null, $s=null) {
$this->Uri = & new Calendar_Util_Uri($y, $m, $d, $h, $i, $s);
}
 
/**
* Sets the separator string between fragments
* @param string separator e.g. /
* @return void
* @access public
*/
function setSeparator($separator)
{
$this->Uri->separator = $separator;
}
 
/**
* Puts Uri decorator into "scalar mode" - URI variable names are not
* returned
* @param boolean (optional)
* @return void
* @access public
*/
function setScalar($state=true)
{
$this->Uri->scalar = $state;
}
 
/**
* Gets the URI string for the previous calendar unit
* @param string calendar unit to fetch uri for (year,month,week or day etc)
* @return string
* @access public
*/
function prev($method)
{
return $this->Uri->prev($this, $method);
}
 
/**
* Gets the URI string for the current calendar unit
* @param string calendar unit to fetch uri for (year,month,week or day etc)
* @return string
* @access public
*/
function this($method)
{
return $this->Uri->this($this, $method);
}
 
/**
* Gets the URI string for the next calendar unit
* @param string calendar unit to fetch uri for (year,month,week or day etc)
* @return string
* @access public
*/
function next($method)
{
return $this->Uri->next($this, $method);
}
 
}
?>
/branches/v1.0-menes/api/pear/Calendar/Decorator/Wrapper.php
New file
0,0 → 1,89
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Wrapper.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Wrapper.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar decorator base class
*/
require_once CALENDAR_ROOT.'Decorator.php';
 
/**
* Decorator to help with wrapping built children in another decorator
* @package Calendar
* @access public
*/
class Calendar_Decorator_Wrapper extends Calendar_Decorator
{
/**
* Constructs Calendar_Decorator_Wrapper
* @param object subclass of Calendar
* @access public
*/
function Calendar_Decorator_Wrapper(&$Calendar)
{
parent::Calendar_Decorator($Calendar);
}
 
/**
* Wraps objects returned from fetch in the named Decorator class
* @param string name of Decorator class to wrap with
* @return object instance of named decorator
* @access public
*/
function & fetch($decorator)
{
$Calendar = parent::fetch();
if ($Calendar) {
return new $decorator($Calendar);
} else {
return false;
}
}
 
/**
* Wraps the returned calendar objects from fetchAll in the named decorator
* @param string name of Decorator class to wrap with
* @return array
* @access public
*/
function fetchAll($decorator)
{
$children = parent::fetchAll();
foreach ($children as $key => $Calendar) {
$children[$key] = & new $decorator($Calendar);
}
return $children;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Month/Weekdays.php
New file
0,0 → 1,188
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Weekdays.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Weekdays.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Load base month
*/
require_once CALENDAR_ROOT.'Month.php';
 
/**
* Represents a Month and builds Days in tabular form<br>
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Month'.DIRECTORY_SEPARATOR.'Weekdays.php';
* $Month = & new Calendar_Month_Weekdays(2003, 10); // Oct 2003
* $Month->build(); // Build Calendar_Day objects
* while ($Day = & $Month->fetch()) {
* if ($Day->isFirst()) {
* echo '<tr>';
* }
* if ($Day->isEmpty()) {
* echo '<td>&nbsp;</td>';
* } else {
* echo '<td>'.$Day->thisDay().'</td>';
* }
* if ($Day->isLast()) {
* echo '</tr>';
* }
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Month_Weekdays extends Calendar_Month
{
/**
* Instance of Calendar_Table_Helper
* @var Calendar_Table_Helper
* @access private
*/
var $tableHelper;
 
/**
* First day of the week
* @access private
* @var string
*/
var $firstDay;
 
/**
* Constructs Calendar_Month_Weekdays
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int (optional) first day of week (e.g. 0 for Sunday, 2 for Tuesday etc.)
* @access public
*/
function Calendar_Month_Weekdays($y, $m, $firstDay=false)
{
Calendar_Month::Calendar_Month($y, $m);
$this->firstDay = $firstDay;
}
 
/**
* Builds Day objects in tabular form, to allow display of calendar month
* with empty cells if the first day of the week does not fall on the first
* day of the month.
* @see Calendar_Day::isEmpty()
* @see Calendar_Day_Base::isFirst()
* @see Calendar_Day_Base::isLast()
* @param array (optional) Calendar_Day objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates=array())
{
require_once CALENDAR_ROOT.'Table'.DIRECTORY_SEPARATOR.'Helper.php';
$this->tableHelper = & new Calendar_Table_Helper($this, $this->firstDay);
Calendar_Month::build($sDates);
$this->buildEmptyDaysBefore();
$this->shiftDays();
$this->buildEmptyDaysAfter();
$this->setWeekMarkers();
return true;
}
 
/**
* Prepends empty days before the real days in the month
* @return void
* @access private
*/
function buildEmptyDaysBefore()
{
$eBefore = $this->tableHelper->getEmptyDaysBefore();
for ($i=0; $i < $eBefore; $i++) {
$stamp = $this->cE->dateToStamp($this->year, $this->month, -$i);
$Day = new Calendar_Day(
$this->cE->stampToYear($stamp),
$this->cE->stampToMonth($stamp),
$this->cE->stampToDay($stamp));
$Day->setEmpty();
array_unshift($this->children, $Day);
}
}
 
/**
* Shifts the array of children forward, if necessary
* @return void
* @access private
*/
function shiftDays()
{
if (isset ($this->children[0])) {
array_unshift($this->children, null);
unset($this->children[0]);
}
}
 
/**
* Appends empty days after the real days in the month
* @return void
* @access private
*/
function buildEmptyDaysAfter()
{
$eAfter = $this->tableHelper->getEmptyDaysAfter();
$sDOM = $this->tableHelper->getNumTableDaysInMonth();
for ($i = 1; $i <= $sDOM-$eAfter; $i++) {
$Day = new Calendar_Day($this->year, $this->month+1, $i);
$Day->setEmpty();
array_push($this->children, $Day);
}
}
 
/**
* Sets the "markers" for the beginning and of a of week, in the
* built Calendar_Day children
* @return void
* @access private
*/
function setWeekMarkers()
{
$dIW = $this->cE->getDaysInWeek(
$this->thisYear(),
$this->thisMonth(),
$this->thisDay()
);
$sDOM = $this->tableHelper->getNumTableDaysInMonth();
for ($i=1; $i <= $sDOM; $i+= $dIW) {
$this->children[$i]->setFirst();
$this->children[$i+($dIW-1)]->setLast();
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Month/Weeks.php
New file
0,0 → 1,140
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Weeks.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Weeks.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Load base month
*/
require_once CALENDAR_ROOT.'Month.php';
 
/**
* Represents a Month and builds Weeks
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Month'.DIRECTORY_SEPARATOR.'Weeks.php';
* $Month = & new Calendar_Month_Weeks(2003, 10); // Oct 2003
* $Month->build(); // Build Calendar_Day objects
* while ($Week = & $Month->fetch()) {
* echo $Week->thisWeek().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Month_Weeks extends Calendar_Month
{
/**
* Instance of Calendar_Table_Helper
* @var Calendar_Table_Helper
* @access private
*/
var $tableHelper;
 
/**
* First day of the week
* @access private
* @var string
*/
var $firstDay;
 
/**
* Constructs Calendar_Month_Weeks
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int (optional) first day of week (e.g. 0 for Sunday, 2 for Tuesday etc.)
* @access public
*/
function Calendar_Month_Weeks($y, $m, $firstDay=false)
{
Calendar_Month::Calendar_Month($y, $m);
$this->firstDay = $firstDay;
}
 
/**
* Builds Calendar_Week objects for the Month. Note that Calendar_Week
* builds Calendar_Day object in tabular form (with Calendar_Day->empty)
* @param array (optional) Calendar_Week objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates=array())
{
require_once CALENDAR_ROOT.'Table'.DIRECTORY_SEPARATOR.'Helper.php';
$this->tableHelper = & new Calendar_Table_Helper($this, $this->firstDay);
require_once CALENDAR_ROOT.'Week.php';
$numWeeks = $this->tableHelper->getNumWeeks();
for ($i=1, $d=1; $i<=$numWeeks; $i++,
$d+=$this->cE->getDaysInWeek(
$this->thisYear(),
$this->thisMonth(),
$this->thisDay()) ) {
$this->children[$i] = new Calendar_Week(
$this->year, $this->month, $d, $this->tableHelper->getFirstDay());
}
//used to set empty days
$this->children[1]->setFirst(true);
$this->children[$numWeeks]->setLast(true);
 
// Handle selected weeks here
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates)
{
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()
&& $this->month == $sDate->thisMonth())
{
$key = $sDate->thisWeek('n_in_month');
if (isset($this->children[$key])) {
$this->children[$key]->setSelected();
}
}
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Year.php
New file
0,0 → 1,119
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Year.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Year.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Year and builds Months<br>
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Year.php';
* $Year = & new Calendar_Year(2003, 10, 21); // 21st Oct 2003
* $Year->build(); // Build Calendar_Month objects
* while ($Month = & $Year->fetch()) {
* echo $Month->thisMonth().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Year extends Calendar
{
/**
* Constructs Calendar_Year
* @param int year e.g. 2003
* @access public
*/
function Calendar_Year($y)
{
Calendar::Calendar($y);
}
 
/**
* Builds the Months of the Year.<br>
* <b>Note:</b> by defining the constant CALENDAR_MONTH_STATE you can
* control what class of Calendar_Month is built e.g.;
* <code>
* require_once 'Calendar/Calendar_Year.php';
* define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKDAYS); // Use Calendar_Month_Weekdays
* // define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKS); // Use Calendar_Month_Weeks
* // define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH); // Use Calendar_Month
* </code>
* It defaults to building Calendar_Month objects.
* @param array (optional) array of Calendar_Month objects representing selected dates
* @param int (optional) first day of week (e.g. 0 for Sunday, 2 for Tuesday etc.)
* @return boolean
* @access public
*/
function build($sDates = array(), $firstDay = null)
{
require_once CALENDAR_ROOT.'Factory.php';
if (is_null($firstDay)) {
$firstDay = $this->cE->getFirstDayOfWeek(
$this->thisYear(),
$this->thisMonth(),
$this->thisDay()
);
}
$monthsInYear = $this->cE->getMonthsInYear($this->thisYear());
for ($i=1; $i <= $monthsInYear; $i++) {
$this->children[$i] = Calendar_Factory::create('Month',$this->year,$i);
}
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates) {
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()) {
$key = $sDate->thisMonth();
if (isset($this->children[$key])) {
$sDate->setSelected();
$this->children[$key] = $sDate;
}
}
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Minute.php
New file
0,0 → 1,114
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Minute.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Minute.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Minute and builds Seconds
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Minute.php';
* $Minute = & new Calendar_Minute(2003, 10, 21, 15, 31); // Oct 21st 2003, 3:31pm
* $Minute->build(); // Build Calendar_Second objects
* while ($Second = & $Minute->fetch()) {
* echo $Second->thisSecond().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Minute extends Calendar
{
/**
* Constructs Minute
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int day e.g. 11
* @param int hour e.g. 13
* @param int minute e.g. 31
* @access public
*/
function Calendar_Minute($y, $m, $d, $h, $i)
{
Calendar::Calendar($y, $m, $d, $h, $i);
}
 
/**
* Builds the Calendar_Second objects
* @param array (optional) Calendar_Second objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates=array())
{
require_once CALENDAR_ROOT.'Second.php';
$sIM = $this->cE->getSecondsInMinute($this->year, $this->month,
$this->day, $this->hour, $this->minute);
for ($i=0; $i < $sIM; $i++) {
$this->children[$i] = new Calendar_Second($this->year, $this->month,
$this->day, $this->hour, $this->minute, $i);
}
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates)
{
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()
&& $this->month == $sDate->thisMonth()
&& $this->day == $sDate->thisDay()
&& $this->hour == $sDate->thisHour()
&& $this->minute == $sDate->thisMinute())
{
$key = (int)$sDate->thisSecond();
if (isset($this->children[$key])) {
$sDate->setSelected();
$this->children[$key] = $sDate;
}
}
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Table/Helper.php
New file
0,0 → 1,280
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Helper.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Helper.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Used by Calendar_Month_Weekdays, Calendar_Month_Weeks and Calendar_Week to
* help with building the calendar in tabular form
* @package Calendar
* @access protected
*/
class Calendar_Table_Helper
{
/**
* Instance of the Calendar object being helped.
* @var object
* @access private
*/
var $calendar;
 
/**
* Instance of the Calendar_Engine
* @var object
* @access private
*/
var $cE;
 
/**
* First day of the week
* @access private
* @var string
*/
var $firstDay;
 
/**
* The seven days of the week named
* @access private
* @var array
*/
var $weekDays;
 
/**
* Days of the week ordered with $firstDay at the beginning
* @access private
* @var array
*/
var $daysOfWeek = array();
 
/**
* Days of the month built from days of the week
* @access private
* @var array
*/
var $daysOfMonth = array();
 
/**
* Number of weeks in month
* @var int
* @access private
*/
var $numWeeks = null;
 
/**
* Number of emtpy days before real days begin in month
* @var int
* @access private
*/
var $emptyBefore = 0;
 
/**
* Constructs Calendar_Table_Helper
* @param object Calendar_Month_Weekdays, Calendar_Month_Weeks, Calendar_Week
* @param int (optional) first day of the week e.g. 1 for Monday
* @access protected
*/
function Calendar_Table_Helper(& $calendar, $firstDay=false)
{
$this->calendar = & $calendar;
$this->cE = & $calendar->getEngine();
if ($firstDay === false) {
$firstDay = $this->cE->getFirstDayOfWeek(
$this->calendar->thisYear(),
$this->calendar->thisMonth(),
$this->calendar->thisDay()
);
}
$this->firstDay = $firstDay;
$this->setFirstDay();
$this->setDaysOfMonth();
}
 
/**
* Constructs $this->daysOfWeek based on $this->firstDay
* @return void
* @access private
*/
function setFirstDay()
{
$weekDays = $this->cE->getWeekDays(
$this->calendar->thisYear(),
$this->calendar->thisMonth(),
$this->calendar->thisDay()
);
$endDays = array();
$tmpDays = array();
$begin = false;
foreach ($weekDays as $day) {
if ($begin == true) {
$endDays[] = $day;
} else if ($day === $this->firstDay) {
$begin = true;
$endDays[] = $day;
} else {
$tmpDays[] = $day;
}
}
$this->daysOfWeek = array_merge($endDays, $tmpDays);
}
 
/**
* Constructs $this->daysOfMonth
* @return void
* @access private
*/
function setDaysOfMonth()
{
$this->daysOfMonth = $this->daysOfWeek;
$daysInMonth = $this->cE->getDaysInMonth(
$this->calendar->thisYear(), $this->calendar->thisMonth());
$firstDayInMonth = $this->cE->getFirstDayInMonth(
$this->calendar->thisYear(), $this->calendar->thisMonth());
$this->emptyBefore=0;
foreach ($this->daysOfMonth as $dayOfWeek) {
if ($firstDayInMonth == $dayOfWeek) {
break;
}
$this->emptyBefore++;
}
$this->numWeeks = ceil(
($daysInMonth + $this->emptyBefore)
/
$this->cE->getDaysInWeek(
$this->calendar->thisYear(),
$this->calendar->thisMonth(),
$this->calendar->thisDay()
)
);
for ($i=1; $i < $this->numWeeks; $i++) {
$this->daysOfMonth =
array_merge($this->daysOfMonth, $this->daysOfWeek);
}
}
 
/**
* Returns the first day of the month
* @see Calendar_Engine_Interface::getFirstDayOfWeek()
* @return int
* @access protected
*/
function getFirstDay()
{
return $this->firstDay;
}
 
/**
* Returns the order array of days in a week
* @return int
* @access protected
*/
function getDaysOfWeek()
{
return $this->daysOfWeek;
}
 
/**
* Returns the number of tabular weeks in a month
* @return int
* @access protected
*/
function getNumWeeks()
{
return $this->numWeeks;
}
 
/**
* Returns the number of real days + empty days
* @return int
* @access protected
*/
function getNumTableDaysInMonth()
{
return count($this->daysOfMonth);
}
 
/**
* Returns the number of empty days before the real days begin
* @return int
* @access protected
*/
function getEmptyDaysBefore()
{
return $this->emptyBefore;
}
 
/**
* Returns the index of the last real day in the month
* @todo Potential performance optimization with static
* @return int
* @access protected
*/
function getEmptyDaysAfter()
{
// Causes bug when displaying more than one month
// static $index;
// if (!isset($index)) {
$index = $this->getEmptyDaysBefore() + $this->cE->getDaysInMonth(
$this->calendar->thisYear(), $this->calendar->thisMonth());
// }
return $index;
}
 
/**
* Returns the index of the last real day in the month, relative to the
* beginning of the tabular week it is part of
* @return int
* @access protected
*/
function getEmptyDaysAfterOffset()
{
$eAfter = $this->getEmptyDaysAfter();
return $eAfter - (
$this->cE->getDaysInWeek(
$this->calendar->thisYear(),
$this->calendar->thisMonth(),
$this->calendar->thisDay()
) * ($this->numWeeks-1) );
}
 
/**
* Returns the timestamp of the first day of the current week
*/
function getWeekStart($y, $m, $d, $firstDay=1)
{
$dow = $this->cE->getDayOfWeek($y, $m, $d);
if ($dow > $firstDay) {
$d -= ($dow - $firstDay);
}
if ($dow < $firstDay) {
$d -= (
$this->cE->getDaysInWeek(
$this->calendar->thisYear(),
$this->calendar->thisMonth(),
$this->calendar->thisDay()
) - $firstDay + $dow);
}
return $this->cE->dateToStamp($y, $m, $d);
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/docs/Readme
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/Readme
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/4.php
New file
0,0 → 1,49
<?php
/**
* Description: shows how to perform validation with PEAR::Calendar
*/
function getmicrotime(){
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Second.php';
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('n');
if (!isset($_GET['d'])) $_GET['d'] = date('j');
if (!isset($_GET['h'])) $_GET['h'] = date('H');
if (!isset($_GET['i'])) $_GET['i'] = date('i');
if (!isset($_GET['s'])) $_GET['s'] = date('s');
 
$Unit = & new Calendar_Second($_GET['y'], $_GET['m'], $_GET['d'], $_GET['h'], $_GET['i'], $_GET['s']);
 
echo '<p><b>Result:</b> '.$Unit->thisYear().'-'.$Unit->thisMonth().'-'.$Unit->thisDay().
' '.$Unit->thisHour().':'.$Unit->thisMinute().':'.$Unit->thisSecond();
if ($Unit->isValid()) {
echo ' is valid!</p>';
} else {
$V= & $Unit->getValidator();
echo ' is invalid:</p>';
while ($error = $V->fetch()) {
echo $error->toString() .'<br />';
}
}
?>
<p>Enter a date / time to validate:</p>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
Year: <input type="text" name="y" value="2039"><br />
Month: <input type="text" name="m" value="13"><br />
Day: <input type="text" name="d" value="32"><br />
Hour: <input type="text" name="h" value="24"><br />
Minute: <input type="text" name="i" value="-1"><br />
Second: <input type="text" name="s" value="60"><br />
<input type="submit" value="Validate">
</form>
<p><b>Note:</b> Error messages can be controlled with the constants <code>CALENDAR_VALUE_TOOSMALL</code> and <code>CALENDAR_VALUE_TOOLARGE</code> - see <code>Calendar_Validator.php</code></p>
 
<?php echo '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>'; ?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/5.php
New file
0,0 → 1,132
<?php
/**
* Description: generating elements of a form with PEAR::Calendar, using
* selections as well as validating the submission
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Year.php';
require_once CALENDAR_ROOT.'Month.php';
require_once CALENDAR_ROOT.'Day.php';
require_once CALENDAR_ROOT.'Hour.php';
require_once CALENDAR_ROOT.'Minute.php';
require_once CALENDAR_ROOT.'Second.php';
 
// Initialize if not set
if (!isset($_POST['y'])) $_POST['y'] = date('Y');
if (!isset($_POST['m'])) $_POST['m'] = date('n');
if (!isset($_POST['d'])) $_POST['d'] = date('j');
if (!isset($_POST['h'])) $_POST['h'] = date('H');
if (!isset($_POST['i'])) $_POST['i'] = date('i');
if (!isset($_POST['s'])) $_POST['s'] = date('s');
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Select and Update </title>
</head>
<body>
<h1>Select and Update</h1>
<?php
if ( isset($_POST['update']) ) {
$Second = & new Calendar_Second($_POST['y'],$_POST['m'],$_POST['d'],$_POST['h'],$_POST['i'],$_POST['s']);
if ( !$Second->isValid() ) {
$V= & $Second->getValidator();
echo ('<p>Validation failed:</p>' );
while ( $error = $V->fetch() ) {
echo ( $error->toString() .'<br>' );
}
} else {
echo ('<p>Validation success.</p>' );
echo ( '<p>New timestamp is: '.$Second->getTimeStamp().' which could be used to update a database, for example');
}
} else {
$Year = new Calendar_Year($_POST['y']);
$Month = new Calendar_Month($_POST['y'],$_POST['m']);
$Day = new Calendar_Day($_POST['y'],$_POST['m'],$_POST['d']);
$Hour = new Calendar_Hour($_POST['y'],$_POST['m'],$_POST['d'],$_POST['h']);
$Minute = new Calendar_Minute($_POST['y'],$_POST['m'],$_POST['d'],$_POST['h'],$_POST['i']);
$Second = new Calendar_Second($_POST['y'],$_POST['m'],$_POST['d'],$_POST['h'],$_POST['i'],$_POST['s']);
?>
<p><b>Set the alarm clock</p></p>
<form action="<?php echo ( $_SERVER['PHP_SELF'] ); ?>" method="post">
Year: <input type="text" name="y" value="<?php echo ( $_POST['y'] ); ?>" size="4">&nbsp;
Month:<select name="m">
<?php
$selection = array($Month);
$Year->build($selection);
while ( $Child = & $Year->fetch() ) {
if ( $Child->isSelected() ) {
echo ( "<option value=\"".$Child->thisMonth()."\" selected>".$Child->thisMonth()."\n" );
} else {
echo ( "<option value=\"".$Child->thisMonth()."\">".$Child->thisMonth()."\n" );
}
}
?>
</select>&nbsp;
Day:<select name="d">
<?php
$selection = array($Day);
$Month->build($selection);
while ( $Child = & $Month->fetch() ) {
if ( $Child->isSelected() ) {
echo ( "<option value=\"".$Child->thisDay()."\" selected>".$Child->thisDay()."\n" );
} else {
echo ( "<option value=\"".$Child->thisDay()."\">".$Child->thisDay()."\n" );
}
}
?>
</select>&nbsp;
Hour:<select name="h">
<?php
$selection = array($Hour);
$Day->build($selection);
while ( $Child = & $Day->fetch() ) {
if ( $Child->isSelected() ) {
echo ( "<option value=\"".$Child->thisHour()."\" selected>".$Child->thisHour()."\n" );
} else {
echo ( "<option value=\"".$Child->thisHour()."\">".$Child->thisHour()."\n" );
}
}
?>
</select>&nbsp;
Minute:<select name="i">
<?php
$selection = array($Minute);
$Hour->build($selection);
while ( $Child = & $Hour->fetch() ) {
if ( $Child->isSelected() ) {
echo ( "<option value=\"".$Child->thisMinute()."\" selected>".$Child->thisMinute()."\n" );
} else {
echo ( "<option value=\"".$Child->thisMinute()."\">".$Child->thisMinute()."\n" );
}
}
?>
</select>&nbsp;
Second:<select name="s">
<?php
$selection = array($Second);
$Minute->build($selection);
while ( $Child = & $Minute->fetch() ) {
if ( $Child->isSelected() ) {
echo ( "<option value=\"".$Child->thisSecond()."\" selected>".$Child->thisSecond()."\n" );
} else {
echo ( "<option value=\"".$Child->thisSecond()."\">".$Child->thisSecond()."\n" );
}
}
?>
</select>&nbsp;
<input type="submit" name="update" value="Set Alarm"><br>
<?php
}
?>
<?php echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' ); ?>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/11.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/11.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/6.php
New file
0,0 → 1,210
<?php
/**
* Description: A "personal planner" with some WML for fun
* Note this is done the stupid way - a giant if/else for WML or HTML
* could be greatly simplified with some HTML/WML rendering classes...
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Day.php';
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('n');
if (!isset($_GET['d'])) $_GET['d'] = date('j');
 
$Month = & new Calendar_Month_Weekdays($_GET['y'],$_GET['m']);
$Day = & new Calendar_Day($_GET['y'],$_GET['m'],$_GET['d']);
$selection = array($Day);
 
#-----------------------------------------------------------------------------#
if ( isset($_GET['mime']) && $_GET['mime']=='wml' ) {
header ('Content-Type: text/vnd.wap.wml');
echo ( '<?xml version="1.0"?>' );
?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<big><strong>Personal Planner Rendered with WML</strong></big>
<?php
if ( isset($_GET['viewday']) ) {
?>
<p><strong>Viewing <?php echo ( date('l, jS of F, Y',$Day->getTimeStamp()) ); ?></strong></p>
<p>
<anchor>
Back to Month View
<go href="<?php
echo ( "?y=".$Day->thisYear()."&amp;m=".
$Day->thisMonth()."&amp;d=".$Day->thisDay()."&amp;mime=wml" );
?>"/>
</anchor>
</p>
<table>
<?php
$Day->build();
while ( $Hour = & $Day->fetch() ) {
echo ( "<tr>\n" );
echo ( "<td>".date('g a',$Hour->getTimeStamp())."</td><td>Free time!</td>\n" );
echo ( "</tr>\n" );
}
?>
</table>
<?php
} else {
?>
<p><strong><?php echo ( date('F Y',$Month->getTimeStamp()) ); ?></strong></p>
<table>
<tr>
<td>M</td><td>T</td><td>W</td><td>T</td><td>F</td><td>S</td><td>S</td>
</tr>
<?php
$Month->build($selection);
while ( $Day = $Month->fetch() ) {
if ( $Day->isFirst() ) {
echo ( "<tr>\n" );
}
if ( $Day->isEmpty() ) {
echo ( "<td></td>\n" );
} else if ( $Day->isSelected() ) {
echo ( "<td><anchor><strong><u>".$Day->thisDay()."</u></strong>\n<go href=\"".$_SERVER['PHP_SELF']."?viewday=true&amp;y=".
$Day->thisYear()."&amp;m=".$Day->thisMonth()."&amp;d=".$Day->thisDay().
"&amp;mime=wml\" />\n</anchor></td>\n" );
} else {
echo ( "<td><anchor>".$Day->thisDay()."\n<go href=\"?viewday=true&amp;y=".
$Day->thisYear()."&amp;m=".$Day->thisMonth()."&amp;d=".$Day->thisDay().
"&amp;mime=wml\" /></anchor></td>\n" );
}
if ( $Day->isLast() ) {
echo ( "</tr>\n" );
}
}
?>
<tr>
<td>
<anchor>
&lt;&lt;
<go href="<?php
echo ( "?y=".$Month->thisYear()."&amp;m=".
$Month->prevMonth()."&amp;d=".$Month->thisDay()."&amp;mime=wml" );
?>"/>
</anchor>
</td>
<td></td><td></td><td></td><td></td><td></td>
<td>
<anchor>
&gt;&gt;
<go href="<?php
echo ( "?y=".$Month->thisYear()."&amp;m=".
$Month->nextMonth()."&amp;d=".$Month->thisDay()."&amp;mime=wml" );
?>"/>
</anchor>
</td>
</tr>
</table>
 
<?php
}
?>
<p><a href="<?php echo ( $_SERVER['PHP_SELF'] ); ?>">Back to HTML</a></p>
<?php echo ( '<p>Took: '.(getmicrotime()-$start).' seconds</p>' ); ?>
</wml>
<?php
#-----------------------------------------------------------------------------#
} else {
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> HTML (+WML) Personal Planner </title>
</head>
<body>
<h1>Personal Planner Rendered with HTML</h1>
<p>To view in WML, click <a href="<?php echo ( $_SERVER['PHP_SELF'] ); ?>?mime=wml">here</a> or place a ?mime=wml at the end of any URL.
Note that <a href="http://www.opera.com/download">Opera</a> supports WML natively and Mozilla / Firefox has the WMLBrowser
plugin: <a href="http://wmlbrowser.mozdev.org">wmlbrowser.mozdev.org</a></p>
<?php
if ( isset($_GET['viewday']) ) {
?>
<p><strong>Viewing <?php echo ( date('l, jS of F, Y',$Day->getTimeStamp()) ); ?></strong></p>
<p>
<anchor>
<a href="<?php
echo ( "?y=".$Day->thisYear()."&amp;m=".
$Day->thisMonth()."&amp;d=".$Day->thisDay());
?>">Back to Month View</a>
</p>
<table>
<?php
$Day->build();
while ( $Hour = & $Day->fetch() ) {
echo ( "<tr>\n" );
echo ( "<td>".date('g a',$Hour->getTimeStamp())."</td><td>Free time!</td>\n" );
echo ( "</tr>\n" );
}
?>
</table>
<?php
} else {
?>
<p><strong><?php echo ( date('F Y',$Month->getTimeStamp()) ); ?></strong></p>
<table>
<tr>
<td>M</td><td>T</td><td>W</td><td>T</td><td>F</td><td>S</td><td>S</td>
</tr>
<?php
$Month->build($selection);
while ( $Day = $Month->fetch() ) {
if ( $Day->isFirst() ) {
echo ( "<tr>\n" );
}
if ( $Day->isEmpty() ) {
echo ( "<td></td>\n" );
} else if ( $Day->isSelected() ) {
echo ( "<td><a href=\"".$_SERVER['PHP_SELF']."?viewday=true&amp;y=".
$Day->thisYear()."&amp;m=".$Day->thisMonth()."&amp;d=".$Day->thisDay().
"&amp;wml\"><strong><u>".$Day->thisDay()."</u></strong></a></td>\n" );
} else {
echo ( "<td><a href=\"".$_SERVER['PHP_SELF']."?viewday=true&amp;y=".
$Day->thisYear()."&amp;m=".$Day->thisMonth()."&amp;d=".$Day->thisDay().
"\">".$Day->thisDay()."</a></td>\n" );
}
if ( $Day->isLast() ) {
echo ( "</tr>\n" );
}
}
?>
<tr>
<td>
<a href="<?php
echo ( "?y=".$Month->thisYear()."&amp;m=".
$Month->prevMonth()."&amp;d=".$Month->thisDay() );
?>">
&lt;&lt;</a>
</td>
<td></td><td></td><td></td><td></td><td></td>
<td>
<a href="<?php
echo ( "?y=".$Month->thisYear()."&amp;m=".
$Month->nextMonth()."&amp;d=".$Month->thisDay() );
?>">&gt;&gt;</a>
</td>
</tr>
</table>
 
<?php
}
?>
 
 
<?php echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' ); ?>
</body>
</html>
<?php
}
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/21.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/21.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/13.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/13.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/7.php
New file
0,0 → 1,92
<?php
/**
* Description: a SOAP Calendar Server
*/
if (!@include('SOAP'.DIRECTORY_SEPARATOR.'Server.php')) {
die('You must have PEAR::SOAP installed');
}
 
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
 
class Calendar_Server
{
var $__dispatch_map = array();
var $__typedef = array();
 
function Calendar_Server()
{
$this->__dispatch_map['getMonth'] =
array('in' => array('year' => 'int', 'month'=>'int'),
'out' => array('month' => '{urn:PEAR_SOAP_Calendar}Month'),
);
$this->__typedef['Month'] = array (
'monthname' => 'string',
'days' => '{urn:PEAR_SOAP_Calendar}MonthDays'
);
$this->__typedef['MonthDays'] = array (array ('{urn:PEAR_SOAP_Calendar}Day'));
$this->__typedef['Day'] = array (
'isFirst' => 'int',
'isLast' => 'int',
'isEmpty' => 'int',
'day' => 'int' );
}
 
function __dispatch($methodname)
{
if (isset($this->__dispatch_map[$methodname]))
return $this->__dispatch_map[$methodname];
return NULL;
}
 
function getMonth($year, $month)
{
require_once(CALENDAR_ROOT.'Month'.DIRECTORY_SEPARATOR.'Weekdays.php');
$Month = & new Calendar_Month_Weekdays($year,$month);
if (!$Month->isValid()) {
$V = & $Month->getValidator();
$errorMsg = '';
while ($error = $V->fetch()) {
$errorMsg .= $error->toString()."\n";
}
return new SOAP_Fault($errorMsg, 'Client');
} else {
$monthname = date('F Y', $Month->getTimeStamp());
$days = array();
$Month->build();
while ($Day = & $Month->fetch()) {
$day = array(
'isFirst' => (int)$Day->isFirst(),
'isLast' => (int)$Day->isLast(),
'isEmpty' => (int)$Day->isEmpty(),
'day' => (int)$Day->thisDay(),
);
$days[] = $day;
}
return array('monthname' => $monthname, 'days' => $days);
}
}
}
 
$server = new SOAP_Server();
$server->_auto_translation = true;
$calendar = new Calendar_Server();
$server->addObjectMap($calendar, 'urn:PEAR_SOAP_Calendar');
 
if (strtoupper($_SERVER['REQUEST_METHOD'])=='POST') {
$server->service($GLOBALS['HTTP_RAW_POST_DATA']);
} else {
require_once 'SOAP'.DIRECTORY_SEPARATOR.'Disco.php';
$disco = new SOAP_DISCO_Server($server, "PEAR_SOAP_Calendar");
if (isset($_SERVER['QUERY_STRING']) &&
strcasecmp($_SERVER['QUERY_STRING'], 'wsdl')==0) {
header("Content-type: text/xml");
echo $disco->getWSDL();
} else {
echo 'This is a PEAR::SOAP Calendar Server. For client try <a href="8.php">here</a><br />';
echo 'For WSDL try <a href="?wsdl">here</a>';
}
exit;
}
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/23.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/23.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/8.php
New file
0,0 → 1,70
<?php
/**
* Description: client for the SOAP Calendar Server
*/
if ( version_compare(phpversion(), "5.0.0", ">") ) {
die('PHP 5 has problems with PEAR::SOAP Client (8.0RC3)
- remove @ before include below to see why');
}
 
if (!@include('SOAP'.DIRECTORY_SEPARATOR.'Client.php')) {
die('You must have PEAR::SOAP installed');
}
 
// Just to save manaul modification...
$basePath = explode('/', $_SERVER['SCRIPT_NAME']);
array_pop($basePath);
$basePath = implode('/', $basePath);
$url = 'http://'.$_SERVER['SERVER_NAME'].$basePath.'/7.php?wsdl';
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('n');
 
$wsdl = new SOAP_WSDL ($url);
 
echo ( '<pre>'.$wsdl->generateProxyCode().'</pre>' );
 
$calendarClient = $wsdl->getProxy();
 
$month = $calendarClient->getMonth((int)$_GET['y'],(int)$_GET['m']);
 
if ( PEAR::isError($month) ) {
die ( $month->toString() );
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Calendar over the Wire </title>
</head>
<body>
<h1>Calendar Over the Wire (featuring PEAR::SOAP)</h1>
<table>
<caption><b><?php echo ( $month->monthname );?></b></caption>
<tr>
<th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th>
</tr>
<?php
foreach ( $month->days as $day ) {
 
if ( $day->isFirst === 1 )
echo ( "<tr>\n" );
if ( $day->isEmpty === 1 ) {
echo ( "<td></td>" );
} else {
echo ( "<td>".$day->day."</td>" );
}
if ( $day->isLast === 1 )
echo ( "</tr>\n" );
}
?>
<tr>
</table>
<p>Enter Year and Month to View:</p>
<form action="<?php echo ( $_SERVER['PHP_SELF'] ); ?>" method="get">
Year: <input type="text" size="4" name="y" value="<?php echo ( $_GET['y'] ); ?>">&nbsp;
Month: <input type="text" size="2" name="m" value="<?php echo ( $_GET['m'] ); ?>">&nbsp;
<input type="submit" value="Fetch Calendar">
</form>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/15.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/15.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/9.php
New file
0,0 → 1,16
<?php
/**
* Description: simple example on i18N
*/
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Day.php';
 
$Day = & new Calendar_Day(2003,10,23);
 
setlocale (LC_TIME, "de_DE"); // Unix based (probably)
// setlocale (LC_TIME, "ge"); // Windows
 
echo ( strftime('%A %d %B %Y',$Day->getTimeStamp()));
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/17.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/17.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/19.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/19.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/10.php
New file
0,0 → 1,93
<?php
/**
* Description: demonstrates a decorator to provide simple output formatting
* on the month while still allowing the days to be accessed via the decorator
* In practice you _wouldn't_ do this - each decorator comes with a performance
* hit for extra method calls. For this example some simple functions could help
* format the month while the days are accessed via the normal Month object
*/
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Decorator.php';
 
// Decorate a Month with methods to improve formatting
class MonthDecorator extends Calendar_Decorator {
/**
* @param Calendar_Month
*/
function MonthDecorator(& $Month) {
parent::Calendar_Decorator($Month);
}
/**
* Override the prevMonth method to format the output
*/
function prevMonth() {
$prevStamp = parent::prevMonth(TRUE);
// Build the URL for the previous month
return $_SERVER['PHP_SELF'].'?y='.date('Y',$prevStamp).
'&m='.date('n',$prevStamp).'&d='.date('j',$prevStamp);
}
/**
* Override the thisMonth method to format the output
*/
function thisMonth() {
$thisStamp = parent::thisMonth(TRUE);
// A human readable string from this month
return date('F Y',$thisStamp);
}
/**
* Override the nextMonth method to format the output
*/
function nextMonth() {
$nextStamp = parent::nextMonth(TRUE);
// Build the URL for next month
return $_SERVER['PHP_SELF'].'?y='.date('Y',$nextStamp).
'&m='.date('n',$nextStamp).'&d='.date('j',$nextStamp);
}
}
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('n');
 
// Creata a month as usual
$Month = new Calendar_Month_Weekdays($_GET['y'],$_GET['m']);
 
// Pass it to the decorator and use the decorator from now on...
$MonthDecorator = new MonthDecorator($Month);
$MonthDecorator->build();
?>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> A Simple Decorator </title>
</head>
<body>
<h1>A Simple Decorator</h1>
<table>
<caption><?php echo ( $MonthDecorator->thisMonth() ); ?></caption>
<?php
while ( $Day = $MonthDecorator->fetch() ) {
if ( $Day->isFirst() ) {
echo ( "\n<tr>\n" );
}
if ( $Day->isEmpty() ) {
echo ( "<td>&nbsp;</td>" );
} else {
echo ( "<td>".$Day->thisDay()."</td>" );
}
if ( $Day->isLast() ) {
echo ( "\n</tr>\n" );
}
}
?>
<tr>
<td><a href="<?php echo ($MonthDecorator->prevMonth()); ?>">Prev</a></td>
<td colspan="5">&nbsp;</td>
<td><a href="<?php echo ($MonthDecorator->nextMonth()); ?>">Next</a></td>
</tr>
</table>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/11.php
New file
0,0 → 1,109
<?php
/**
* Description: demonstrates a decorator used to "attach a payload" to a selection
* to make it available when iterating over calendar children
*/
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Day.php';
require_once CALENDAR_ROOT.'Hour.php';
require_once CALENDAR_ROOT.'Decorator.php';
 
// Decorator to "attach" functionality to selected hours
class DiaryEvent extends Calendar_Decorator {
var $entry;
function DiaryEvent($calendar) {
Calendar_Decorator::Calendar_Decorator($calendar);
}
function setEntry($entry) {
$this->entry = $entry;
}
function getEntry() {
return $this->entry;
}
}
 
// Create a day to view the hours for
$Day = & new Calendar_Day(2003,10,24);
 
// A sample query to get the data for today (NOT ACTUALLY USED HERE)
$sql = "
SELECT
*
FROM
diary
WHERE
eventtime >= '".$Day->thisDay(TRUE)."'
AND
eventtime < '".$Day->nextDay(TRUE)."';";
 
// An array simulating data from a database
$result = array (
array('eventtime'=>mktime(9,0,0,10,24,2003),'entry'=>'Meeting with sales team'),
array('eventtime'=>mktime(11,0,0,10,24,2003),'entry'=>'Conference call with Widget Inc.'),
array('eventtime'=>mktime(15,0,0,10,24,2003),'entry'=>'Presentation to board of directors')
);
 
// An array to place selected hours in
$selection = array();
 
// Loop through the "database result"
foreach ( $result as $row ) {
$Hour = new Calendar_Hour(2000,1,1,1); // Create Hour with dummy values
$Hour->setTimeStamp($row['eventtime']); // Set the real time with setTimeStamp
 
// Create the decorator, passing it the Hour
$DiaryEvent = new DiaryEvent($Hour);
 
// Attach the payload
$DiaryEvent->setEntry($row['entry']);
 
// Add the decorator to the selection
$selection[] = $DiaryEvent;
}
 
// Build the hours in that day, passing the selection
$Day->build($selection);
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Passing a Selection Payload with a Decorator </title>
</head>
<body>
<h1>Passing a Selection "Payload" using a Decorator</h1>
<table>
<caption><b>Your Schedule for <?php echo ( date('D nS F Y',$Day->thisDay(TRUE)) ); ?></b></caption>
<tr>
<th width="5%">Time</th>
<th>Entry</th>
</tr>
<?php
while ( $Hour = & $Day->fetch() ) {
 
$hour = $Hour->thisHour();
$minute = $Hour->thisMinute();
 
// Office hours only...
if ( $hour >= 8 && $hour <= 18 ) {
echo ( "<tr>\n" );
echo ( "<td>$hour:$minute</td>\n" );
 
// If the hour is selected, call the decorator method...
if ( $Hour->isSelected() ) {
echo ( "<td bgcolor=\"silver\">".$Hour->getEntry()."</td>\n" );
} else {
echo ( "<td>&nbsp;</td>\n" );
}
echo ( "</tr>\n" );
}
}
?>
</table>
<p>The query to fetch this data, with help from PEAR::Calendar, might be;</p>
<pre>
<?php echo ( $sql ); ?>
</pre>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/12.php
New file
0,0 → 1,116
<?php
/**
* Description: a complete year
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
 
require_once CALENDAR_ROOT.'Year.php';
 
define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKDAYS);
 
if ( !isset($_GET['year']) ) $_GET['year'] = date('Y');
 
$Year = new Calendar_Year($_GET['year']);
 
$Year->build();
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> <?php echo ( $Year->thisYear() ); ?> </title>
<style type="text/css">
body {
font-family: Georgia, serif;
}
caption.year {
font-weight: bold;
font-size: 120%;
font-color: navy;
}
caption.month {
font-size: 110%;
font-color: navy;
}
table.month {
border: thin groove #800080
}
tr {
vertical-align: top;
}
th, td {
text-align: right;
font-size: 70%;
}
#prev {
float: left;
font-size: 70%;
}
#next {
float: right;
font-size: 70%;
}
</style>
</head>
<body>
<table>
<caption class="year">
<?php echo ( $Year->thisYear() ); ?>
<div id="next">
<a href="?year=<?php echo ( $Year->nextYear() ); ?>">>></a>
</div>
<div id="prev">
<a href="?year=<?php echo ( $Year->prevYear() ); ?>"><<</a>
</div>
</caption>
<?php
$i = 0;
while ( $Month = $Year->fetch() ) {
 
switch ( $i ) {
case 0:
echo ( "<tr>\n" );
break;
case 3:
case 6:
case 9:
echo ( "</tr>\n<tr>\n" );
break;
case 12:
echo ( "</tr>\n" );
break;
}
 
echo ( "<td>\n<table class=\"month\">\n" );
echo ( "<caption class=\"month\">".date('F',$Month->thisMonth(TRUE))."</caption>" );
echo ( "<tr>\n<th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th>\n</tr>" );
$Month->build();
while ( $Day = $Month->fetch() ) {
if ( $Day->isFirst() ) {
echo ( "<tr>\n" );
}
if ( $Day->isEmpty() ) {
echo ( "<td>&nbsp;</td>\n" );
} else {
echo ( "<td>".$Day->thisDay()."</td>\n" );
}
if ( $Day->isLast() ) {
echo ( "</tr>\n" );
}
}
echo ( "</table>\n</td>\n" );
 
$i++;
}
?>
</table>
<p>Took: <?php echo ((getmicrotime()-$start)); ?></p>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/1.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/1.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/13.php
New file
0,0 → 1,99
<?php
/**
* Description: same as 1.php, but using the PEAR::Date engine
* Notice the use of the CALENDAR_ENGINE constant, which
* switches the calculation "engine"
* Note: make sure PEAR::Date is a stable release!!!
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
 
// Switch to PEAR::Date engine
define('CALENDAR_ENGINE','PearDate');
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
 
if (!isset($_GET['y'])) $_GET['y'] = 2003;
if (!isset($_GET['m'])) $_GET['m'] = 8;
if (!isset($_GET['d'])) $_GET['d'] = 9;
if (!isset($_GET['h'])) $_GET['h'] = 12;
if (!isset($_GET['i'])) $_GET['i'] = 34;
if (!isset($_GET['s'])) $_GET['s'] = 46;
 
switch ( @$_GET['view'] ) {
default:
$_GET['view'] = 'calendar_year';
case 'calendar_year':
require_once CALENDAR_ROOT.'Year.php';
$c = new Calendar_Year($_GET['y']);
break;
case 'calendar_month':
require_once CALENDAR_ROOT.'Month.php';
$c = new Calendar_Month($_GET['y'],$_GET['m']);
break;
case 'calendar_day':
require_once CALENDAR_ROOT.'Day.php';
$c = new Calendar_Day($_GET['y'],$_GET['m'],$_GET['d']);
break;
case 'calendar_hour':
require_once CALENDAR_ROOT.'Hour.php';
$c = new Calendar_Hour($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h']);
break;
case 'calendar_minute':
require_once CALENDAR_ROOT.'Minute.php';
$c = new Calendar_Minute($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h'],$_GET['i']);
break;
case 'calendar_second':
require_once CALENDAR_ROOT.'Second.php';
$c = new Calendar_Second($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h'],$_GET['i'],$_GET['s']);
break;
}
 
// Convert timestamp to human readable date
$date = new Date($c->getTimestamp());
 
echo ( '<h1>Using PEAR::Date engine</h1>' );
echo ( 'Viewing: '.@$_GET['view'].'<br />' );
echo ( 'The time is now: '.$date->format('%Y %a %e %T').'<br >' );
 
$i = 1;
echo ( '<h1>First Iteration</h1>' );
echo ( '<p>The first iteration is more "expensive", the calendar data
structures having to be built.</p>' );
$start = getmicrotime();
$c->build();
while ( $e = $c->fetch() ) {
$class = strtolower(get_class($e));
$link ="&y=".$e->thisYear()."&m=".$e->thisMonth()."&d=".$e->thisDay().
"&h=".$e->thisHour()."&i=".$e->thisMinute()."&s=".$e->thisSecond();
$method = 'this'.str_replace('calendar_','',$class);
echo ( "<a href=\"".$_SERVER['PHP_SELF']."?view=".$class.$link."\">".$e->{$method}()."</a> : " );
if ( ($i % 10) == 0 ) {
echo ( '<br>' );
}
$i++;
}
echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' );
 
$i = 1;
echo ( '<h1>Second Iteration</h1>' );
echo ( '<p>This second iteration is faster, the data structures
being re-used</p>' );
$start = getmicrotime();
while ( $e = $c->fetch() ) {
$class = strtolower(get_class($e));
$link ="&y=".$e->thisYear()."&m=".$e->thisMonth()."&d=".$e->thisDay().
"&h=".$e->thisHour()."&i=".$e->thisMinute()."&s=".$e->thisSecond();
$method = 'this'.str_replace('calendar_','',$class);
echo ( "<a href=\"".$_SERVER['PHP_SELF']."?view=".$class.$link."\">".$e->{$method}()."</a> : " );
if ( ($i % 10) == 0 ) {
echo ( '<br>' );
}
$i++;
}
echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' );
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/14.php
New file
0,0 → 1,141
<?php
/**
* Description: same as 3.php, but using the PEAR::Date engine
* Note: make sure PEAR::Date is a stable release!!!
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
// Switch to PEAR::Date engine
define('CALENDAR_ENGINE', 'PearDate');
 
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Day.php';
 
// Initialize GET variables if not set
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('m');
if (!isset($_GET['d'])) $_GET['d'] = date('d');
 
// Build the month
$month = new Calendar_Month_Weekdays($_GET['y'], $_GET['m']);
 
// Create an array of days which are "selected"
// Used for Week::build() below
$selectedDays = array (
new Calendar_Day($_GET['y'], $_GET['m'], $_GET['d']),
new Calendar_Day($_GET['y'], 12, 25),
);
 
// Build the days in the month
$month->build($selectedDays);
 
// Construct strings for next/previous links
$PMonth = $month->prevMonth('object'); // Get previous month as object
$prev = $_SERVER['PHP_SELF'].'?y='.$PMonth->thisYear().'&m='.$PMonth->thisMonth().'&d='.$PMonth->thisDay();
$NMonth = $month->nextMonth('object');
$next = $_SERVER['PHP_SELF'].'?y='.$NMonth->thisYear().'&m='.$NMonth->thisMonth().'&d='.$NMonth->thisDay();
 
$thisDate = new Date($month->thisMonth('timestamp'));
?>
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Calendar using PEAR::Date Engine </title>
<style text="text/css">
table {
background-color: silver;
}
caption {
font-family: verdana;
font-size: 12px;
background-color: while;
}
.prevMonth {
font-size: 10px;
text-align: left;
}
.nextMonth {
font-size: 10px;
text-align: right;
}
th {
font-family: verdana;
font-size: 11px;
color: navy;
text-align: right;
}
td {
font-family: verdana;
font-size: 11px;
text-align: right;
}
.selected {
background-color: yellow;
}
</style>
</head>
 
<body>
 
<h2>Calendar using PEAR::Date Engine</h2>
<table class="calendar">
<caption>
<?php echo $thisDate->format('%B %Y'); ?>
</caption>
<tr>
<th>M</th>
<th>T</th>
<th>W</th>
<th>T</th>
<th>F</th>
<th>S</th>
<th>S</th>
</tr>
<?php
while ($day = $month->fetch()) {
// Build a link string for each day
$link = $_SERVER['PHP_SELF'].
'?y='.$day->thisYear().
'&m='.$day->thisMonth().
'&d='.$day->thisDay();
 
// isFirst() to find start of week
if ($day->isFirst())
echo "<tr>\n";
 
if ($day->isSelected()) {
echo '<td class="selected">'.$day->thisDay().'</td>'."\n";
} else if ($day->isEmpty()) {
echo '<td>&nbsp;</td>'."\n";
} else {
echo '<td><a href="'.$link.'">'.$day->thisDay().'</a></td>'."\n";
}
 
// isLast() to find end of week
if ($day->isLast()) {
echo "</tr>\n";
}
}
?>
<tr>
<td>
<a href="<?php echo $prev; ?>" class="prevMonth"><< </a>
</td>
<td colspan="5">&nbsp;</td>
<td>
<a href="<?php echo $next; ?>" class="nextMonth"> >></a>
</td>
</tr>
</table>
<?php
echo '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>';
?>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/index.html
New file
0,0 → 1,49
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>PEAR::Calendar Examples</title>
<style type="text/css">
body {
font-family: georgia, serif;
}
pre {
background-color: silver;
}
code {
color: navy;
background-color: #e2e3e4;
}
</style>
</head>
 
<body>
<h1>PEAR::Calendar Examples</h1>
<p>$Id: index.html,v 1.1 2005-09-30 14:58:00 ddelon Exp $</p>
<ul>
<li><a href="1.php">1.php</a> [<a href="1.phps">src</a>] - shows basic usage, passing all the way down from <code>Calendar_Year</code> to <code>Calendar_Second</code> - more of a quick test it's working</li>
<li><a href="2.php">2.php</a> [<a href="2.phps">src</a>] - shows how to build a tabular month using <code>Calendar_Month_Weeks</code>, <code>Calendar_Week</code>, <code>Calendar_Day</code> as well as selecting some dates.</li>
<li><a href="3.php">3.php</a> [<a href="3.phps">src</a>] - shows how to build a tabular month using <code>Calendar_Month_Weekdays</code> and <code>Calendar_Day</code>, as well as selecting some dates (this method is faster).</li>
<li><a href="4.php">4.php</a> [<a href="4.phps">src</a>] - shows how to use PEAR::Calendar for validation.</li>
<li><a href="5.php">5.php</a> [<a href="5.phps">src</a>] - shows PEAR::Calendar in use to help generate a form.</li>
<li><a href="6.php">6.php</a> [<a href="6.phps">src</a>] - a month and day "planner" calendar, which can be rendered both as HTML and WML.</li>
<li><a href="7.php">7.php</a> [<a href="7.phps">src</a>] - a simple SOAP Calendar Server, using PEAR::SOAP and PEAR::Calendar</li>
<li><a href="8.php">8.php</a> [<a href="8.phps">src</a>] - a WSDL SOAP client for the SOAP Calendar Server</li>
<li><a href="9.php">9.php</a> [<a href="9.phps">src</a>] - quick example of i18n with <code>setlocale</code> (not working on SF)</li>
<li><a href="10.php">10.php</a> [<a href="10.phps">src</a>] - an example of extending <code>Calendar_Decorator</code> to modify output</li>
<li><a href="11.php">11.php</a> [<a href="11.phps">src</a>] - attaching a "payload" (e.g. results of a DB query) to a calendar using <code>Calendar_Decorator</code> to allow the payload to be available inside the main loop.</li>
<li><a href="12.php">12.php</a> [<a href="12.phps">src</a>] - a complete year with months.</li>
<li><a href="13.php">13.php</a> [<a href="13.phps">src</a>] - same as 1.php but using <code>Calendar_Engine_PearDate</code>, (see <a href="http://pear.php.net/Date">PEAR::Date</a>).</li>
<li><a href="14.php">14.php</a> [<a href="14.phps">src</a>] - same as 3.php but using <code>Calendar_Engine_PearDate</code></li>
<li><a href="15.php">15.php</a> [<a href="15.phps">src</a>] - paging through weeks </li>
<li><a href="16.php">16.php</a> [<a href="16.phps">src</a>] - demonstrates using the Uri decorator. <i>Note</i> you should prefer <code>Calendar_Util_Uri</code> (see below) in most cases, for performance </li>
<li><a href="17.php">17.php</a> [<a href="17.phps">src</a>] - demonstrates using the Textual decorator</li>
<li><a href="18.php">18.php</a> [<a href="18.phps">src</a>] - demonstrates using the Wrapper decorator</li>
<li><a href="19.php">19.php</a> [<a href="19.phps">src</a>] - demonstrates using the Weekday decorator</li>
<li><a href="20.php">20.php</a> [<a href="20.phps">src</a>] - shows how to attach a "payload" spanning multiple days, with more than one entry per day</li>
<li><a href="21.php">21.php</a> [<a href="21.phps">src</a>] - same as 12.php but using <code>Calendar_Month_Weeks</code> instead of <code>Calendar_Month_Weekdays</code> to allow the week in the year or week in the month to be displayed.</li>
<li><a href="22.php">22.php</a> [<a href="22.phps">src</a>] - demonstrates use of <code>Calendar_Util_Uri</code>.</li>
<li><a href="22.php">23.php</a> [<a href="23.phps">src</a>] - demonstrates use of <code>Calendar_Util_Textual</code>.</li>
</ul>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/3.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/3.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/15.php
New file
0,0 → 1,58
<?php
/**
* Shows more on how a week can be used
*/
function getmicrotime() {
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if (!@include 'Calendar/Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Week.php';
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('m');
if (!isset($_GET['d'])) $_GET['d'] = 1;
 
// Build the month
$Week = new Calendar_Week($_GET['y'], $_GET['m'], $_GET['d']);
/*
$Validator = $Week->getValidator();
if (!$Validator->isValidWeek()) {
die ('Please enter a valid week!');
}
*/
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Paging Weeks </title>
</head>
<body>
<h1>Paging Weeks</h1>
<h2>Week: <?php echo $Week->thisWeek().' '.date('F Y',$Week->thisMonth(true)); ?></h2>
<?php
$Week->build();
while ($Day = $Week->fetch()) {
echo '<p>'.date('jS F',$Day->thisDay(true))."</p>\n";
}
$days = $Week->fetchAll();
 
$prevWeek = $Week->prevWeek('array');
$prevWeekLink = $_SERVER['PHP_SELF'].
'?y='.$prevWeek['year'].
'&m='.$prevWeek['month'].
'&d='.$prevWeek['day'];
 
$nextWeek = $Week->nextWeek('array');
$nextWeekLink = $_SERVER['PHP_SELF'].
'?y='.$nextWeek['year'].
'&m='.$nextWeek['month'].
'&d='.$nextWeek['day'];
?>
<p><a href="<?php echo $prevWeekLink; ?>"><<</a> | <a href="<?php echo $nextWeekLink; ?>">>></a></p>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/16.php
New file
0,0 → 1,31
<?php
/**
* Description: demonstrates using the Uri decorator
*/
if (!@include 'Calendar/Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Decorator/Uri.php';
 
if (!isset($_GET['jahr'])) $_GET['jahr'] = date('Y');
if (!isset($_GET['monat'])) $_GET['monat'] = date('m');
 
// Build the month
$Calendar = new Calendar_Month_Weekdays($_GET['jahr'], $_GET['monat']);
 
echo ( '<p>The current month is '
.$Calendar->thisMonth().' of year '.$Calendar->thisYear().'</p>');
 
$Uri = & new Calendar_Decorator_Uri($Calendar);
$Uri->setFragments('jahr','monat');
// $Uri->setSeperator('/'); // Default is &
// $Uri->setScalar(); // Omit variable names
echo ( "<pre>Previous Uri:\t".$Uri->prev('month')."\n" );
echo ( "This Uri:\t".$Uri->this('month')."\n" );
echo ( "Next Uri:\t".$Uri->next('month')."\n</pre>" );
?>
<p>
<a href="<?php echo($_SERVER['PHP_SELF'].'?'.$Uri->prev('month'));?>">Prev</a> :
<a href="<?php echo($_SERVER['PHP_SELF'].'?'.$Uri->next('month'));?>">Next</a>
</p>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/5.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/5.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/17.php
New file
0,0 → 1,71
<?php
/**
* Description: demonstrates using the Textual decorator
*/
 
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Day.php';
require_once CALENDAR_ROOT.'Month'.DIRECTORY_SEPARATOR.'Weekdays.php';
require_once CALENDAR_ROOT.'Decorator'.DIRECTORY_SEPARATOR.'Textual.php';
 
// Could change language like this
// setlocale (LC_TIME, "de_DE"); // Unix based (probably)
// setlocale (LC_TIME, "ge"); // Windows
 
echo "<hr>Calling: Calendar_Decorator_Textual::monthNames('long');<pre>";
print_r(Calendar_Decorator_Textual::monthNames('long'));
echo '</pre>';
 
echo "<hr>Calling: Calendar_Decorator_Textual::weekdayNames('two');<pre>";
print_r(Calendar_Decorator_Textual::weekdayNames('two'));
echo '</pre>';
 
echo "<hr>Creating: new Calendar_Day(date('Y'), date('n'), date('d'));<br />";
$Calendar = new Calendar_Day(date('Y'), date('n'), date('d'));
 
// Decorate
$Textual = & new Calendar_Decorator_Textual($Calendar);
 
echo '<hr>Previous month is: '.$Textual->prevMonthName('two').'<br />';
echo 'This month is: '.$Textual->thisMonthName('short').'<br />';
echo 'Next month is: '.$Textual->nextMonthName().'<br /><hr />';
echo 'Previous day is: '.$Textual->prevDayName().'<br />';
echo 'This day is: '.$Textual->thisDayName('short').'<br />';
echo 'Next day is: '.$Textual->nextDayName('one').'<br /><hr />';
 
echo "Creating: new Calendar_Month_Weekdays(date('Y'), date('n'), 6); - Saturday is first day of week<br />";
$Calendar = new Calendar_Month_Weekdays(date('Y'), date('n'), 6);
 
// Decorate
$Textual = & new Calendar_Decorator_Textual($Calendar);
?>
<p>Rendering calendar....</p>
<table>
<caption><?php echo $Textual->thisMonthName().' '.$Textual->thisYear(); ?></caption>
<tr>
<?php
$dayheaders = $Textual->orderedWeekdays('short');
foreach ($dayheaders as $dayheader) {
echo '<th>'.$dayheader.'</th>';
}
?>
</tr>
<?php
$Calendar->build();
while ($Day = $Calendar->fetch()) {
if ($Day->isFirst()) {
echo "<tr>\n";
}
if ($Day->isEmpty()) {
echo '<td>&nbsp;</td>';
} else {
echo '<td>'.$Day->thisDay().'</td>';
}
if ($Day->isLast()) {
echo "</tr>\n";
}
}
?>
</table>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/18.php
New file
0,0 → 1,36
<?php
/**
* Description: demonstrates using the Wrapper decorator
*/
 
if (!@include 'Calendar/Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Month.php';
require_once CALENDAR_ROOT.'Decorator.php'; // Not really needed but added to help this make sense
require_once CALENDAR_ROOT.'Decorator/Wrapper.php';
 
class MyBoldDecorator extends Calendar_Decorator
{
function MyBoldDecorator(&$Calendar)
{
parent::Calendar_Decorator($Calendar);
}
 
function thisDay()
{
return '<b>'.parent::thisDay().'</b>';
}
}
 
$Month = new Calendar_Month(date('Y'), date('n'));
 
$Wrapper = & new Calendar_Decorator_Wrapper($Month);
$Wrapper->build();
 
echo '<h2>The Wrapper decorator</h2>';
echo '<i>Day numbers are rendered in bold</i><br /> <br />';
while ($DecoratedDay = $Wrapper->fetch('MyBoldDecorator')) {
echo $DecoratedDay->thisDay().'<br />';
}
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/7.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/7.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/19.php
New file
0,0 → 1,24
<?php
/**
* Description: demonstrates using the Weekday decorator
*/
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Day.php';
require_once CALENDAR_ROOT.'Decorator/Weekday.php';
 
$Day = new Calendar_Day(date('Y'), date('n'),date('d'));
$WeekDay = & new Calendar_Decorator_Weekday($Day);
// $WeekDay->setFirstDay(0); // Make Sunday first Day
 
echo 'Yesterday: '.$WeekDay->prevWeekDay().'<br>';
echo 'Today: '.$WeekDay->thisWeekDay().'<br>';
echo 'Tomorrow: '.$WeekDay->nextWeekDay().'<br>';
 
$WeekDay->build();
echo 'Hours today:<br>';
while ( $Hour = $WeekDay->fetch() ) {
echo $Hour->thisHour().'<br>';
}
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/9.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/9.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/10.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/10.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/20.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/20.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/12.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/12.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/22.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/22.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/14.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/14.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/16.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/16.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/18.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/18.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/20.php
New file
0,0 → 1,314
<?php
/**
* Description: demonstrates a decorator used to "attach a payload" to a selection
* to make it available when iterating over calendar children
*/
 
//if you use ISO-8601 dates, switch to PearDate engine
define('CALENDAR_ENGINE', 'PearDate');
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
 
require_once CALENDAR_ROOT . 'Month/Weekdays.php';
require_once CALENDAR_ROOT . 'Day.php';
require_once CALENDAR_ROOT . 'Decorator.php';
 
// accepts multiple entries
class DiaryEvent extends Calendar_Decorator
{
var $entries = array();
 
function DiaryEvent($calendar) {
Calendar_Decorator::Calendar_Decorator($calendar);
}
 
function addEntry($entry) {
$this->entries[] = $entry;
}
 
function getEntry() {
$entry = each($this->entries);
if ($entry) {
return $entry['value'];
} else {
reset($this->entries);
return false;
}
}
}
 
class MonthPayload_Decorator extends Calendar_Decorator
{
//Calendar engine
var $cE;
var $tableHelper;
 
var $year;
var $month;
var $firstDay = false;
 
function build($events=array())
{
require_once CALENDAR_ROOT . 'Day.php';
require_once CALENDAR_ROOT . 'Table/Helper.php';
 
$this->tableHelper = & new Calendar_Table_Helper($this, $this->firstDay);
$this->cE = & $this->getEngine();
$this->year = $this->thisYear();
$this->month = $this->thisMonth();
 
$daysInMonth = $this->cE->getDaysInMonth($this->year, $this->month);
for ($i=1; $i<=$daysInMonth; $i++) {
$Day = new Calendar_Day(2000,1,1); // Create Day with dummy values
$Day->setTimeStamp($this->cE->dateToStamp($this->year, $this->month, $i));
$this->children[$i] = new DiaryEvent($Day);
}
if (count($events) > 0) {
$this->setSelection($events);
}
Calendar_Month_Weekdays::buildEmptyDaysBefore();
Calendar_Month_Weekdays::shiftDays();
Calendar_Month_Weekdays::buildEmptyDaysAfter();
Calendar_Month_Weekdays::setWeekMarkers();
return true;
}
 
function setSelection($events)
{
$daysInMonth = $this->cE->getDaysInMonth($this->year, $this->month);
for ($i=1; $i<=$daysInMonth; $i++) {
$stamp1 = $this->cE->dateToStamp($this->year, $this->month, $i);
$stamp2 = $this->cE->dateToStamp($this->year, $this->month, $i+1);
foreach ($events as $event) {
if (($stamp1 >= $event['start'] && $stamp1 < $event['end']) ||
($stamp2 >= $event['start'] && $stamp2 < $event['end']) ||
($stamp1 <= $event['start'] && $stamp2 > $event['end'])
) {
$this->children[$i]->addEntry($event);
$this->children[$i]->setSelected();
}
}
}
}
 
function fetch()
{
$child = each($this->children);
if ($child) {
return $child['value'];
} else {
reset($this->children);
return false;
}
}
}
 
// Calendar instance used to get the dates in the preferred format:
// you can switch Calendar Engine and the example still works
$cal = new Calendar;
 
$events = array();
//add some events
$events[] = array(
'start' => $cal->cE->dateToStamp(2004, 6, 1, 10),
'end' => $cal->cE->dateToStamp(2004, 6, 1, 12),
'desc' => 'Important meeting'
);
$events[] = array(
'start' => $cal->cE->dateToStamp(2004, 6, 1, 21),
'end' => $cal->cE->dateToStamp(2004, 6, 1, 23, 59),
'desc' => 'Dinner with the boss'
);
$events[] = array(
'start' => $cal->cE->dateToStamp(2004, 6, 5),
'end' => $cal->cE->dateToStamp(2004, 6, 10, 23, 59),
'desc' => 'Holidays!'
);
 
 
 
$Month = & new Calendar_Month_Weekdays(2004, 6);
$MonthDecorator = new MonthPayload_Decorator($Month);
$MonthDecorator->build($events);
 
?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text-align: center;
+ background-color: #e7e3e7;
+ padding: 5pt;
+
+
+
+
+
+
+ text-align: left;
+
+
+
+
+
+
+
+
+
+
+
+
+div.dayNumber {
+ text-align: right;
+ background-color: #f8f8f8;
+ border-bottom: 1px solid #ccc;
+}
+ul {
+ margin-left: 0;
+
+
+
+
+
+
+
+<body>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo '<td class="calCell';
+ if ($Day->isSelected()) {
+ echo ' calCellBusy';
+ } elseif ($Day->isEmpty()) {
+ echo ' calCellEmpty';
+ }
+ echo '">';
+ echo '<div class="dayNumber">'.$Day->thisDay().'</div>';
+
+
+
+
+ echo '<div class="dayContents"><ul>';
+ while ($entry = $Day->getEntry()) {
+ echo '<li>'.$entry['desc'].'</li>';
+ //you can print the time range as well
+ }
+ echo '</ul></div>';
+ }
+
+
+
+ echo "</tr>\n";
+
+
+
+
+
+</html>
\ No newline at end of file
/branches/v1.0-menes/api/pear/Calendar/docs/examples/21.php
New file
0,0 → 1,139
<?php
/**
* Description: a complete year with numeric week numbers
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if (!@include 'Calendar/Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
 
require_once CALENDAR_ROOT.'Year.php';
require_once CALENDAR_ROOT.'Month/Weeks.php';
 
define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKS);
 
if (!isset($_GET['year'])) $_GET['year'] = date('Y');
 
$week_types = array(
'n_in_year',
'n_in_month',
);
 
if (!isset($_GET['week_type']) || !in_array($_GET['week_type'],$week_types) ) {
$_GET['week_type'] = 'n_in_year';
}
 
$Year = new Calendar_Year($_GET['year']);
 
$Year->build();
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> <?php echo $Year->thisYear(); ?> </title>
<style type="text/css">
body {
font-family: Georgia, serif;
}
caption.year {
font-weight: bold;
font-size: 120%;
font-color: navy;
}
caption.month {
font-size: 110%;
font-color: navy;
}
table.month {
border: thin groove #800080
}
tr {
vertical-align: top;
}
th, td {
text-align: right;
font-size: 70%;
}
#prev {
float: left;
font-size: 70%;
}
#next {
float: right;
font-size: 70%;
}
#week_type {
float: none;
font-size: 70%;
}
.weekNumbers {
background-color: #e5e5f5;
padding-right: 3pt;
}
</style>
</head>
<body>
<table>
<caption class="year">
<?php echo $Year->thisYear(); ?>
<div id="next">
<a href="?year=<?php echo $Year->nextYear(); ?>&week_type=<?php echo $_GET['week_type']; ?>">>></a>
</div>
<div id="prev">
<a href="?year=<?php echo $Year->prevYear(); ?>&week_type=<?php echo $_GET['week_type']; ?>"><<</a>
</div>
<div id="week_type">
<a href="?year=<?php echo $Year->thisYear(); ?>&week_type=n_in_year">Weeks by Year</a> :
<a href="?year=<?php echo $Year->thisYear(); ?>&week_type=n_in_month">Weeks by Month</a>
</div>
</caption>
<?php
$i = 0;
while ($Month = $Year->fetch()) {
 
switch ($i) {
case 0:
echo "<tr>\n";
break;
case 3:
case 6:
case 9:
echo "</tr>\n<tr>\n";
break;
case 12:
echo "</tr>\n";
break;
}
 
echo "<td>\n<table class=\"month\">\n";
echo '<caption class="month">'.date('F', $Month->thisMonth(TRUE)).'</caption>';
echo '<colgroup><col class="weekNumbers"><col span="7"></colgroup>'."\n";
echo "<tr>\n<th>Week</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th>\n</tr>";
$Month->build();
while ($Week = $Month->fetch()) {
echo "<tr>\n";
echo '<td>'.$Week->thisWeek($_GET['week_type'])."</td>\n";
$Week->build();
 
while ($Day = $Week->fetch()) {
if ($Day->isEmpty()) {
echo "<td>&nbsp;</td>\n";
} else {
echo "<td>".$Day->thisDay()."</td>\n";
}
}
}
echo "</table>\n</td>\n";
 
$i++;
}
?>
</table>
<p>Took: <?php echo ((getmicrotime()-$start)); ?></p>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/22.php
New file
0,0 → 1,46
<?php
/**
* Description: demonstrates using the Uri util
*/
if (!@include 'Calendar/Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Util/Uri.php';
 
if (!isset($_GET['jahr'])) $_GET['jahr'] = date('Y');
if (!isset($_GET['monat'])) $_GET['monat'] = date('m');
 
// Build the month
$Calendar = new Calendar_Month_Weekdays($_GET['jahr'], $_GET['monat']);
 
echo ( '<p>The current month is '
.$Calendar->thisMonth().' of year '.$Calendar->thisYear().'</p>');
 
$Uri = & new Calendar_Util_Uri('jahr','monat');
$Uri->setFragments('jahr','monat');
 
echo "\"Vector\" URIs<pre>";
echo ( "Previous Uri:\t".htmlentities($Uri->prev($Calendar, 'month'))."\n" );
echo ( "This Uri:\t".htmlentities($Uri->this($Calendar, 'month'))."\n" );
echo ( "Next Uri:\t".htmlentities($Uri->next($Calendar, 'month'))."\n" );
echo "</pre>";
 
// Switch to scalar URIs
$Uri->separator = '/'; // Default is &amp;
$Uri->scalar = true; // Omit variable names
 
echo "\"Scalar\" URIs<pre>";
echo ( "Previous Uri:\t".$Uri->prev($Calendar, 'month')."\n" );
echo ( "This Uri:\t".$Uri->this($Calendar, 'month')."\n" );
echo ( "Next Uri:\t".$Uri->next($Calendar, 'month')."\n" );
echo "</pre>";
 
// Restore the vector URIs
$Uri->separator = '&amp;';
$Uri->scalar = false;
?>
<p>
<a href="<?php echo($_SERVER['PHP_SELF'].'?'.$Uri->prev($Calendar, 'month'));?>">Prev</a> :
<a href="<?php echo($_SERVER['PHP_SELF'].'?'.$Uri->next($Calendar, 'month'));?>">Next</a>
</p>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/23.php
New file
0,0 → 1,66
<?php
/**
* Description: demonstrates using the Textual util
*/
 
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Day.php';
require_once CALENDAR_ROOT.'Month'.DIRECTORY_SEPARATOR.'Weekdays.php';
require_once CALENDAR_ROOT.'Util'.DIRECTORY_SEPARATOR.'Textual.php';
 
// Could change language like this
// setlocale (LC_TIME, "de_DE"); // Unix based (probably)
// setlocale (LC_TIME, "ge"); // Windows
 
echo "<hr>Calling: Calendar_Util_Textual::monthNames('long');<pre>";
print_r(Calendar_Util_Textual::monthNames('long'));
echo '</pre>';
 
echo "<hr>Calling: Calendar_Util_Textual::weekdayNames('two');<pre>";
print_r(Calendar_Util_Textual::weekdayNames('two'));
echo '</pre>';
 
echo "<hr>Creating: new Calendar_Day(date('Y'), date('n'), date('d'));<br />";
$Calendar = new Calendar_Day(date('Y'), date('n'), date('d'));
 
echo '<hr>Previous month is: '.Calendar_Util_Textual::prevMonthName($Calendar,'two').'<br />';
echo 'This month is: '.Calendar_Util_Textual::thisMonthName($Calendar,'short').'<br />';
echo 'Next month is: '.Calendar_Util_Textual::nextMonthName($Calendar).'<br /><hr />';
echo 'Previous day is: '.Calendar_Util_Textual::prevDayName($Calendar).'<br />';
echo 'This day is: '.Calendar_Util_Textual::thisDayName($Calendar,'short').'<br />';
echo 'Next day is: '.Calendar_Util_Textual::nextDayName($Calendar,'one').'<br /><hr />';
 
echo "Creating: new Calendar_Month_Weekdays(date('Y'), date('n'), 6); - Saturday is first day of week<br />";
$Calendar = new Calendar_Month_Weekdays(date('Y'), date('n'), 6);
 
?>
<p>Rendering calendar....</p>
<table>
<caption><?php echo Calendar_Util_Textual::thisMonthName($Calendar).' '.$Calendar->thisYear(); ?></caption>
<tr>
<?php
$dayheaders = Calendar_Util_Textual::orderedWeekdays($Calendar,'short');
foreach ($dayheaders as $dayheader) {
echo '<th>'.$dayheader.'</th>';
}
?>
</tr>
<?php
$Calendar->build();
while ($Day = $Calendar->fetch()) {
if ($Day->isFirst()) {
echo "<tr>\n";
}
if ($Day->isEmpty()) {
echo '<td>&nbsp;</td>';
} else {
echo '<td>'.$Day->thisDay().'</td>';
}
if ($Day->isLast()) {
echo "</tr>\n";
}
}
?>
</table>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/2.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/2.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/4.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/4.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/6.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/6.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/8.phps
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v1.0-menes/api/pear/Calendar/docs/examples/8.phps
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v1.0-menes/api/pear/Calendar/docs/examples/1.php
New file
0,0 → 1,92
<?php
/**
* Description: Passes through all main calendar classes, beginning with year
* and down to seconds, skipping weeks. Useful to test Calendar is (basically)
* working correctly
*
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
 
if (!isset($_GET['y'])) $_GET['y'] = 2003;
if (!isset($_GET['m'])) $_GET['m'] = 8;
if (!isset($_GET['d'])) $_GET['d'] = 9;
if (!isset($_GET['h'])) $_GET['h'] = 12;
if (!isset($_GET['i'])) $_GET['i'] = 34;
if (!isset($_GET['s'])) $_GET['s'] = 46;
 
switch ( @$_GET['view'] ) {
default:
$_GET['view'] = 'calendar_year';
case 'calendar_year':
require_once CALENDAR_ROOT.'Year.php';
$c = new Calendar_Year($_GET['y']);
break;
case 'calendar_month':
require_once CALENDAR_ROOT.'Month.php';
$c = new Calendar_Month($_GET['y'],$_GET['m']);
break;
case 'calendar_day':
require_once CALENDAR_ROOT.'Day.php';
$c = new Calendar_Day($_GET['y'],$_GET['m'],$_GET['d']);
break;
case 'calendar_hour':
require_once CALENDAR_ROOT.'Hour.php';
$c = new Calendar_Hour($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h']);
break;
case 'calendar_minute':
require_once CALENDAR_ROOT.'Minute.php';
$c = new Calendar_Minute($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h'],$_GET['i']);
break;
case 'calendar_second':
require_once CALENDAR_ROOT.'Second.php';
$c = new Calendar_Second($_GET['y'],$_GET['m'],$_GET['d'],$_GET['h'],$_GET['i'],$_GET['s']);
break;
}
 
echo ( 'Viewing: '.@$_GET['view'].'<br />' );
echo ( 'The time is now: '.date('Y M d H:i:s',$c->getTimestamp()).'<br >' );
 
$i = 1;
echo ( '<h1>First Iteration</h1>' );
echo ( '<p>The first iteration is more "expensive", the calendar data
structures having to be built.</p>' );
$start = getmicrotime();
$c->build();
while ( $e = $c->fetch() ) {
$class = strtolower(get_class($e));
$link ="&y=".$e->thisYear()."&m=".$e->thisMonth()."&d=".$e->thisDay().
"&h=".$e->thisHour()."&i=".$e->thisMinute()."&s=".$e->thisSecond();
$method = 'this'.str_replace('calendar_','',$class);
echo ( "<a href=\"".$_SERVER['PHP_SELF']."?view=".$class.$link."\">".$e->{$method}()."</a> : " );
if ( ($i % 10) == 0 ) {
echo ( '<br>' );
}
$i++;
}
echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' );
 
$i = 1;
echo ( '<h1>Second Iteration</h1>' );
echo ( '<p>This second iteration is faster, the data structures
being re-used</p>' );
$start = getmicrotime();
while ( $e = $c->fetch() ) {
$class = strtolower(get_class($e));
$link ="&y=".$e->thisYear()."&m=".$e->thisMonth()."&d=".$e->thisDay().
"&h=".$e->thisHour()."&i=".$e->thisMinute()."&s=".$e->thisSecond();
$method = 'this'.str_replace('calendar_','',$class);
echo ( "<a href=\"".$_SERVER['PHP_SELF']."?view=".$class.$link."\">".$e->{$method}()."</a> : " );
if ( ($i % 10) == 0 ) {
echo ( '<br>' );
}
$i++;
}
echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' );
?>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/2.php
New file
0,0 → 1,142
<?php
/**
* Description: Demonstrates building a calendar for a month using the Week class
* Uses UnixTs engine
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
// Force UnixTs engine (default setting)
define('CALENDAR_ENGINE','UnixTs');
 
if (!@include 'Calendar'.DIRECTORY_SEPARATOR.'Calendar.php') {
define('CALENDAR_ROOT', '../../');
}
require_once CALENDAR_ROOT.'Month/Weeks.php';
require_once CALENDAR_ROOT.'Day.php';
 
// Initialize GET variables if not set
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('m');
if (!isset($_GET['d'])) $_GET['d'] = date('d');
 
// Build a month object
$Month = new Calendar_Month_Weeks($_GET['y'], $_GET['m']);
 
// Create an array of days which are "selected"
// Used for Week::build() below
$selectedDays = array (
new Calendar_Day($_GET['y'],$_GET['m'], $_GET['d']),
new Calendar_Day($_GET['y'], 12, 25),
new Calendar_Day(date('Y'), date('m'), date('d')),
);
 
// Instruct month to build Week objects
$Month->build();
 
// Construct strings for next/previous links
$PMonth = $Month->prevMonth('object'); // Get previous month as object
$prev = $_SERVER['PHP_SELF'].'?y='.$PMonth->thisYear().'&m='.$PMonth->thisMonth().'&d='.$PMonth->thisDay();
$NMonth = $Month->nextMonth('object');
$next = $_SERVER['PHP_SELF'].'?y='.$NMonth->thisYear().'&m='.$NMonth->thisMonth().'&d='.$NMonth->thisDay();
?>
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Calendar </title>
<style text="text/css">
table {
background-color: silver;
}
caption {
font-family: verdana;
font-size: 12px;
background-color: while;
}
.prevMonth {
font-size: 10px;
text-align: left;
}
.nextMonth {
font-size: 10px;
text-align: right;
}
th {
font-family: verdana;
font-size: 11px;
color: navy;
text-align: right;
}
td {
font-family: verdana;
font-size: 11px;
text-align: right;
}
.selected {
background-color: yellow;
}
.empty {
color: white;
}
</style>
</head>
 
<body>
<h2>Build with Calendar_Month_Weeks::build() then Calendar_Week::build()</h2>
<table class="calendar">
<caption>
<?php echo date('F Y', $Month->getTimeStamp()); ?>
</caption>
<tr>
<th>M</th>
<th>T</th>
<th>W</th>
<th>T</th>
<th>F</th>
<th>S</th>
<th>S</th>
</tr>
<?php
while ($Week = $Month->fetch()) {
echo "<tr>\n";
// Build the days in the week, passing the selected days
$Week->build($selectedDays);
while ($Day = $Week->fetch()) {
 
// Build a link string for each day
$link = $_SERVER['PHP_SELF'].
'?y='.$Day->thisYear().
'&m='.$Day->thisMonth().
'&d='.$Day->thisDay();
 
// Check to see if day is selected
if ($Day->isSelected()) {
echo '<td class="selected">'.$Day->thisDay().'</td>'."\n";
// Check to see if day is empty
} else if ($Day->isEmpty()) {
echo '<td class="empty">'.$Day->thisDay().'</td>'."\n";
} else {
echo '<td><a href="'.$link.'">'.$Day->thisDay().'</a></td>'."\n";
}
}
echo '</tr>'."\n";
}
?>
<tr>
<td>
<a href="<?php echo $prev; ?>" class="prevMonth"><< </a>
</td>
<td colspan="5">&nbsp;</td>
<td>
<a href="<?php echo $next; ?>" class="nextMonth"> >></a>
</td>
</tr>
</table>
<?php
echo '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>';
?>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/docs/examples/3.php
New file
0,0 → 1,134
<?php
/**
* Description: Performs same behaviour as 2.php but uses Month::buildWeekDays()
* and is faster
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$start = getmicrotime();
 
if ( !@include 'Calendar/Calendar.php' ) {
define('CALENDAR_ROOT','../../');
}
require_once CALENDAR_ROOT.'Month/Weekdays.php';
require_once CALENDAR_ROOT.'Day.php';
 
if (!isset($_GET['y'])) $_GET['y'] = date('Y');
if (!isset($_GET['m'])) $_GET['m'] = date('m');
if (!isset($_GET['d'])) $_GET['d'] = date('d');
 
// Build the month
$Month = new Calendar_Month_Weekdays($_GET['y'],$_GET['m']);
 
// Construct strings for next/previous links
$PMonth = $Month->prevMonth('object'); // Get previous month as object
$prev = $_SERVER['PHP_SELF'].'?y='.$PMonth->thisYear().'&m='.$PMonth->thisMonth().'&d='.$PMonth->thisDay();
$NMonth = $Month->nextMonth('object');
$next = $_SERVER['PHP_SELF'].'?y='.$NMonth->thisYear().'&m='.$NMonth->thisMonth().'&d='.$NMonth->thisDay();
?>
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Calendar </title>
<style text="text/css">
table {
background-color: silver;
}
caption {
font-family: verdana;
font-size: 12px;
background-color: while;
}
.prevMonth {
font-size: 10px;
text-align: left;
}
.nextMonth {
font-size: 10px;
text-align: right;
}
th {
font-family: verdana;
font-size: 11px;
color: navy;
text-align: right;
}
td {
font-family: verdana;
font-size: 11px;
text-align: right;
}
.selected {
background-color: yellow;
}
</style>
</head>
 
<body>
 
<?php
$selectedDays = array (
new Calendar_Day($_GET['y'],$_GET['m'],$_GET['d']),
new Calendar_Day($_GET['y'],12,25),
);
 
// Build the days in the month
$Month->build($selectedDays);
?>
<h2>Built with Calendar_Month_Weekday::build()</h2>
<table class="calendar">
<caption>
<?php echo ( date('F Y',$Month->getTimeStamp())); ?>
</caption>
<tr>
<th>M</th>
<th>T</th>
<th>W</th>
<th>T</th>
<th>F</th>
<th>S</th>
<th>S</th>
</tr>
<?php
while ( $Day = $Month->fetch() ) {
 
// Build a link string for each day
$link = $_SERVER['PHP_SELF'].
'?y='.$Day->thisYear().
'&m='.$Day->thisMonth().
'&d='.$Day->thisDay();
 
// isFirst() to find start of week
if ( $Day->isFirst() )
echo ( "<tr>\n" );
 
if ( $Day->isSelected() ) {
echo ( "<td class=\"selected\">".$Day->thisDay()."</td>\n" );
} else if ( $Day->isEmpty() ) {
echo ( "<td>&nbsp;</td>\n" );
} else {
echo ( "<td><a href=\"".$link."\">".$Day->thisDay()."</a></td>\n" );
}
 
// isLast() to find end of week
if ( $Day->isLast() )
echo ( "</tr>\n" );
}
?>
<tr>
<td>
<a href="<?php echo ($prev);?>" class="prevMonth"><< </a>
</td>
<td colspan="5">&nbsp;</td>
<td>
<a href="<?php echo ($next);?>" class="nextMonth"> >></a>
</td>
</tr>
</table>
<?php
echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' );
?>
</body>
</html>
/branches/v1.0-menes/api/pear/Calendar/Factory.php
New file
0,0 → 1,158
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Factory.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Factory.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Constant for the first day of the week (integer e.g. 0-6)
*/
if ( !defined ('CALENDAR_FIRST_DAY_OF_WEEK') ) {
define ('CALENDAR_FIRST_DAY_OF_WEEK',1);
}
 
/**
* Contains a factory method to return a Singleton instance of a class
* implementing the Calendar_Engine_Interface.<br>
* For Month objects, to control type of month returned, use CALENDAR_MONTH_STATE
* constact e.g.;
* <code>
* require_once 'Calendar/Factory.php';
* define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKDAYS); // Use Calendar_Month_Weekdays
* // define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH_WEEKS); // Use Calendar_Month_Weeks
* // define ('CALENDAR_MONTH_STATE',CALENDAR_USE_MONTH); // Use Calendar_Month
* </code>
* It defaults to building Calendar_Month objects.<br>
* Use the constract CALENDAR_FIRST_DAY_OF_WEEK to control the first day of the week
* for Month or Week objects (e.g. 0 = Sunday, 6 = Saturday)
* @package Calendar
* @access protected
*/
class Calendar_Factory
{
/**
* Creates a calendar object given the type and units
* @param string class of calendar object to create
* @param int year
* @param int month
* @param int day
* @param int hour
* @param int minute
* @param int second
* @return object subclass of Calendar
* @access public
* @static
*/
function create($type, $y = 2000, $m = 1, $d = 1, $h = 0, $i = 0, $s = 0)
{
switch ( $type ) {
case 'Day':
require_once CALENDAR_ROOT.'Day.php';
return new Calendar_Day($y,$m,$d);
break;
case 'Month':
// Set default state for which month type to build
if (!defined('CALENDAR_MONTH_STATE')) {
define('CALENDAR_MONTH_STATE', CALENDAR_USE_MONTH);
}
switch (CALENDAR_MONTH_STATE) {
case CALENDAR_USE_MONTH_WEEKDAYS:
require_once CALENDAR_ROOT.'Month'.DIRECTORY_SEPARATOR.'Weekdays.php';
$class = 'Calendar_Month_Weekdays';
break;
case CALENDAR_USE_MONTH_WEEKS:
require_once CALENDAR_ROOT.'Month'.DIRECTORY_SEPARATOR.'Weeks.php';
$class = 'Calendar_Month_Weeks';
break;
case CALENDAR_USE_MONTH:
default:
require_once CALENDAR_ROOT.'Month.php';
$class = 'Calendar_Month';
break;
}
return new $class($y,$m,CALENDAR_FIRST_DAY_OF_WEEK);
break;
case 'Week':
require_once CALENDAR_ROOT.'Week.php';
return new Calendar_Week($y,$m,$d,CALENDAR_FIRST_DAY_OF_WEEK);
break;
case 'Hour':
require_once CALENDAR_ROOT.'Hour.php';
return new Calendar_Hour($y,$m,$d,$h);
break;
case 'Minute':
require_once CALENDAR_ROOT.'Minute.php';
return new Calendar_Minute($y,$m,$d,$h,$i);
break;
case 'Second':
require_once CALENDAR_ROOT.'Second.php';
return new Calendar_Second($y,$m,$d,$h,$i,$s);
break;
case 'Year':
require_once CALENDAR_ROOT.'Year.php';
return new Calendar_Year($y);
break;
default:
require_once 'PEAR.php';
PEAR::raiseError(
'Calendar_Factory::create() unrecognised type: '.$type, null, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar_Factory::create()');
return false;
break;
}
}
/**
* Creates an instance of a calendar object, given a type and timestamp
* @param string type of object to create
* @param mixed timestamp (depending on Calendar engine being used)
* @return object subclass of Calendar
* @access public
* @static
*/
function & createByTimestamp($type, $stamp)
{
$cE = & Calendar_Engine_Factory::getEngine();
$y = $cE->stampToYear($stamp);
$m = $cE->stampToMonth($stamp);
$d = $cE->stampToDay($stamp);
$h = $cE->stampToHour($stamp);
$i = $cE->stampToMinute($stamp);
$s = $cE->stampToSecond($stamp);
return Calendar_Factory::create($type, $y, $m, $d, $h, $i, $s);
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Calendar.php
New file
0,0 → 1,654
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Calendar.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Calendar.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Constant which defines the calculation engine to use
*/
if (!defined('CALENDAR_ENGINE')) {
define('CALENDAR_ENGINE', 'UnixTS');
}
 
/**
* Define Calendar Month states
*/
define('CALENDAR_USE_MONTH', 1);
define('CALENDAR_USE_MONTH_WEEKDAYS', 2);
define('CALENDAR_USE_MONTH_WEEKS', 3);
 
/**
* Contains a factory method to return a Singleton instance of a class
* implementing the Calendar_Engine_Interface.<br>
* <b>Note:</b> this class must be modified to "register" alternative
* Calendar_Engines. The engine used can be controlled with the constant
* CALENDAR_ENGINE
* @see Calendar_Engine_Interface
* @package Calendar
* @access protected
*/
class Calendar_Engine_Factory
{
/**
* Returns an instance of the engine
* @return object instance of a calendar calculation engine
* @access protected
*/
function & getEngine()
{
static $engine = false;
switch (CALENDAR_ENGINE) {
case 'PearDate':
$class = 'Calendar_Engine_PearDate';
break;
case 'UnixTS':
default:
$class = 'Calendar_Engine_UnixTS';
break;
}
if (!$engine) {
if (!class_exists($class)) {
require_once CALENDAR_ROOT.'Engine'.DIRECTORY_SEPARATOR.CALENDAR_ENGINE.'.php';
}
$engine = new $class;
}
return $engine;
}
}
 
/**
* Base class for Calendar API. This class should not be instantiated
* directly.
* @abstract
* @package Calendar
*/
class Calendar
{
/**
* Instance of class implementing calendar engine interface
* @var object
* @access private
*/
var $cE;
 
/**
* Instance of Calendar_Validator (lazy initialized when isValid() or
* getValidor() is called
* @var Calendar_Validator
* @access private
*/
var $validator;
 
/**
* Year for this calendar object e.g. 2003
* @access private
* @var int
*/
var $year;
 
/**
* Month for this calendar object e.g. 9
* @access private
* @var int
*/
var $month;
 
/**
* Day of month for this calendar object e.g. 23
* @access private
* @var int
*/
var $day;
 
/**
* Hour of day for this calendar object e.g. 13
* @access private
* @var int
*/
var $hour;
 
/**
* Minute of hour this calendar object e.g. 46
* @access private
* @var int
*/
var $minute;
 
/**
* Second of minute this calendar object e.g. 34
* @access private
* @var int
*/
var $second;
 
/**
* Marks this calendar object as selected (e.g. 'today')
* @access private
* @var boolean
*/
var $selected = false;
 
/**
* Collection of child calendar objects created from subclasses
* of Calendar. Type depends on the object which created them.
* @access private
* @var array
*/
var $children = array();
 
/**
* Constructs the Calendar
* @param int year
* @param int month
* @param int day
* @param int hour
* @param int minute
* @param int second
* @access protected
*/
function Calendar($y = 2000, $m = 1, $d = 1, $h = 0, $i = 0, $s = 0)
{
static $cE = null;
if (!isset($cE)) {
$cE = & Calendar_Engine_Factory::getEngine();
}
$this->cE = & $cE;
$this->year = (int)$y;
$this->month = (int)$m;
$this->day = (int)$d;
$this->hour = (int)$h;
$this->minute = (int)$i;
$this->second = (int)$s;
}
 
/**
* Defines the calendar by a timestamp (Unix or ISO-8601), replacing values
* passed to the constructor
* @param int|string Unix or ISO-8601 timestamp
* @return void
* @access public
*/
function setTimestamp($ts)
{
$this->year = $this->cE->stampToYear($ts);
$this->month = $this->cE->stampToMonth($ts);
$this->day = $this->cE->stampToDay($ts);
$this->hour = $this->cE->stampToHour($ts);
$this->minute = $this->cE->stampToMinute($ts);
$this->second = $this->cE->stampToSecond($ts);
}
 
/**
* Returns a timestamp from the current date / time values. Format of
* timestamp depends on Calendar_Engine implementation being used
* @return int|string timestamp
* @access public
*/
function getTimestamp()
{
return $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute, $this->second);
}
 
/**
* Defines calendar object as selected (e.g. for today)
* @param boolean state whether Calendar subclass
* @return void
* @access public
*/
function setSelected($state = true)
{
$this->selected = $state;
}
 
/**
* True if the calendar subclass object is selected (e.g. today)
* @return boolean
* @access public
*/
function isSelected()
{
return $this->selected;
}
 
/**
* Adjusts the date (helper method)
* @return void
* @access public
*/
function adjust()
{
$stamp = $this->getTimeStamp();
$this->year = $this->cE->stampToYear($stamp);
$this->month = $this->cE->stampToMonth($stamp);
$this->day = $this->cE->stampToDay($stamp);
$this->hour = $this->cE->stampToHour($stamp);
$this->minute = $this->cE->stampToMinute($stamp);
$this->second = $this->cE->stampToSecond($stamp);
}
 
/**
* Returns the date as an associative array (helper method)
* @param mixed timestamp (leave empty for current timestamp)
* @return array
* @access public
*/
function toArray($stamp=null)
{
if (is_null($stamp)) {
$stamp = $this->getTimeStamp();
}
return array(
'year' => $this->cE->stampToYear($stamp),
'month' => $this->cE->stampToMonth($stamp),
'day' => $this->cE->stampToDay($stamp),
'hour' => $this->cE->stampToHour($stamp),
'minute' => $this->cE->stampToMinute($stamp),
'second' => $this->cE->stampToSecond($stamp)
);
}
 
/**
* Returns the value as an associative array (helper method)
* @param string type of date object that return value represents
* @param string $format ['int' | 'array' | 'timestamp' | 'object']
* @param mixed timestamp (depending on Calendar engine being used)
* @param int integer default value (i.e. give me the answer quick)
* @return mixed
* @access private
*/
function returnValue($returnType, $format, $stamp, $default)
{
switch (strtolower($format)) {
case 'int':
return $default;
case 'array':
return $this->toArray($stamp);
break;
case 'object':
require_once CALENDAR_ROOT.'Factory.php';
return Calendar_Factory::createByTimestamp($returnType,$stamp);
break;
case 'timestamp':
default:
return $stamp;
break;
}
}
 
/**
* Abstract method for building the children of a calendar object.
* Implemented by Calendar subclasses
* @param array containing Calendar objects to select (optional)
* @return boolean
* @access public
* @abstract
*/
function build($sDates = array())
{
require_once 'PEAR.php';
PEAR::raiseError(
'Calendar::build is abstract', null, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar::build()');
return false;
}
 
/**
* Abstract method for selected data objects called from build
* @param array
* @return boolean
* @access public
* @abstract
*/
function setSelection($sDates)
{
require_once 'PEAR.php';
PEAR::raiseError(
'Calendar::setSelection is abstract', null, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar::setSelection()');
return false;
}
 
/**
* Iterator method for fetching child Calendar subclass objects
* (e.g. a minute from an hour object). On reaching the end of
* the collection, returns false and resets the collection for
* further iteratations.
* @return mixed either an object subclass of Calendar or false
* @access public
*/
function fetch()
{
$child = each($this->children);
if ($child) {
return $child['value'];
} else {
reset($this->children);
return false;
}
}
 
/**
* Fetches all child from the current collection of children
* @return array
* @access public
*/
function fetchAll()
{
return $this->children;
}
 
/**
* Get the number Calendar subclass objects stored in the internal
* collection.
* @return int
* @access public
*/
function size()
{
return count($this->children);
}
 
/**
* Determine whether this date is valid, with the bounds determined by
* the Calendar_Engine. The call is passed on to
* Calendar_Validator::isValid
* @return boolean
* @access public
*/
function isValid()
{
$validator = & $this->getValidator();
return $validator->isValid();
}
 
/**
* Returns an instance of Calendar_Validator
* @return Calendar_Validator
* @access public
*/
function & getValidator()
{
if (!isset($this->validator)) {
require_once CALENDAR_ROOT.'Validator.php';
$this->validator = & new Calendar_Validator($this);
}
return $this->validator;
}
 
/**
* Returns a reference to the current Calendar_Engine being used. Useful
* for Calendar_Table_Helper and Caledar_Validator
* @return object implementing Calendar_Engine_Inteface
* @access private
*/
function & getEngine()
{
return $this->cE;
}
 
/**
* Returns the value for the previous year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2002 or timestamp
* @access public
*/
function prevYear($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year-1, 1, 1, 0, 0, 0);
return $this->returnValue('Year', $format, $ts, $this->year-1);
}
 
/**
* Returns the value for this year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2003 or timestamp
* @access public
*/
function thisYear($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year, 1, 1, 0, 0, 0);
return $this->returnValue('Year', $format, $ts, $this->year);
}
 
/**
* Returns the value for next year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2004 or timestamp
* @access public
*/
function nextYear($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year+1, 1, 1, 0, 0, 0);
return $this->returnValue('Year', $format, $ts, $this->year+1);
}
 
/**
* Returns the value for the previous month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 4 or Unix timestamp
* @access public
*/
function prevMonth($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year, $this->month-1, 1, 0, 0, 0);
return $this->returnValue('Month', $format, $ts, $this->cE->stampToMonth($ts));
}
 
/**
* Returns the value for this month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 5 or timestamp
* @access public
*/
function thisMonth($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year, $this->month, 1, 0, 0, 0);
return $this->returnValue('Month', $format, $ts, $this->month);
}
 
/**
* Returns the value for next month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 6 or timestamp
* @access public
*/
function nextMonth($format = 'int')
{
$ts = $this->cE->dateToStamp($this->year, $this->month+1, 1, 0, 0, 0);
return $this->returnValue('Month', $format, $ts, $this->cE->stampToMonth($ts));
}
 
/**
* Returns the value for the previous day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 10 or timestamp
* @access public
*/
function prevDay($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day-1, 0, 0, 0);
return $this->returnValue('Day', $format, $ts, $this->cE->stampToDay($ts));
}
 
/**
* Returns the value for this day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 11 or timestamp
* @access public
*/
function thisDay($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day, 0, 0, 0);
return $this->returnValue('Day', $format, $ts, $this->day);
}
 
/**
* Returns the value for the next day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 12 or timestamp
* @access public
*/
function nextDay($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day+1, 0, 0, 0);
return $this->returnValue('Day', $format, $ts, $this->cE->stampToDay($ts));
}
 
/**
* Returns the value for the previous hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 13 or timestamp
* @access public
*/
function prevHour($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day, $this->hour-1, 0, 0);
return $this->returnValue('Hour', $format, $ts, $this->cE->stampToHour($ts));
}
 
/**
* Returns the value for this hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 14 or timestamp
* @access public
*/
function thisHour($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day, $this->hour, 0, 0);
return $this->returnValue('Hour', $format, $ts, $this->hour);
}
 
/**
* Returns the value for the next hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 14 or timestamp
* @access public
*/
function nextHour($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day, $this->hour+1, 0, 0);
return $this->returnValue('Hour', $format, $ts, $this->cE->stampToHour($ts));
}
 
/**
* Returns the value for the previous minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 23 or timestamp
* @access public
*/
function prevMinute($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute-1, 0);
return $this->returnValue('Minute', $format, $ts, $this->cE->stampToMinute($ts));
}
 
/**
* Returns the value for this minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 24 or timestamp
* @access public
*/
function thisMinute($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute, 0);
return $this->returnValue('Minute', $format, $ts, $this->minute);
}
 
/**
* Returns the value for the next minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 25 or timestamp
* @access public
*/
function nextMinute($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute+1, 0);
return $this->returnValue('Minute', $format, $ts, $this->cE->stampToMinute($ts));
}
 
/**
* Returns the value for the previous second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 43 or timestamp
* @access public
*/
function prevSecond($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute, $this->second-1);
return $this->returnValue('Second', $format, $ts, $this->cE->stampToSecond($ts));
}
 
/**
* Returns the value for this second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 44 or timestamp
* @access public
*/
function thisSecond($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute, $this->second);
return $this->returnValue('Second', $format, $ts, $this->second);
}
 
/**
* Returns the value for the next second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 45 or timestamp
* @access public
*/
function nextSecond($format = 'int')
{
$ts = $this->cE->dateToStamp(
$this->year, $this->month, $this->day,
$this->hour, $this->minute, $this->second+1);
return $this->returnValue('Second', $format, $ts, $this->cE->stampToSecond($ts));
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Second.php
New file
0,0 → 1,98
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Second.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Second.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Second<br />
* <b>Note:</b> Seconds do not build other objects
* so related methods are overridden to return NULL
* @package Calendar
*/
class Calendar_Second extends Calendar
{
/**
* Constructs Second
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int day e.g. 11
* @param int hour e.g. 13
* @param int minute e.g. 31
* @param int second e.g. 45
*/
function Calendar_Second($y, $m, $d, $h, $i, $s)
{
Calendar::Calendar($y, $m, $d, $h, $i, $s);
}
 
/**
* Overwrite build
* @return NULL
*/
function build()
{
return null;
}
 
/**
* Overwrite fetch
* @return NULL
*/
function fetch()
{
return null;
}
 
/**
* Overwrite fetchAll
* @return NULL
*/
function fetchAll()
{
return null;
}
 
/**
* Overwrite size
* @return NULL
*/
function size()
{
return null;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/validator_unit_test.php
New file
0,0 → 1,210
<?php
// $Id: validator_unit_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
Mock::generate('Calendar_Engine_Interface','Mock_Calendar_Engine');
Mock::generate('Calendar_Second','Mock_Calendar_Second');
 
class TestOfValidator extends UnitTestCase {
var $mockengine;
var $mockcal;
function TestOfValidator() {
$this->UnitTestCase('Test of Validator');
}
function setUp() {
$this->mockengine = new Mock_Calendar_Engine($this);
$this->mockengine->setReturnValue('getMinYears',1970);
$this->mockengine->setReturnValue('getMaxYears',2037);
$this->mockengine->setReturnValue('getMonthsInYear',12);
$this->mockengine->setReturnValue('getDaysInMonth',30);
$this->mockengine->setReturnValue('getHoursInDay',24);
$this->mockengine->setReturnValue('getMinutesInHour',60);
$this->mockengine->setReturnValue('getSecondsInMinute',60);
$this->mockcal = new Mock_Calendar_Second($this);
$this->mockcal->setReturnValue('getEngine',$this->mockengine);
}
function tearDown() {
unset ($this->mockengine);
unset ($this->mocksecond);
}
function testIsValidYear() {
$this->mockcal->setReturnValue('thisYear',2000);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidYear());
}
function testIsValidYearTooSmall() {
$this->mockcal->setReturnValue('thisYear',1969);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidYear());
}
function testIsValidYearTooLarge() {
$this->mockcal->setReturnValue('thisYear',2038);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidYear());
}
function testIsValidMonth() {
$this->mockcal->setReturnValue('thisMonth',10);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidMonth());
}
function testIsValidMonthTooSmall() {
$this->mockcal->setReturnValue('thisMonth',0);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidMonth());
}
function testIsValidMonthTooLarge() {
$this->mockcal->setReturnValue('thisMonth',13);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidMonth());
}
function testIsValidDay() {
$this->mockcal->setReturnValue('thisDay',10);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidDay());
}
function testIsValidDayTooSmall() {
$this->mockcal->setReturnValue('thisDay',0);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidDay());
}
function testIsValidDayTooLarge() {
$this->mockcal->setReturnValue('thisDay',31);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidDay());
}
function testIsValidHour() {
$this->mockcal->setReturnValue('thisHour',10);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidHour());
}
function testIsValidHourTooSmall() {
$this->mockcal->setReturnValue('thisHour',-1);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidHour());
}
function testIsValidHourTooLarge() {
$this->mockcal->setReturnValue('thisHour',24);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidHour());
}
function testIsValidMinute() {
$this->mockcal->setReturnValue('thisMinute',30);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidMinute());
}
function testIsValidMinuteTooSmall() {
$this->mockcal->setReturnValue('thisMinute',-1);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidMinute());
}
function testIsValidMinuteTooLarge() {
$this->mockcal->setReturnValue('thisMinute',60);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidMinute());
}
function testIsValidSecond() {
$this->mockcal->setReturnValue('thisSecond',30);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValidSecond());
}
function testIsValidSecondTooSmall() {
$this->mockcal->setReturnValue('thisSecond',-1);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidSecond());
}
function testIsValidSecondTooLarge() {
$this->mockcal->setReturnValue('thisSecond',60);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValidSecond());
}
function testIsValid() {
$this->mockcal->setReturnValue('thisYear',2000);
$this->mockcal->setReturnValue('thisMonth',5);
$this->mockcal->setReturnValue('thisDay',15);
$this->mockcal->setReturnValue('thisHour',13);
$this->mockcal->setReturnValue('thisMinute',30);
$this->mockcal->setReturnValue('thisSecond',40);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertTrue($Validator->isValid());
}
function testIsValidAllWrong() {
$this->mockcal->setReturnValue('thisYear',2038);
$this->mockcal->setReturnValue('thisMonth',13);
$this->mockcal->setReturnValue('thisDay',31);
$this->mockcal->day = 31;
$this->mockcal->setReturnValue('thisHour',24);
$this->mockcal->setReturnValue('thisMinute',60);
$this->mockcal->setReturnValue('thisSecond',60);
$Validator = & new Calendar_Validator($this->mockcal);
$this->assertFalse($Validator->isValid());
$i = 0;
while ( $Validator->fetch() ) {
$i++;
}
$this->assertEqual($i,6);
}
}
 
class TestOfValidatorLive extends UnitTestCase {
function TestOfValidatorLive() {
$this->UnitTestCase('Test of Validator Live');
}
function testYear() {
$Unit = new Calendar_Year(2038);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidYear());
}
function testMonth() {
$Unit = new Calendar_Month(2000,13);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidMonth());
}
/*
function testWeek() {
$Unit = new Calendar_Week(2000,12,7);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidWeek());
}
*/
function testDay() {
$Unit = new Calendar_Day(2000,12,32);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidDay());
}
function testHour() {
$Unit = new Calendar_Hour(2000,12,20,24);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidHour());
}
function testMinute() {
$Unit = new Calendar_Minute(2000,12,20,23,60);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidMinute());
}
function testSecond() {
$Unit = new Calendar_Second(2000,12,20,23,59,60);
$Validator = & $Unit->getValidator();
$this->assertFalse($Validator->isValidSecond());
}
function testAllBad() {
$Unit = new Calendar_Second(2000,13,32,24,60,60);
$this->assertFalse($Unit->isValid());
$Validator = & $Unit->getValidator();
$i = 0;
while ( $Validator->fetch() ) {
$i++;
}
$this->assertEqual($i,5);
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfValidator();
$test->run(new HtmlReporter());
$test = &new TestOfValidatorLive();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/month_test.php
New file
0,0 → 1,119
<?php
// $Id: month_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfMonth extends TestOfCalendar {
function TestOfMonth() {
$this->UnitTestCase('Test of Month');
}
function setUp() {
$this->cal = new Calendar_Month(2003,10);
}
function testPrevMonth_Object() {
$this->assertEqual(new Calendar_Month(2003, 9), $this->cal->prevMonth('object'));
}
function testPrevDay () {
$this->assertEqual(30,$this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 9,
'day' => 30,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(1,$this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(2,$this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(23,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,10,1,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfMonthBuild extends TestOfMonth {
function TestOfMonthBuild() {
$this->UnitTestCase('Test of Month::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(31,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(31,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 1;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Day.php');
$selection = array(new Calendar_Day(2003,10,25));
$this->cal->build($selection);
$i = 1;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 25 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfMonth();
$test->run(new HtmlReporter());
$test = &new TestOfMonthBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/decorator_textual_test.php
New file
0,0 → 1,174
<?php
// $Id: decorator_textual_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./decorator_test.php');
 
class TestOfDecoratorTextual extends TestOfDecorator {
function TestOfDecoratorTextual() {
$this->UnitTestCase('Test of Calendar_Decorator_Textual');
}
function testMonthNamesLong() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$monthNames = array(
1=>'January',
2=>'February',
3=>'March',
4=>'April',
5=>'May',
6=>'June',
7=>'July',
8=>'August',
9=>'September',
10=>'October',
11=>'November',
12=>'December',
);
$this->assertEqual($monthNames,$Textual->monthNames());
}
function testMonthNamesShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$monthNames = array(
1=>'Jan',
2=>'Feb',
3=>'Mar',
4=>'Apr',
5=>'May',
6=>'Jun',
7=>'Jul',
8=>'Aug',
9=>'Sep',
10=>'Oct',
11=>'Nov',
12=>'Dec',
);
$this->assertEqual($monthNames,$Textual->monthNames('short'));
}
function testMonthNamesTwo() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$monthNames = array(
1=>'Ja',
2=>'Fe',
3=>'Ma',
4=>'Ap',
5=>'Ma',
6=>'Ju',
7=>'Ju',
8=>'Au',
9=>'Se',
10=>'Oc',
11=>'No',
12=>'De',
);
$this->assertEqual($monthNames,$Textual->monthNames('two'));
}
function testMonthNamesOne() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$monthNames = array(
1=>'J',
2=>'F',
3=>'M',
4=>'A',
5=>'M',
6=>'J',
7=>'J',
8=>'A',
9=>'S',
10=>'O',
11=>'N',
12=>'D',
);
$this->assertEqual($monthNames,$Textual->monthNames('one'));
}
function testWeekdayNamesLong() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$weekdayNames = array(
0=>'Sunday',
1=>'Monday',
2=>'Tuesday',
3=>'Wednesday',
4=>'Thursday',
5=>'Friday',
6=>'Saturday',
);
$this->assertEqual($weekdayNames,$Textual->weekdayNames());
}
function testWeekdayNamesShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$weekdayNames = array(
0=>'Sun',
1=>'Mon',
2=>'Tue',
3=>'Wed',
4=>'Thu',
5=>'Fri',
6=>'Sat',
);
$this->assertEqual($weekdayNames,$Textual->weekdayNames('short'));
}
function testWeekdayNamesTwo() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$weekdayNames = array(
0=>'Su',
1=>'Mo',
2=>'Tu',
3=>'We',
4=>'Th',
5=>'Fr',
6=>'Sa',
);
$this->assertEqual($weekdayNames,$Textual->weekdayNames('two'));
}
function testWeekdayNamesOne() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$weekdayNames = array(
0=>'S',
1=>'M',
2=>'T',
3=>'W',
4=>'T',
5=>'F',
6=>'S',
);
$this->assertEqual($weekdayNames,$Textual->weekdayNames('one'));
}
function testPrevMonthNameShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$this->assertEqual('Sep',$Textual->prevMonthName('short'));
}
function testThisMonthNameShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$this->assertEqual('Oct',$Textual->thisMonthName('short'));
}
function testNextMonthNameShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$this->assertEqual('Nov',$Textual->nextMonthName('short'));
}
function testThisDayNameShort() {
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$this->assertEqual('Wed',$Textual->thisDayName('short'));
}
function testOrderedWeekdaysShort() {
$weekdayNames = array(
0=>'Sun',
1=>'Mon',
2=>'Tue',
3=>'Wed',
4=>'Thu',
5=>'Fri',
6=>'Sat',
);
$Textual = new Calendar_Decorator_Textual($this->mockcal);
$this->assertEqual($weekdayNames,$Textual->orderedWeekdays('short'));
}
 
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfDecoratorTextual();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/week_test.php
New file
0,0 → 1,226
<?php
// $Id: week_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfWeek extends TestOfCalendar {
function TestOfWeek() {
$this->UnitTestCase('Test of Week');
}
function setUp() {
$this->cal = new Calendar_Week(2003, 10, 9, 1); //force firstDay = monday
//print_r($this->cal);
}
function testPrevDay () {
$this->assertEqual(8, $this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 8,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(9, $this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(10, $this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(23, $this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0, $this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1, $this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59, $this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0, $this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1, $this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59, $this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0, $this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1, $this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,10,9,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
function testNewTimeStamp() {
$stamp = mktime(0,0,0,7,28,2004);
$this->cal->setTimestamp($stamp);
$this->assertEqual('30 2004', date('W Y', $this->cal->prevWeek(true)));
$this->assertEqual('31 2004', date('W Y', $this->cal->thisWeek(true)));
$this->assertEqual('32 2004', date('W Y', $this->cal->nextWeek(true)));
}
function testPrevWeekInMonth() {
$this->assertEqual(1, $this->cal->prevWeek());
}
function testThisWeekInMonth() {
$this->assertEqual(2, $this->cal->thisWeek());
}
function testNextWeekInMonth() {
$this->assertEqual(3, $this->cal->nextWeek());
}
function testPrevWeekInYear() {
$this->assertEqual(40, $this->cal->prevWeek('n_in_year'));
}
function testThisWeekInYear() {
$this->assertEqual(41, $this->cal->thisWeek('n_in_year'));
}
function testNextWeekInYear() {
$this->assertEqual(42, $this->cal->nextWeek('n_in_year'));
}
function testPrevWeekArray() {
$testArray = array(
'year'=>2003,
'month'=>9,
'day'=>29,
'hour'=>0,
'minute'=>0,
'second'=>0
);
$this->assertEqual($testArray, $this->cal->prevWeek('array'));
}
function testThisWeekArray() {
$testArray = array(
'year'=>2003,
'month'=>10,
'day'=>6,
'hour'=>0,
'minute'=>0,
'second'=>0
);
$this->assertEqual($testArray, $this->cal->thisWeek('array'));
}
function testNextWeekArray() {
$testArray = array(
'year'=>2003,
'month'=>10,
'day'=>13,
'hour'=>0,
'minute'=>0,
'second'=>0
);
$this->assertEqual($testArray, $this->cal->nextWeek('array'));
}
function testPrevWeekObject() {
$testWeek = new Calendar_Week(2003,9,29);
$Week = $this->cal->prevWeek('object');
$this->assertEqual($testWeek->getTimeStamp(),$Week->getTimeStamp());
}
function testThisWeekObject() {
$testWeek = new Calendar_Week(2003,10,6);
$Week = $this->cal->thisWeek('object');
$this->assertEqual($testWeek->getTimeStamp(),$Week->getTimeStamp());
}
function testNextWeekObject() {
$testWeek = new Calendar_Week(2003,10,13);
$Week = $this->cal->nextWeek('object');
$this->assertEqual($testWeek->getTimeStamp(),$Week->getTimeStamp());
}
}
 
class TestOfWeekBuild extends TestOfWeek {
function TestOfWeekBuild() {
$this->UnitTestCase('Test of Week::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(7, $this->cal->size());
}
 
function testFetch() {
$this->cal->build();
$i=0;
while ($Child = $this->cal->fetch()) {
$i++;
}
$this->assertEqual(7, $i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 1;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
 
function testSelection() {
require_once(CALENDAR_ROOT . 'Day.php');
$selection = array(new Calendar_Day(2003, 10, 7));
$this->cal->build($selection);
$i = 1;
while ($Child = $this->cal->fetch()) {
if ($i == 2) {
break; //07-10-2003 is the 2nd day of the week
}
$i++;
}
$this->assertTrue($Child->isSelected());
}
function testSelectionCornerCase() {
require_once(CALENDAR_ROOT . 'Day.php');
+
+
+
+
+
+
+
+ new Calendar_Day(2004, 01, 03)
+ );
+ $this->cal = new Calendar_Week(2003, 12, 31, 0);
+
+
+ $this->assertTrue($Day->isSelected());
+ }
+
+
+
+ $this->assertTrue($Day->isSelected());
+ }
+ }
+}
+if (!defined('TEST_RUNNING')) {
+ define('TEST_RUNNING', true);
+ $test = &new TestOfWeek();
+ $test->run(new HtmlReporter());
+ $test = &new TestOfWeekBuild();
+ $test->run(new HtmlReporter());
+}
+?>
\ No newline at end of file
/branches/v1.0-menes/api/pear/Calendar/tests/all_tests.php
New file
0,0 → 1,34
<?php
// $Id: all_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
define("TEST_RUNNING", true);
 
require_once('./calendar_tests.php');
require_once('./calendar_tabular_tests.php');
require_once('./validator_tests.php');
require_once('./calendar_engine_tests.php');
require_once('./calendar_engine_tests.php');
require_once('./table_helper_tests.php');
require_once('./decorator_tests.php');
require_once('./util_tests.php');
 
 
class AllTests extends GroupTest {
function AllTests() {
$this->GroupTest('All PEAR::Calendar Tests');
$this->AddTestCase(new CalendarTests());
$this->AddTestCase(new CalendarTabularTests());
$this->AddTestCase(new ValidatorTests());
$this->AddTestCase(new CalendarEngineTests());
$this->AddTestCase(new TableHelperTests());
$this->AddTestCase(new DecoratorTests());
$this->AddTestCase(new UtilTests());
}
}
 
$test = &new AllTests();
$test->run(new HtmlReporter());
?>
/branches/v1.0-menes/api/pear/Calendar/tests/util_uri_test.php
New file
0,0 → 1,54
<?php
// $Id: util_uri_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
Mock::generate('Calendar_Day','Mock_Calendar_Day');
Mock::generate('Calendar_Engine_Interface','Mock_Calendar_Engine');
 
class TestOfUtilUri extends UnitTestCase {
 
var $MockCal;
function TestOfUtilUri() {
$this->UnitTestCase('Test of Calendar_Util_Uri');
}
function setUp() {
$this->MockCal = & new Mock_Calendar_Day($this);
$this->MockCal->setReturnValue('getEngine',new Mock_Calendar_Engine($this));
}
function testFragments() {
$Uri = new Calendar_Util_Uri('y','m','d','h','m','s');
$Uri->setFragments('year','month','day','hour','minute','second');
$this->assertEqual(
'year=&amp;month=&amp;day=&amp;hour=&amp;minute=&amp;second=',
$Uri->this($this->MockCal, 'second')
);
}
function testScalarFragments() {
$Uri = new Calendar_Util_Uri('year','month','day','hour','minute','second');
$Uri->scalar = true;
$this->assertEqual(
'&amp;&amp;&amp;&amp;&amp;',
$Uri->this($this->MockCal, 'second')
);
}
function testSetSeperator() {
$Uri = new Calendar_Util_Uri('year','month','day','hour','minute','second');
$Uri->separator = '/';
$this->assertEqual(
'year=/month=/day=/hour=/minute=/second=',
$Uri->this($this->MockCal, 'second')
);
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfUtilUri();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/calendar_tests.php
New file
0,0 → 1,25
<?php
// $Id: calendar_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class CalendarTests extends GroupTest {
function CalendarTests() {
$this->GroupTest('Calendar Tests');
$this->addTestFile('calendar_test.php');
$this->addTestFile('year_test.php');
$this->addTestFile('month_test.php');
$this->addTestFile('day_test.php');
$this->addTestFile('hour_test.php');
$this->addTestFile('minute_test.php');
$this->addTestFile('second_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new CalendarTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/simple_include.php
New file
0,0 → 1,10
<?php
// $Id: simple_include.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
if (!defined('SIMPLE_TEST')) {
define('SIMPLE_TEST', '../../../simpletest/');
}
 
require_once(SIMPLE_TEST . 'unit_tester.php');
require_once(SIMPLE_TEST . 'reporter.php');
require_once(SIMPLE_TEST . 'mock_objects.php');
?>
/branches/v1.0-menes/api/pear/Calendar/tests/validator_error_test.php
New file
0,0 → 1,34
<?php
// $Id: validator_error_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class TestOfValidationError extends UnitTestCase {
var $vError;
function TestOfValidationError() {
$this->UnitTestCase('Test of Validation Error');
}
function setUp() {
$this->vError = new Calendar_Validation_Error('foo',20,'bar');
}
function testGetUnit() {
$this->assertEqual($this->vError->getUnit(),'foo');
}
function testGetValue() {
$this->assertEqual($this->vError->getValue(),20);
}
function testGetMessage() {
$this->assertEqual($this->vError->getMessage(),'bar');
}
function testToString() {
$this->assertEqual($this->vError->toString(),'foo = 20 [bar]');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfValidationError();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/year_test.php
New file
0,0 → 1,142
<?php
// $Id: year_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfYear extends TestOfCalendar {
function TestOfYear() {
$this->UnitTestCase('Test of Year');
}
function setUp() {
$this->cal = new Calendar_Year(2003);
}
function testPrevYear_Object() {
$this->assertEqual(new Calendar_Year(2002), $this->cal->prevYear('object'));
}
function testThisYear_Object() {
$this->assertEqual(new Calendar_Year(2003), $this->cal->thisYear('object'));
}
function testPrevMonth () {
$this->assertEqual(12,$this->cal->prevMonth());
}
function testPrevMonth_Array () {
$this->assertEqual(
array(
'year' => 2002,
'month' => 12,
'day' => 1,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevMonth('array'));
}
function testThisMonth () {
$this->assertEqual(1,$this->cal->thisMonth());
}
function testNextMonth () {
$this->assertEqual(2,$this->cal->nextMonth());
}
function testPrevDay () {
$this->assertEqual(31,$this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2002,
'month' => 12,
'day' => 31,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(1,$this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(2,$this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(23,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,1,1,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfYearBuild extends TestOfYear {
function TestOfYearBuild() {
$this->UnitTestCase('Test of Year::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(12,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(12,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 1;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Month.php');
$selection = array(new Calendar_Month(2003,10));
$this->cal->build($selection);
$i = 1;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 10 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfYear();
$test->run(new HtmlReporter());
$test = &new TestOfYearBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/util_tests.php
New file
0,0 → 1,20
<?php
// $Id: util_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class UtilTests extends GroupTest {
function UtilTests() {
$this->GroupTest('Util Tests');
$this->addTestFile('util_uri_test.php');
$this->addTestFile('util_textual_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new UtilTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/decorator_uri_test.php
New file
0,0 → 1,37
<?php
// $Id: decorator_uri_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./decorator_test.php');
 
class TestOfDecoratorUri extends TestOfDecorator {
function TestOfDecoratorUri() {
$this->UnitTestCase('Test of Calendar_Decorator_Uri');
}
function testFragments() {
$Uri = new Calendar_Decorator_Uri($this->mockcal);
$Uri->setFragments('year','month','day','hour','minute','second');
$this->assertEqual('year=&amp;month=&amp;day=&amp;hour=&amp;minute=&amp;second=',$Uri->this('second'));
}
function testScalarFragments() {
$Uri = new Calendar_Decorator_Uri($this->mockcal);
$Uri->setFragments('year','month','day','hour','minute','second');
$Uri->setScalar();
$this->assertEqual('&amp;&amp;&amp;&amp;&amp;',$Uri->this('second'));
}
function testSetSeperator() {
$Uri = new Calendar_Decorator_Uri($this->mockcal);
$Uri->setFragments('year','month','day','hour','minute','second');
$Uri->setSeparator('/');
$this->assertEqual('year=/month=/day=/hour=/minute=/second=',$Uri->this('second'));
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfDecoratorUri();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/minute_test.php
New file
0,0 → 1,99
<?php
// $Id: minute_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfMinute extends TestOfCalendar {
function TestOfMinute() {
$this->UnitTestCase('Test of Minute');
}
function setUp() {
$this->cal = new Calendar_Minute(2003,10,25,13,32);
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 24,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testThisSecond_Timestamp () {
$this->assertEqual($this->cal->cE->dateToStamp(
2003, 10, 25, 13, 32, 0),
$this->cal->thisSecond('timestamp'));
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testNextSecond_Timestamp () {
$this->assertEqual($this->cal->cE->dateToStamp(
2003, 10, 25, 13, 32, 1),
$this->cal->nextSecond('timestamp'));
}
function testGetTimeStamp() {
$stamp = mktime(13,32,0,10,25,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfMinuteBuild extends TestOfMinute {
function TestOfMinuteBuild() {
$this->UnitTestCase('Test of Minute::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(60,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(60,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 0;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Second.php');
$selection = array(new Calendar_Second(2003,10,25,13,32,43));
$this->cal->build($selection);
$i = 0;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 43 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfMinute();
$test->run(new HtmlReporter());
$test = &new TestOfMinuteBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/decorator_tests.php
New file
0,0 → 1,21
<?php
// $Id: decorator_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class DecoratorTests extends GroupTest {
function DecoratorTests() {
$this->GroupTest('Decorator Tests');
$this->addTestFile('decorator_test.php');
$this->addTestFile('decorator_textual_test.php');
$this->addTestFile('decorator_uri_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new DecoratorTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/calendar_tabular_tests.php
New file
0,0 → 1,21
<?php
// $Id: calendar_tabular_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class CalendarTabularTests extends GroupTest {
function CalendarTabularTests() {
$this->GroupTest('Calendar Tabular Tests');
$this->addTestFile('month_weekdays_test.php');
$this->addTestFile('month_weeks_test.php');
$this->addTestFile('week_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new CalendarTabularTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/validator_tests.php
New file
0,0 → 1,20
<?php
// $Id: validator_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class ValidatorTests extends GroupTest {
function ValidatorTests() {
$this->GroupTest('Validator Tests');
$this->addTestFile('validator_unit_test.php');
$this->addTestFile('validator_error_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new ValidatorTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/README
New file
0,0 → 1,7
These tests require Simple Test: http://www.lastcraft.com/simple_test.php
 
Ideally they would use PEAR::PHPUnit but the current version has bugs and
lacks alot of the functionality (e.g. Mock Objects) which Simple Test
provides.
 
Modifying the simple_include.php script for your simple test install dir
/branches/v1.0-menes/api/pear/Calendar/tests/table_helper_tests.php
New file
0,0 → 1,19
<?php
// $Id: table_helper_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class TableHelperTests extends GroupTest {
function TableHelperTests() {
$this->GroupTest('Table Helper Tests');
$this->addTestFile('helper_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TableHelperTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/calendar_test.php
New file
0,0 → 1,115
<?php
// $Id: calendar_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class TestOfCalendar extends UnitTestCase {
var $cal;
function TestOfCalendar($name='Test of Calendar') {
$this->UnitTestCase($name);
}
function setUp() {
$this->cal = new Calendar(2003,10,25,13,32,43);
}
function tearDown() {
unset($this->cal);
}
function testPrevYear () {
$this->assertEqual(2002,$this->cal->prevYear());
}
function testPrevYear_Array () {
$this->assertEqual(
array(
'year' => 2002,
'month' => 1,
'day' => 1,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevYear('array'));
}
function testThisYear () {
$this->assertEqual(2003,$this->cal->thisYear());
}
function testNextYear () {
$this->assertEqual(2004,$this->cal->nextYear());
}
function testPrevMonth () {
$this->assertEqual(9,$this->cal->prevMonth());
}
function testPrevMonth_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 9,
'day' => 1,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevMonth('array'));
}
function testThisMonth () {
$this->assertEqual(10,$this->cal->thisMonth());
}
function testNextMonth () {
$this->assertEqual(11,$this->cal->nextMonth());
}
function testPrevDay () {
$this->assertEqual(24,$this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 24,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(25,$this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(26,$this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(12,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(13,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(14,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(31,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(32,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(33,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(42,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(43,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(44,$this->cal->nextSecond());
}
function testSetTimeStamp() {
$stamp = mktime(13,32,43,10,25,2003);
$this->cal->setTimeStamp($stamp);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
function testGetTimeStamp() {
$stamp = mktime(13,32,43,10,25,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/peardate_engine_test.php
New file
0,0 → 1,124
<?php
// $Id: peardate_engine_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class TestOfPearDateEngine extends UnitTestCase {
var $engine;
function TestOfPearDateEngine() {
$this->UnitTestCase('Test of Calendar_Engine_PearDate');
}
function setUp() {
$this->engine = new Calendar_Engine_PearDate();
}
function testGetSecondsInMinute() {
$this->assertEqual($this->engine->getSecondsInMinute(),60);
}
function testGetMinutesInHour() {
$this->assertEqual($this->engine->getMinutesInHour(),60);
}
function testGetHoursInDay() {
$this->assertEqual($this->engine->getHoursInDay(),24);
}
function testGetFirstDayOfWeek() {
$this->assertEqual($this->engine->getFirstDayOfWeek(),1);
}
function testGetWeekDays() {
$this->assertEqual($this->engine->getWeekDays(),array(0,1,2,3,4,5,6));
}
function testGetDaysInWeek() {
$this->assertEqual($this->engine->getDaysInWeek(),7);
}
function testGetWeekNInYear() {
$this->assertEqual($this->engine->getWeekNInYear(2003, 11, 3), 45);
}
function testGetWeekNInMonth() {
$this->assertEqual($this->engine->getWeekNInMonth(2003, 11, 3), 2);
}
function testGetWeeksInMonth0() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 11, 0), 6); //week starts on sunday
}
function testGetWeeksInMonth1() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 11, 1), 5); //week starts on monday
}
function testGetWeeksInMonth2() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 2, 6), 4); //week starts on saturday
}
function testGetWeeksInMonth3() {
// Unusual cases that can cause fails (shows up with example 21.php)
$this->assertEqual($this->engine->getWeeksInMonth(2004,2,1),5);
$this->assertEqual($this->engine->getWeeksInMonth(2004,8,1),6);
}
function testGetDayOfWeek() {
$this->assertEqual($this->engine->getDayOfWeek(2003, 11, 18), 2);
}
function testGetFirstDayInMonth() {
$this->assertEqual($this->engine->getFirstDayInMonth(2003,10),3);
}
function testGetDaysInMonth() {
$this->assertEqual($this->engine->getDaysInMonth(2003,10),31);
}
function testGetMinYears() {
$this->assertEqual($this->engine->getMinYears(),0);
}
function testGetMaxYears() {
$this->assertEqual($this->engine->getMaxYears(),9999);
}
function testDateToStamp() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->dateToStamp(2003,10,15,13,30,45),$stamp);
}
function testStampToSecond() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToSecond($stamp),45);
}
function testStampToMinute() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToMinute($stamp),30);
}
function testStampToHour() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToHour($stamp),13);
}
function testStampToDay() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToDay($stamp),15);
}
function testStampToMonth() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToMonth($stamp),10);
}
function testStampToYear() {
$stamp = '2003-10-15 13:30:45';
$this->assertEqual($this->engine->stampToYear($stamp),2003);
}
function testAdjustDate() {
$stamp = '2004-01-01 13:30:45';
$y = $this->engine->stampToYear($stamp);
$m = $this->engine->stampToMonth($stamp);
$d = $this->engine->stampToDay($stamp);
 
//the first day of the month should be thursday
$this->assertEqual($this->engine->getDayOfWeek($y, $m, $d), 4);
 
$m--; // 2004-00-01 => 2003-12-01
$this->engine->adjustDate($y, $m, $d, $dummy, $dummy, $dummy);
 
$this->assertEqual($y, 2003);
$this->assertEqual($m, 12);
$this->assertEqual($d, 1);
 
// get last day and check if it's wednesday
$d = $this->engine->getDaysInMonth($y, $m);
 
$this->assertEqual($this->engine->getDayOfWeek($y, $m, $d), 3);
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfPearDateEngine();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/second_test.php
New file
0,0 → 1,34
<?php
// $Id: second_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfSecond extends TestOfCalendar {
function TestOfSecond() {
$this->UnitTestCase('Test of Second');
}
function setUp() {
$this->cal = new Calendar_Second(2003,10,25,13,32,43);
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 24,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfSecond();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/hour_test.php
New file
0,0 → 1,98
<?php
// $Id: hour_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfHour extends TestOfCalendar {
function TestOfHour() {
$this->UnitTestCase('Test of Hour');
}
function setUp() {
$this->cal = new Calendar_Hour(2003,10,25,13);
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 24,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(13,0,0,10,25,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfHourBuild extends TestOfHour {
function TestOfHourBuild() {
$this->UnitTestCase('Test of Hour::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(60,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(60,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 0;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Minute.php');
$selection = array(new Calendar_Minute(2003,10,25,13,32));
$this->cal->build($selection);
$i = 0;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 32 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfHour();
$test->run(new HtmlReporter());
$test = &new TestOfHourBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/day_test.php
New file
0,0 → 1,107
<?php
// $Id: day_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfDay extends TestOfCalendar {
function TestOfDay() {
$this->UnitTestCase('Test of Day');
}
function setUp() {
$this->cal = new Calendar_Day(2003,10,25);
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 10,
'day' => 24,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testPrevHour () {
$this->assertEqual(23,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,10,25,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfDayBuild extends TestOfDay {
function TestOfDayBuild() {
$this->UnitTestCase('Test of Day::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(24,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(24,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 0;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Hour.php');
$selection = array(new Calendar_Hour(2003,10,25,13));
$this->cal->build($selection);
$i = 0;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 13 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfDay();
$test->run(new HtmlReporter());
$test = &new TestOfDayBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/calendar_include.php
New file
0,0 → 1,28
<?php
// $Id: calendar_include.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
if ( !@include 'Calendar/Calendar.php' ) {
@define('CALENDAR_ROOT','../');
}
require_once(CALENDAR_ROOT . 'Year.php');
require_once(CALENDAR_ROOT . 'Month.php');
require_once(CALENDAR_ROOT . 'Day.php');
require_once(CALENDAR_ROOT . 'Week.php');
require_once(CALENDAR_ROOT . 'Hour.php');
require_once(CALENDAR_ROOT . 'Minute.php');
require_once(CALENDAR_ROOT . 'Second.php');
require_once(CALENDAR_ROOT . 'Month.php');
require_once(CALENDAR_ROOT . 'Decorator.php');
require_once(CALENDAR_ROOT . 'Month/Weekdays.php');
require_once(CALENDAR_ROOT . 'Month/Weeks.php');
require_once(CALENDAR_ROOT . 'Validator.php');
require_once(CALENDAR_ROOT . 'Engine/Interface.php');
require_once(CALENDAR_ROOT . 'Engine/UnixTs.php');
require_once(CALENDAR_ROOT . 'Engine/PearDate.php');
require_once(CALENDAR_ROOT . 'Table/Helper.php');
require_once(CALENDAR_ROOT . 'Decorator/Textual.php');
require_once(CALENDAR_ROOT . 'Decorator/Uri.php');
require_once(CALENDAR_ROOT . 'Decorator/Weekday.php');
require_once(CALENDAR_ROOT . 'Decorator/Wrapper.php');
require_once(CALENDAR_ROOT . 'Util/Uri.php');
require_once(CALENDAR_ROOT . 'Util/Textual.php');
?>
/branches/v1.0-menes/api/pear/Calendar/tests/helper_test.php
New file
0,0 → 1,83
<?php
// $Id: helper_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
Mock::generate('Calendar_Engine_Interface','Mock_Calendar_Engine');
Mock::generate('Calendar_Second','Mock_Calendar_Second');
 
class TestOfTableHelper extends UnitTestCase {
var $mockengine;
var $mockcal;
function TestOfTableHelper() {
$this->UnitTestCase('Test of Calendar_Table_Helper');
}
function setUp() {
$this->mockengine = new Mock_Calendar_Engine($this);
$this->mockengine->setReturnValue('getMinYears',1970);
$this->mockengine->setReturnValue('getMaxYears',2037);
$this->mockengine->setReturnValue('getMonthsInYear',12);
$this->mockengine->setReturnValue('getDaysInMonth',31);
$this->mockengine->setReturnValue('getHoursInDay',24);
$this->mockengine->setReturnValue('getMinutesInHour',60);
$this->mockengine->setReturnValue('getSecondsInMinute',60);
$this->mockengine->setReturnValue('getWeekDays',array(0,1,2,3,4,5,6));
$this->mockengine->setReturnValue('getDaysInWeek',7);
$this->mockengine->setReturnValue('getFirstDayOfWeek',1);
$this->mockengine->setReturnValue('getFirstDayInMonth',3);
$this->mockcal = new Mock_Calendar_Second($this);
$this->mockcal->setReturnValue('thisYear',2003);
$this->mockcal->setReturnValue('thisMonth',10);
$this->mockcal->setReturnValue('thisDay',15);
$this->mockcal->setReturnValue('thisHour',13);
$this->mockcal->setReturnValue('thisMinute',30);
$this->mockcal->setReturnValue('thisSecond',45);
$this->mockcal->setReturnValue('getEngine',$this->mockengine);
}
function testGetFirstDay() {
for ( $i = 0; $i <= 7; $i++ ) {
$Helper = & new Calendar_Table_Helper($this->mockcal,$i);
$this->assertEqual($Helper->getFirstDay(),$i);
}
}
function testGetDaysOfWeekMonday() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getDaysOfWeek(),array(1,2,3,4,5,6,0));
}
function testGetDaysOfWeekSunday() {
$Helper = & new Calendar_Table_Helper($this->mockcal,0);
$this->assertEqual($Helper->getDaysOfWeek(),array(0,1,2,3,4,5,6));
}
function testGetDaysOfWeekThursday() {
$Helper = & new Calendar_Table_Helper($this->mockcal,4);
$this->assertEqual($Helper->getDaysOfWeek(),array(4,5,6,0,1,2,3));
}
function testGetNumWeeks() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getNumWeeks(),5);
}
function testGetNumTableDaysInMonth() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getNumTableDaysInMonth(),35);
}
function testGetEmptyDaysBefore() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getEmptyDaysBefore(),2);
}
function testGetEmptyDaysAfter() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getEmptyDaysAfter(),33);
}
function testGetEmptyDaysAfterOffset() {
$Helper = & new Calendar_Table_Helper($this->mockcal);
$this->assertEqual($Helper->getEmptyDaysAfterOffset(),5);
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfTableHelper();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/unixts_engine_test.php
New file
0,0 → 1,104
<?php
// $Id: unixts_engine_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class TestOfUnixTsEngine extends UnitTestCase {
var $engine;
function TestOfUnixTsEngine() {
$this->UnitTestCase('Test of Calendar_Engine_UnixTs');
}
function setUp() {
$this->engine = new Calendar_Engine_UnixTs();
}
function testGetSecondsInMinute() {
$this->assertEqual($this->engine->getSecondsInMinute(),60);
}
function testGetMinutesInHour() {
$this->assertEqual($this->engine->getMinutesInHour(),60);
}
function testGetHoursInDay() {
$this->assertEqual($this->engine->getHoursInDay(),24);
}
function testGetFirstDayOfWeek() {
$this->assertEqual($this->engine->getFirstDayOfWeek(),1);
}
function testGetWeekDays() {
$this->assertEqual($this->engine->getWeekDays(),array(0,1,2,3,4,5,6));
}
function testGetDaysInWeek() {
$this->assertEqual($this->engine->getDaysInWeek(),7);
}
function testGetWeekNInYear() {
$this->assertEqual($this->engine->getWeekNInYear(2003, 11, 3), 45);
}
function testGetWeekNInMonth() {
$this->assertEqual($this->engine->getWeekNInMonth(2003, 11, 3), 2);
}
function testGetWeeksInMonth0() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 11, 0), 6); //week starts on sunday
}
function testGetWeeksInMonth1() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 11, 1), 5); //week starts on monday
}
function testGetWeeksInMonth2() {
$this->assertEqual($this->engine->getWeeksInMonth(2003, 2, 6), 4); //week starts on saturday
}
function testGetWeeksInMonth3() {
// Unusual cases that can cause fails (shows up with example 21.php)
$this->assertEqual($this->engine->getWeeksInMonth(2004,2,1),5);
$this->assertEqual($this->engine->getWeeksInMonth(2004,8,1),6);
}
function testGetDayOfWeek() {
$this->assertEqual($this->engine->getDayOfWeek(2003, 11, 18), 2);
}
function testGetFirstDayInMonth() {
$this->assertEqual($this->engine->getFirstDayInMonth(2003,10),3);
}
function testGetDaysInMonth() {
$this->assertEqual($this->engine->getDaysInMonth(2003,10),31);
}
function testGetMinYears() {
$test = strpos(PHP_OS, 'WIN') >= 0 ? 1970 : 1902;
$this->assertEqual($this->engine->getMinYears(),$test);
}
function testGetMaxYears() {
$this->assertEqual($this->engine->getMaxYears(),2037);
}
function testDateToStamp() {
$stamp = mktime(0,0,0,10,15,2003);
$this->assertEqual($this->engine->dateToStamp(2003,10,15,0,0,0),$stamp);
}
function testStampToSecond() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToSecond($stamp),45);
}
function testStampToMinute() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToMinute($stamp),30);
}
function testStampToHour() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToHour($stamp),13);
}
function testStampToDay() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToDay($stamp),15);
}
function testStampToMonth() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToMonth($stamp),10);
}
function testStampToYear() {
$stamp = mktime(13,30,45,10,15,2003);
$this->assertEqual($this->engine->stampToYear($stamp),2003);
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfUnixTsEngine();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/calendar_engine_tests.php
New file
0,0 → 1,20
<?php
// $Id: calendar_engine_tests.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
class CalendarEngineTests extends GroupTest {
function CalendarEngineTests() {
$this->GroupTest('Calendar Engine Tests');
$this->addTestFile('peardate_engine_test.php');
$this->addTestFile('unixts_engine_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new CalendarEngineTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/month_weekdays_test.php
New file
0,0 → 1,130
<?php
// $Id: month_weekdays_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfMonthWeekdays extends TestOfCalendar {
function TestOfMonthWeekdays() {
$this->UnitTestCase('Test of Month Weekdays');
}
function setUp() {
$this->cal = new Calendar_Month_Weekdays(2003,10);
}
function testPrevDay () {
$this->assertEqual(30,$this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 9,
'day' => 30,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(1,$this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(2,$this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(23,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,10,1,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfMonthWeekdaysBuild extends TestOfMonthWeekdays {
function TestOfMonthWeekdaysBuild() {
$this->UnitTestCase('Test of Month_Weekdays::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(35,$this->cal->size());
}
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(35,$i);
}
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 1;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
function testSelection() {
require_once(CALENDAR_ROOT . 'Day.php');
$selection = array(new Calendar_Day(2003,10,25));
$this->cal->build($selection);
$i = 1;
while ( $Child = $this->cal->fetch() ) {
if ( $i == 27 )
break;
$i++;
}
$this->assertTrue($Child->isSelected());
}
function testEmptyCount() {
$this->cal->build();
$empty = 0;
while ( $Child = $this->cal->fetch() ) {
if ( $Child->isEmpty() )
$empty++;
}
$this->assertEqual(4,$empty);
}
function testEmptyDaysBefore_AfterAdjust() {
$this->cal = new Calendar_Month_Weekdays(2004,0);
$this->cal->build();
$this->assertEqual(0,$this->cal->tableHelper->getEmptyDaysBefore());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfMonthWeekdays();
$test->run(new HtmlReporter());
$test = &new TestOfMonthWeekdaysBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/decorator_test.php
New file
0,0 → 1,268
<?php
// $Id: decorator_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
Mock::generate('Calendar_Engine_Interface','Mock_Calendar_Engine');
Mock::generate('Calendar_Second','Mock_Calendar_Second');
Mock::generate('Calendar_Week','Mock_Calendar_Week');
Mock::generate('Calendar_Day','Mock_Calendar_Day');
 
class TestOfDecorator extends UnitTestCase {
var $mockengine;
var $mockcal;
var $decorator;
function TestOfDecorator() {
$this->UnitTestCase('Test of Calendar_Decorator');
}
function setUp() {
$this->mockengine = new Mock_Calendar_Engine($this);
$this->mockcal = new Mock_Calendar_Second($this);
$this->mockcal->setReturnValue('prevYear',2002);
$this->mockcal->setReturnValue('thisYear',2003);
$this->mockcal->setReturnValue('nextYear',2004);
$this->mockcal->setReturnValue('prevMonth',9);
$this->mockcal->setReturnValue('thisMonth',10);
$this->mockcal->setReturnValue('nextMonth',11);
$this->mockcal->setReturnValue('prevDay',14);
$this->mockcal->setReturnValue('thisDay',15);
$this->mockcal->setReturnValue('nextDay',16);
$this->mockcal->setReturnValue('prevHour',12);
$this->mockcal->setReturnValue('thisHour',13);
$this->mockcal->setReturnValue('nextHour',14);
$this->mockcal->setReturnValue('prevMinute',29);
$this->mockcal->setReturnValue('thisMinute',30);
$this->mockcal->setReturnValue('nextMinute',31);
$this->mockcal->setReturnValue('prevSecond',44);
$this->mockcal->setReturnValue('thisSecond',45);
$this->mockcal->setReturnValue('nextSecond',46);
$this->mockcal->setReturnValue('getEngine',$this->mockengine);
$this->mockcal->setReturnValue('getTimestamp',12345);
 
}
function tearDown() {
unset ( $this->engine );
unset ( $this->mockcal );
}
function testPrevYear() {
$this->mockcal->expectOnce('prevYear',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(2002,$Decorator->prevYear());
}
function testThisYear() {
$this->mockcal->expectOnce('thisYear',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(2003,$Decorator->thisYear());
}
function testNextYear() {
$this->mockcal->expectOnce('nextYear',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(2004,$Decorator->nextYear());
}
function testPrevMonth() {
$this->mockcal->expectOnce('prevMonth',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(9,$Decorator->prevMonth());
}
function testThisMonth() {
$this->mockcal->expectOnce('thisMonth',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(10,$Decorator->thisMonth());
}
function testNextMonth() {
$this->mockcal->expectOnce('nextMonth',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(11,$Decorator->nextMonth());
}
function testPrevWeek() {
$mockweek = & new Mock_Calendar_Week($this);
$mockweek->setReturnValue('prevWeek',1);
$mockweek->expectOnce('prevWeek',array('n_in_month'));
$Decorator =& new Calendar_Decorator($mockweek);
$this->assertEqual(1,$Decorator->prevWeek());
}
function testThisWeek() {
$mockweek = & new Mock_Calendar_Week($this);
$mockweek->setReturnValue('thisWeek',2);
$mockweek->expectOnce('thisWeek',array('n_in_month'));
$Decorator =& new Calendar_Decorator($mockweek);
$this->assertEqual(2,$Decorator->thisWeek());
}
function testNextWeek() {
$mockweek = & new Mock_Calendar_Week($this);
$mockweek->setReturnValue('nextWeek',3);
$mockweek->expectOnce('nextWeek',array('n_in_month'));
$Decorator =& new Calendar_Decorator($mockweek);
$this->assertEqual(3,$Decorator->nextWeek());
}
function testPrevDay() {
$this->mockcal->expectOnce('prevDay',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(14,$Decorator->prevDay());
}
function testThisDay() {
$this->mockcal->expectOnce('thisDay',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(15,$Decorator->thisDay());
}
function testNextDay() {
$this->mockcal->expectOnce('nextDay',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(16,$Decorator->nextDay());
}
function testPrevHour() {
$this->mockcal->expectOnce('prevHour',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(12,$Decorator->prevHour());
}
function testThisHour() {
$this->mockcal->expectOnce('thisHour',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(13,$Decorator->thisHour());
}
function testNextHour() {
$this->mockcal->expectOnce('nextHour',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(14,$Decorator->nextHour());
}
function testPrevMinute() {
$this->mockcal->expectOnce('prevMinute',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(29,$Decorator->prevMinute());
}
function testThisMinute() {
$this->mockcal->expectOnce('thisMinute',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(30,$Decorator->thisMinute());
}
function testNextMinute() {
$this->mockcal->expectOnce('nextMinute',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(31,$Decorator->nextMinute());
}
function testPrevSecond() {
$this->mockcal->expectOnce('prevSecond',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(44,$Decorator->prevSecond());
}
function testThisSecond() {
$this->mockcal->expectOnce('thisSecond',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(45,$Decorator->thisSecond());
}
function testNextSecond() {
$this->mockcal->expectOnce('nextSecond',array('int'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(46,$Decorator->nextSecond());
}
function testGetEngine() {
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertIsA($Decorator->getEngine(),'Mock_Calendar_Engine');
}
function testSetTimestamp() {
$this->mockcal->expectOnce('setTimestamp',array('12345'));
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->setTimestamp('12345');
}
function testGetTimestamp() {
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual(12345,$Decorator->getTimestamp());
}
function testSetSelected() {
$this->mockcal->expectOnce('setSelected',array(true));
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->setSelected();
}
function testIsSelected() {
$this->mockcal->setReturnValue('isSelected',true);
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertTrue($Decorator->isSelected());
}
function testAdjust() {
$this->mockcal->expectOnce('adjust',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->adjust();
}
function testToArray() {
$this->mockcal->expectOnce('toArray',array(12345));
$testArray = array('foo'=>'bar');
$this->mockcal->setReturnValue('toArray',$testArray);
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual($testArray,$Decorator->toArray(12345));
}
function testReturnValue() {
$this->mockcal->expectOnce('returnValue',array('a','b','c','d'));
$this->mockcal->setReturnValue('returnValue','foo');
$Decorator =& new Calendar_Decorator($this->mockcal);
$this->assertEqual('foo',$Decorator->returnValue('a','b','c','d'));
}
function testSetFirst() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->expectOnce('setFirst',array(true));
$Decorator =& new Calendar_Decorator($mockday);
$Decorator->setFirst();
}
function testSetLast() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->expectOnce('setLast',array(true));
$Decorator =& new Calendar_Decorator($mockday);
$Decorator->setLast();
}
function testIsFirst() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->setReturnValue('isFirst',TRUE);
$Decorator =& new Calendar_Decorator($mockday);
$this->assertTrue($Decorator->isFirst());
}
function testIsLast() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->setReturnValue('isLast',TRUE);
$Decorator =& new Calendar_Decorator($mockday);
$this->assertTrue($Decorator->isLast());
}
function testSetEmpty() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->expectOnce('setEmpty',array(true));
$Decorator =& new Calendar_Decorator($mockday);
$Decorator->setEmpty();
}
function testIsEmpty() {
$mockday = & new Mock_Calendar_Day($this);
$mockday->setReturnValue('isEmpty',TRUE);
$Decorator =& new Calendar_Decorator($mockday);
$this->assertTrue($Decorator->isEmpty());
}
function testBuild() {
$testArray=array('foo'=>'bar');
$this->mockcal->expectOnce('build',array($testArray));
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->build($testArray);
}
function testFetch() {
$this->mockcal->expectOnce('fetch',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->fetch();
}
function testFetchAll() {
$this->mockcal->expectOnce('fetchAll',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->fetchAll();
}
function testSize() {
$this->mockcal->expectOnce('size',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->size();
}
function testIsValid() {
$this->mockcal->expectOnce('isValid',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->isValid();
}
function testGetValidator() {
$this->mockcal->expectOnce('getValidator',array());
$Decorator =& new Calendar_Decorator($this->mockcal);
$Decorator->getValidator();
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/month_weeks_test.php
New file
0,0 → 1,125
<?php
// $Id: month_weeks_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./calendar_test.php');
 
class TestOfMonthWeeks extends TestOfCalendar {
function TestOfMonthWeeks() {
$this->UnitTestCase('Test of Month Weeks');
}
function setUp() {
$this->cal = new Calendar_Month_Weeks(2003,10);
}
function testPrevDay () {
$this->assertEqual(30,$this->cal->prevDay());
}
function testPrevDay_Array () {
$this->assertEqual(
array(
'year' => 2003,
'month' => 9,
'day' => 30,
'hour' => 0,
'minute' => 0,
'second' => 0),
$this->cal->prevDay('array'));
}
function testThisDay () {
$this->assertEqual(1,$this->cal->thisDay());
}
function testNextDay () {
$this->assertEqual(2,$this->cal->nextDay());
}
function testPrevHour () {
$this->assertEqual(23,$this->cal->prevHour());
}
function testThisHour () {
$this->assertEqual(0,$this->cal->thisHour());
}
function testNextHour () {
$this->assertEqual(1,$this->cal->nextHour());
}
function testPrevMinute () {
$this->assertEqual(59,$this->cal->prevMinute());
}
function testThisMinute () {
$this->assertEqual(0,$this->cal->thisMinute());
}
function testNextMinute () {
$this->assertEqual(1,$this->cal->nextMinute());
}
function testPrevSecond () {
$this->assertEqual(59,$this->cal->prevSecond());
}
function testThisSecond () {
$this->assertEqual(0,$this->cal->thisSecond());
}
function testNextSecond () {
$this->assertEqual(1,$this->cal->nextSecond());
}
function testGetTimeStamp() {
$stamp = mktime(0,0,0,10,1,2003);
$this->assertEqual($stamp,$this->cal->getTimeStamp());
}
}
 
class TestOfMonthWeeksBuild extends TestOfMonthWeeks {
function TestOfMonthWeeksBuild() {
$this->UnitTestCase('Test of Month_Weeks::build()');
}
function testSize() {
$this->cal->build();
$this->assertEqual(5,$this->cal->size());
}
 
function testFetch() {
$this->cal->build();
$i=0;
while ( $Child = $this->cal->fetch() ) {
$i++;
}
$this->assertEqual(5,$i);
}
/* Recusive dependency issue with SimpleTest
function testFetchAll() {
$this->cal->build();
$children = array();
$i = 1;
while ( $Child = $this->cal->fetch() ) {
$children[$i]=$Child;
$i++;
}
$this->assertEqual($children,$this->cal->fetchAll());
}
*/
function testSelection() {
require_once(CALENDAR_ROOT . 'Week.php');
$selection = array(new Calendar_Week(2003, 10, 12));
$this->cal->build($selection);
$i = 1;
while ($Child = $this->cal->fetch()) {
if ($i == 2) {
break; //12-10-2003 is the 2nd day of the week
}
$i++;
}
$this->assertTrue($Child->isSelected());
}
function testEmptyDaysBefore_AfterAdjust() {
$this->cal = new Calendar_Month_Weeks(2004,0);
$this->cal->build();
$this->assertEqual(0,$this->cal->tableHelper->getEmptyDaysBefore());
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfMonthWeeks();
$test->run(new HtmlReporter());
$test = &new TestOfMonthWeeksBuild();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/tests/util_textual_test.php
New file
0,0 → 1,191
<?php
// $Id: util_textual_test.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
 
require_once('simple_include.php');
require_once('calendar_include.php');
 
require_once('./decorator_test.php');
 
class TestOfUtilTextual extends UnitTestCase {
var $mockengine;
var $mockcal;
function TestOfUtilTextual() {
$this->UnitTestCase('Test of Calendar_Util_Textual');
}
function setUp() {
$this->mockengine = new Mock_Calendar_Engine($this);
$this->mockcal = new Mock_Calendar_Second($this);
$this->mockcal->setReturnValue('prevYear',2002);
$this->mockcal->setReturnValue('thisYear',2003);
$this->mockcal->setReturnValue('nextYear',2004);
$this->mockcal->setReturnValue('prevMonth',9);
$this->mockcal->setReturnValue('thisMonth',10);
$this->mockcal->setReturnValue('nextMonth',11);
$this->mockcal->setReturnValue('prevDay',14);
$this->mockcal->setReturnValue('thisDay',15);
$this->mockcal->setReturnValue('nextDay',16);
$this->mockcal->setReturnValue('prevHour',12);
$this->mockcal->setReturnValue('thisHour',13);
$this->mockcal->setReturnValue('nextHour',14);
$this->mockcal->setReturnValue('prevMinute',29);
$this->mockcal->setReturnValue('thisMinute',30);
$this->mockcal->setReturnValue('nextMinute',31);
$this->mockcal->setReturnValue('prevSecond',44);
$this->mockcal->setReturnValue('thisSecond',45);
$this->mockcal->setReturnValue('nextSecond',46);
$this->mockcal->setReturnValue('getEngine',$this->mockengine);
$this->mockcal->setReturnValue('getTimestamp',12345);
}
function tearDown() {
unset ( $this->engine );
unset ( $this->mockcal );
}
function testMonthNamesLong() {
$monthNames = array(
1=>'January',
2=>'February',
3=>'March',
4=>'April',
5=>'May',
6=>'June',
7=>'July',
8=>'August',
9=>'September',
10=>'October',
11=>'November',
12=>'December',
);
$this->assertEqual($monthNames,Calendar_Util_Textual::monthNames());
}
function testMonthNamesShort() {
$monthNames = array(
1=>'Jan',
2=>'Feb',
3=>'Mar',
4=>'Apr',
5=>'May',
6=>'Jun',
7=>'Jul',
8=>'Aug',
9=>'Sep',
10=>'Oct',
11=>'Nov',
12=>'Dec',
);
$this->assertEqual($monthNames,Calendar_Util_Textual::monthNames('short'));
}
function testMonthNamesTwo() {
$monthNames = array(
1=>'Ja',
2=>'Fe',
3=>'Ma',
4=>'Ap',
5=>'Ma',
6=>'Ju',
7=>'Ju',
8=>'Au',
9=>'Se',
10=>'Oc',
11=>'No',
12=>'De',
);
$this->assertEqual($monthNames,Calendar_Util_Textual::monthNames('two'));
}
function testMonthNamesOne() {
$monthNames = array(
1=>'J',
2=>'F',
3=>'M',
4=>'A',
5=>'M',
6=>'J',
7=>'J',
8=>'A',
9=>'S',
10=>'O',
11=>'N',
12=>'D',
);
$this->assertEqual($monthNames,Calendar_Util_Textual::monthNames('one'));
}
function testWeekdayNamesLong() {
$weekdayNames = array(
0=>'Sunday',
1=>'Monday',
2=>'Tuesday',
3=>'Wednesday',
4=>'Thursday',
5=>'Friday',
6=>'Saturday',
);
$this->assertEqual($weekdayNames,Calendar_Util_Textual::weekdayNames());
}
function testWeekdayNamesShort() {
$weekdayNames = array(
0=>'Sun',
1=>'Mon',
2=>'Tue',
3=>'Wed',
4=>'Thu',
5=>'Fri',
6=>'Sat',
);
$this->assertEqual($weekdayNames,Calendar_Util_Textual::weekdayNames('short'));
}
function testWeekdayNamesTwo() {
$weekdayNames = array(
0=>'Su',
1=>'Mo',
2=>'Tu',
3=>'We',
4=>'Th',
5=>'Fr',
6=>'Sa',
);
$this->assertEqual($weekdayNames,Calendar_Util_Textual::weekdayNames('two'));
}
function testWeekdayNamesOne() {
$weekdayNames = array(
0=>'S',
1=>'M',
2=>'T',
3=>'W',
4=>'T',
5=>'F',
6=>'S',
);
$this->assertEqual($weekdayNames,Calendar_Util_Textual::weekdayNames('one'));
}
function testPrevMonthNameShort() {
$this->assertEqual('Sep',Calendar_Util_Textual::prevMonthName($this->mockcal,'short'));
}
function testThisMonthNameShort() {
$this->assertEqual('Oct',Calendar_Util_Textual::thisMonthName($this->mockcal,'short'));
}
function testNextMonthNameShort() {
$this->assertEqual('Nov',Calendar_Util_Textual::nextMonthName($this->mockcal,'short'));
}
function testThisDayNameShort() {
$this->assertEqual('Wed',Calendar_Util_Textual::thisDayName($this->mockcal,'short'));
}
function testOrderedWeekdaysShort() {
$weekdayNames = array(
0=>'Sun',
1=>'Mon',
2=>'Tue',
3=>'Wed',
4=>'Thu',
5=>'Fri',
6=>'Sat',
);
$this->assertEqual($weekdayNames,Calendar_Util_Textual::orderedWeekdays($this->mockcal,'short'));
}
 
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfUtilTextual();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Calendar/Day.php
New file
0,0 → 1,197
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Day.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Day.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Day and builds Hours.
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Day.php';
* $Day = & new Calendar_Day(2003, 10, 21); // Oct 21st 2003
* while ($Hour = & $Day->fetch()) {
* echo $Hour->thisHour().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Day extends Calendar
{
/**
* Marks the Day at the beginning of a week
* @access private
* @var boolean
*/
var $first = false;
 
/**
* Marks the Day at the end of a week
* @access private
* @var boolean
*/
var $last = false;
 
 
/**
* Used for tabular calendars
* @access private
* @var boolean
*/
var $empty = false;
 
/**
* Constructs Calendar_Day
* @param int year e.g. 2003
* @param int month e.g. 8
* @param int day e.g. 15
* @access public
*/
function Calendar_Day($y, $m, $d)
{
Calendar::Calendar($y, $m, $d);
}
 
/**
* Builds the Hours of the Day
* @param array (optional) Caledar_Hour objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates = array())
{
require_once CALENDAR_ROOT.'Hour.php';
 
$hID = $this->cE->getHoursInDay($this->year, $this->month, $this->day);
for ($i=0; $i < $hID; $i++) {
$this->children[$i]=
new Calendar_Hour($this->year, $this->month, $this->day, $i);
}
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates)
{
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()
&& $this->month == $sDate->thisMonth()
&& $this->day == $sDate->thisDay())
{
$key = (int)$sDate->thisHour();
if (isset($this->children[$key])) {
$sDate->setSelected();
$this->children[$key] = $sDate;
}
}
}
}
 
/**
* Defines Day object as first in a week
* Only used by Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setFirst ($state = true)
{
$this->first = $state;
}
 
/**
* Defines Day object as last in a week
* Used only following Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setLast($state = true)
{
$this->last = $state;
}
 
/**
* Returns true if Day object is first in a Week
* Only relevant when Day is created by Calendar_Month_Weekdays::build()
* @return boolean
* @access public
*/
function isFirst() {
return $this->first;
}
 
/**
* Returns true if Day object is last in a Week
* Only relevant when Day is created by Calendar_Month_Weekdays::build()
* @return boolean
* @access public
*/
function isLast()
{
return $this->last;
}
 
/**
* Defines Day object as empty
* Only used by Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setEmpty ($state = true)
{
$this->empty = $state;
}
 
/**
* @return boolean
* @access public
*/
function isEmpty()
{
return $this->empty;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Hour.php
New file
0,0 → 1,113
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Hour.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Hour.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents an Hour and builds Minutes
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Hour.php';
* $Hour = & new Calendar_Hour(2003, 10, 21, 15); // Oct 21st 2003, 3pm
* $Hour->build(); // Build Calendar_Minute objects
* while ($Minute = & $Hour->fetch()) {
* echo $Minute->thisMinute().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Hour extends Calendar
{
/**
* Constructs Calendar_Hour
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int day e.g. 11
* @param int hour e.g. 13
* @access public
*/
function Calendar_Hour($y, $m, $d, $h)
{
Calendar::Calendar($y, $m, $d, $h);
}
 
/**
* Builds the Minutes in the Hour
* @param array (optional) Calendar_Minute objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates=array())
{
require_once CALENDAR_ROOT.'Minute.php';
$mIH = $this->cE->getMinutesInHour($this->year, $this->month, $this->day,
$this->hour);
for ($i=0; $i < $mIH; $i++) {
$this->children[$i]=
new Calendar_Minute($this->year, $this->month, $this->day,
$this->hour, $i);
}
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates)
{
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()
&& $this->month == $sDate->thisMonth()
&& $this->day == $sDate->thisDay()
&& $this->hour == $sDate->thisHour())
{
$key = (int)$sDate->thisMinute();
if (isset($this->children[$key])) {
$sDate->setSelected();
$this->children[$key] = $sDate;
}
}
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Engine/UnixTS.php
New file
0,0 → 1,372
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: UnixTS.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: UnixTS.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
/**
* Performs calendar calculations based on the PHP date() function and
* Unix timestamps (using PHP's mktime() function).
* @package Calendar
* @access protected
*/
class Calendar_Engine_UnixTS /* implements Calendar_Engine_Interface */
{
/**
* Makes sure a given timestamp is only ever parsed once
* <pre>
* array (
* [0] => year (e.g 2003),
* [1] => month (e.g 9),
* [2] => day (e.g 6),
* [3] => hour (e.g 14),
* [4] => minute (e.g 34),
* [5] => second (e.g 45),
* [6] => num days in month (e.g. 31),
* [7] => week in year (e.g. 50),
* [8] => day in week (e.g. 0 for Sunday)
* )
* </pre>
* Uses a static variable to prevent date() being used twice
* for a date which is already known
* @param int Unix timestamp
* @return array
* @access protected
*/
function stampCollection($stamp)
{
static $stamps = array();
if ( !isset($stamps[$stamp]) ) {
$date = @date('Y n j H i s t W w',$stamp);
$stamps[$stamp] = sscanf($date, "%d %d %d %d %d %d %d %d %d");
}
return $stamps[$stamp];
}
 
/**
* Returns a numeric year given a timestamp
* @param int Unix timestamp
* @return int year (e.g. 2003)
* @access protected
*/
function stampToYear($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[0];
}
 
/**
* Returns a numeric month given a timestamp
* @param int Unix timestamp
* @return int month (e.g. 9)
* @access protected
*/
function stampToMonth($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[1];
}
 
/**
* Returns a numeric day given a timestamp
* @param int Unix timestamp
* @return int day (e.g. 15)
* @access protected
*/
function stampToDay($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[2];
}
 
/**
* Returns a numeric hour given a timestamp
* @param int Unix timestamp
* @return int hour (e.g. 13)
* @access protected
*/
function stampToHour($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[3];
}
 
/**
* Returns a numeric minute given a timestamp
* @param int Unix timestamp
* @return int minute (e.g. 34)
* @access protected
*/
function stampToMinute($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[4];
}
 
/**
* Returns a numeric second given a timestamp
* @param int Unix timestamp
* @return int second (e.g. 51)
* @access protected
*/
function stampToSecond($stamp)
{
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return (int)$date[5];
}
 
/**
* Returns a timestamp
* @param int year (2003)
* @param int month (9)
* @param int day (13)
* @param int hour (13)
* @param int minute (34)
* @param int second (53)
* @return int Unix timestamp
* @access protected
*/
function dateToStamp($y, $m, $d, $h=0, $i=0, $s=0)
{
static $dates = array();
if ( !isset($dates[$y][$m][$d][$h][$i][$s]) ) {
$dates[$y][$m][$d][$h][$i][$s] = @mktime($h, $i, $s, $m, $d, $y);
}
return $dates[$y][$m][$d][$h][$i][$s];
}
 
/**
* The upper limit on years that the Calendar Engine can work with
* @return int (2037)
* @access protected
*/
function getMaxYears()
{
return 2037;
}
 
/**
* The lower limit on years that the Calendar Engine can work with
* @return int (1970 if it's Windows and 1902 for all other OSs)
* @access protected
*/
function getMinYears()
{
return $min = strpos(PHP_OS, 'WIN') === false ? 1902 : 1970;
}
 
/**
* Returns the number of months in a year
* @return int (12)
* @access protected
*/
function getMonthsInYear($y=null)
{
return 12;
}
 
/**
* Returns the number of days in a month, given year and month
* @param int year (2003)
* @param int month (9)
* @return int days in month
* @access protected
*/
function getDaysInMonth($y, $m)
{
$stamp = Calendar_Engine_UnixTS::dateToStamp($y,$m,1);
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return $date[6];
}
 
/**
* Returns numeric representation of the day of the week in a month,
* given year and month
* @param int year (2003)
* @param int month (9)
* @return int from 0 to 6
* @access protected
*/
function getFirstDayInMonth($y, $m)
{
$stamp = Calendar_Engine_UnixTS::dateToStamp($y,$m,1);
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return $date[8];
}
 
/**
* Returns the number of days in a week
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (7)
* @access protected
*/
function getDaysInWeek($y=NULL, $m=NULL, $d=NULL)
{
return 7;
}
 
/**
* Returns the number of the week in the year (ISO-8601), given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int week number
* @access protected
*/
function getWeekNInYear($y, $m, $d)
{
$stamp = Calendar_Engine_UnixTS::dateToStamp($y,$m,$d);
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return $date[7];
}
 
/**
* Returns the number of the week in the month, given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @param int first day of the week (default: monday)
* @return int week number
* @access protected
*/
function getWeekNInMonth($y, $m, $d, $firstDay=1)
{
$weekEnd = ($firstDay == 0) ? $this->getDaysInWeek()-1 : $firstDay-1;
$end_of_week = 1;
while (@date('w', @mktime(0, 0, 0, $m, $end_of_week, $y)) != $weekEnd) {
++$end_of_week; //find first weekend of the month
}
$w = 1;
while ($d > $end_of_week) {
++$w;
$end_of_week += $this->getDaysInWeek();
}
return $w;
}
 
/**
* Returns the number of weeks in the month
* @param int year (2003)
* @param int month (9)
* @param int first day of the week (default: monday)
* @return int weeks number
* @access protected
*/
function getWeeksInMonth($y, $m, $firstDay=1)
{
$FDOM = $this->getFirstDayInMonth($y, $m);
 
if ($FDOM > $firstDay) {
$firstWeekDays = $this->getDaysInWeek() - $FDOM + $firstDay;
$weeks = 1;
} else {
$firstWeekDays = $firstDay - $FDOM;
$weeks = 0;
}
$firstWeekDays %= $this->getDaysInWeek();
 
$result = (int)(ceil(($this->getDaysInMonth($y, $m) - $firstWeekDays) /
$this->getDaysInWeek()) + $weeks);
 
// Hack - 0 as FDOM is a special case
if ( $FDOM != 0 ) {
return $result;
} else {
return $result + 1;
}
}
 
/**
* Returns the number of the day of the week (0=sunday, 1=monday...)
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int weekday number
* @access protected
*/
function getDayOfWeek($y, $m, $d)
{
$stamp = Calendar_Engine_UnixTS::dateToStamp($y,$m,$d);
$date = Calendar_Engine_UnixTS::stampCollection($stamp);
return $date[8];
}
 
/**
* Returns a list of integer days of the week beginning 0
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return array (0,1,2,3,4,5,6) 1 = Monday
* @access protected
*/
function getWeekDays($y=NULL, $m=NULL, $d=NULL)
{
return array(0, 1, 2, 3, 4, 5, 6);
}
 
/**
* Returns the default first day of the week
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (default 1 = Monday)
* @access protected
*/
function getFirstDayOfWeek($y=NULL, $m=NULL, $d=NULL)
{
return 1;
}
 
/**
* Returns the number of hours in a day
* @return int (24)
* @access protected
*/
function getHoursInDay($y=null,$m=null,$d=null)
{
return 24;
}
 
/**
* Returns the number of minutes in an hour
* @return int (60)
* @access protected
*/
function getMinutesInHour($y=null,$m=null,$d=null,$h=null)
{
return 60;
}
 
/**
* Returns the number of seconds in a minutes
* @return int (60)
* @access protected
*/
function getSecondsInMinute($y=null,$m=null,$d=null,$h=null,$i=null)
{
return 60;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Engine/Interface.php
New file
0,0 → 1,293
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Interface.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Interface.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
/**
* The methods the classes implementing the Calendar_Engine must implement.
* Note this class is not used but simply to help development
* @package Calendar
* @access protected
*/
class Calendar_Engine_Interface
{
/**
* Provides a mechansim to make sure parsing of timestamps
* into human dates is only performed once per timestamp.
* Typically called "internally" by methods like stampToYear.
* Return value can vary, depending on the specific implementation
* @param int timestamp (depending on implementation)
* @return mixed
* @access protected
*/
function stampCollection($stamp)
{
}
 
/**
* Returns a numeric year given a timestamp
* @param int timestamp (depending on implementation)
* @return int year (e.g. 2003)
* @access protected
*/
function stampToYear($stamp)
{
}
 
/**
* Returns a numeric month given a timestamp
* @param int timestamp (depending on implementation)
* @return int month (e.g. 9)
* @access protected
*/
function stampToMonth($stamp)
{
}
 
/**
* Returns a numeric day given a timestamp
* @param int timestamp (depending on implementation)
* @return int day (e.g. 15)
* @access protected
*/
function stampToDay($stamp)
{
}
 
/**
* Returns a numeric hour given a timestamp
* @param int timestamp (depending on implementation)
* @return int hour (e.g. 13)
* @access protected
*/
function stampToHour($stamp)
{
}
 
/**
* Returns a numeric minute given a timestamp
* @param int timestamp (depending on implementation)
* @return int minute (e.g. 34)
* @access protected
*/
function stampToMinute($stamp)
{
}
 
/**
* Returns a numeric second given a timestamp
* @param int timestamp (depending on implementation)
* @return int second (e.g. 51)
* @access protected
*/
function stampToSecond($stamp)
{
}
 
/**
* Returns a timestamp. Can be worth "caching" generated
* timestamps in a static variable, identified by the
* params this method accepts, to timestamp will only
* be calculated once.
* @param int year (e.g. 2003)
* @param int month (e.g. 9)
* @param int day (e.g. 13)
* @param int hour (e.g. 13)
* @param int minute (e.g. 34)
* @param int second (e.g. 53)
* @return int (depends on implementation)
* @access protected
*/
function dateToStamp($y,$m,$d,$h,$i,$s)
{
}
 
/**
* The upper limit on years that the Calendar Engine can work with
* @return int (e.g. 2037)
* @access protected
*/
function getMaxYears()
{
}
 
/**
* The lower limit on years that the Calendar Engine can work with
* @return int (e.g 1902)
* @access protected
*/
function getMinYears()
{
}
 
/**
* Returns the number of months in a year
* @param int (optional) year to get months for
* @return int (e.g. 12)
* @access protected
*/
function getMonthsInYear($y=null)
{
}
 
/**
* Returns the number of days in a month, given year and month
* @param int year (e.g. 2003)
* @param int month (e.g. 9)
* @return int days in month
* @access protected
*/
function getDaysInMonth($y, $m)
{
}
 
/**
* Returns numeric representation of the day of the week in a month,
* given year and month
* @param int year (e.g. 2003)
* @param int month (e.g. 9)
* @return int
* @access protected
*/
function getFirstDayInMonth ($y, $m)
{
}
 
/**
* Returns the number of days in a week
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (e.g. 7)
* @access protected
*/
function getDaysInWeek($y=NULL, $m=NULL, $d=NULL)
{
}
 
/**
* Returns the number of the week in the year (ISO-8601), given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int week number
* @access protected
*/
function getWeekNInYear($y, $m, $d)
{
}
 
/**
* Returns the number of the week in the month, given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @param int first day of the week (default: 1 - monday)
* @return int week number
* @access protected
*/
function getWeekNInMonth($y, $m, $d, $firstDay=1)
{
}
 
/**
* Returns the number of weeks in the month
* @param int year (2003)
* @param int month (9)
* @param int first day of the week (default: 1 - monday)
* @return int weeks number
* @access protected
*/
function getWeeksInMonth($y, $m)
{
}
 
/**
* Returns the number of the day of the week (0=sunday, 1=monday...)
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int weekday number
* @access protected
*/
function getDayOfWeek($y, $m, $d)
{
}
 
/**
* Returns the numeric values of the days of the week.
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return array list of numeric values of days in week, beginning 0
* @access protected
*/
function getWeekDays($y=NULL, $m=NULL, $d=NULL)
{
}
 
/**
* Returns the default first day of the week as an integer. Must be a
* member of the array returned from getWeekDays
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (e.g. 1 for Monday)
* @see getWeekDays
* @access protected
*/
function getFirstDayOfWeek($y=NULL, $m=NULL, $d=NULL)
{
}
 
/**
* Returns the number of hours in a day<br>
* @param int (optional) day to get hours for
* @return int (e.g. 24)
* @access protected
*/
function getHoursInDay($y=null,$m=null,$d=null)
{
}
 
/**
* Returns the number of minutes in an hour
* @param int (optional) hour to get minutes for
* @return int
* @access protected
*/
function getMinutesInHour($y=null,$m=null,$d=null,$h=null)
{
}
 
/**
* Returns the number of seconds in a minutes
* @param int (optional) minute to get seconds for
* @return int
* @access protected
*/
function getSecondsInMinute($y=null,$m=null,$d=null,$h=null,$i=null)
{
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Engine/PearDate.php
New file
0,0 → 1,413
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: PearDate.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: PearDate.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
/**
* Load PEAR::Date class
*/
require_once 'Date.php';
 
/**
* Performs calendar calculations based on the PEAR::Date class
* Timestamps are in the ISO-8601 format (YYYY-MM-DD HH:MM:SS)
* @package Calendar
* @access protected
*/
class Calendar_Engine_PearDate /* implements Calendar_Engine_Interface */
{
/**
* Makes sure a given timestamp is only ever parsed once
* Uses a static variable to prevent date() being used twice
* for a date which is already known
* @param mixed Any timestamp format recognized by Pear::Date
* @return object Pear::Date object
* @access protected
*/
function stampCollection($stamp)
{
static $stamps = array();
if (!isset($stamps[$stamp])) {
$stamps[$stamp] = new Date($stamp);
}
return $stamps[$stamp];
}
 
/**
* Returns a numeric year given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int year (e.g. 2003)
* @access protected
*/
function stampToYear($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->year;
}
 
/**
* Returns a numeric month given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int month (e.g. 9)
* @access protected
*/
function stampToMonth($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->month;
}
 
/**
* Returns a numeric day given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int day (e.g. 15)
* @access protected
*/
function stampToDay($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->day;
}
 
/**
* Returns a numeric hour given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int hour (e.g. 13)
* @access protected
*/
function stampToHour($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->hour;
}
 
/**
* Returns a numeric minute given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int minute (e.g. 34)
* @access protected
*/
function stampToMinute($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->minute;
}
 
/**
* Returns a numeric second given a iso-8601 datetime
* @param string iso-8601 datetime (YYYY-MM-DD HH:MM:SS)
* @return int second (e.g. 51)
* @access protected
*/
function stampToSecond($stamp)
{
$date = Calendar_Engine_PearDate::stampCollection($stamp);
return (int)$date->second;
}
 
/**
* Returns a iso-8601 datetime
* @param int year (2003)
* @param int month (9)
* @param int day (13)
* @param int hour (13)
* @param int minute (34)
* @param int second (53)
* @return string iso-8601 datetime
* @access protected
*/
function dateToStamp($y, $m, $d, $h=0, $i=0, $s=0)
{
$r = array();
Calendar_Engine_PearDate::adjustDate($y, $m, $d, $h, $i, $s);
$key = $y.$m.$d.$h.$i.$s;
if (!isset($r[$key])) {
$r[$key] = sprintf("%04d-%02d-%02d %02d:%02d:%02d",
$y, $m, $d, $h, $i, $s);
}
return $r[$key];
}
 
/**
* Set the correct date values (useful for math operations on dates)
* @param int year (2003)
* @param int month (9)
* @param int day (13)
* @param int hour (13)
* @param int minute (34)
* @param int second (53)
* @access protected
*/
function adjustDate(&$y, &$m, &$d, &$h, &$i, &$s)
{
if ($s < 0) {
$m -= floor($s / 60);
$s = -$s % 60;
}
if ($s > 60) {
$m += floor($s / 60);
$s %= 60;
}
if ($i < 0) {
$h -= floor($i / 60);
$i = -$i % 60;
}
if ($i > 60) {
$h += floor($i / 60);
$i %= 60;
}
if ($h < 0) {
$d -= floor($h / 24);
$h = -$h % 24;
}
if ($h > 24) {
$d += floor($h / 24);
$h %= 24;
}
for(; $m < 1; $y--, $m+=12);
for(; $m > 12; $y++, $m-=12);
 
while ($d < 1) {
if ($m > 1) {
$m--;
} else {
$m = 12;
$y--;
}
$d += Date_Calc::daysInMonth($m, $y);
}
for ($max_days = Date_Calc::daysInMonth($m, $y); $d > $max_days; ) {
$d -= $max_days;
if ($m < 12) {
$m++;
} else {
$m = 1;
$y++;
}
}
}
 
/**
* The upper limit on years that the Calendar Engine can work with
* @return int 9999
* @access protected
*/
function getMaxYears()
{
return 9999;
}
 
/**
* The lower limit on years that the Calendar Engine can work with
* @return int 0
* @access protected
*/
function getMinYears()
{
return 0;
}
 
/**
* Returns the number of months in a year
* @return int (12)
* @access protected
*/
function getMonthsInYear($y=null)
{
return 12;
}
 
/**
* Returns the number of days in a month, given year and month
* @param int year (2003)
* @param int month (9)
* @return int days in month
* @access protected
*/
function getDaysInMonth($y, $m)
{
return (int)Date_Calc::daysInMonth($m, $y);
}
 
/**
* Returns numeric representation of the day of the week in a month,
* given year and month
* @param int year (2003)
* @param int month (9)
* @return int from 0 to 7
* @access protected
*/
function getFirstDayInMonth($y, $m)
{
return (int)Date_Calc::dayOfWeek(1, $m, $y);
}
 
/**
* Returns the number of days in a week
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (7)
* @access protected
*/
function getDaysInWeek($y=NULL, $m=NULL, $d=NULL)
{
return 7;
}
 
/**
* Returns the number of the week in the year (ISO-8601), given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int week number
* @access protected
*/
function getWeekNInYear($y, $m, $d)
{
return Date_Calc::weekOfYear($d, $m, $y); //beware, Date_Calc doesn't follow ISO-8601 standard!
}
 
/**
* Returns the number of the week in the month, given a date
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @param int first day of the week (default: monday)
* @return int week number
* @access protected
*/
function getWeekNInMonth($y, $m, $d, $firstDay=1)
{
$weekEnd = ($firstDay == 0) ? $this->getDaysInWeek()-1 : $firstDay-1;
$end_of_week = (int)Date_Calc::nextDayOfWeek($weekEnd, 1, $m, $y, '%e', true);
$w = 1;
while ($d > $end_of_week) {
++$w;
$end_of_week += $this->getDaysInWeek();
}
return $w;
}
 
/**
* Returns the number of weeks in the month
* @param int year (2003)
* @param int month (9)
* @param int first day of the week (default: monday)
* @return int weeks number
* @access protected
*/
function getWeeksInMonth($y, $m, $firstDay=1)
{
$FDOM = Date_Calc::firstOfMonthWeekday($m, $y);
 
if ($FDOM > $firstDay) {
$firstWeekDays = $this->getDaysInWeek() - $FDOM + $firstDay;
$weeks = 1;
} else {
$firstWeekDays = $firstDay - $FDOM;
$weeks = 0;
}
$firstWeekDays %= $this->getDaysInWeek();
$result = (int)(ceil(($this->getDaysInMonth($y, $m) - $firstWeekDays) /
$this->getDaysInWeek()) + $weeks);
 
if ( $FDOM != 0 ) {
return $result;
} else {
return $result + 1;
}
}
 
/**
* Returns the number of the day of the week (0=sunday, 1=monday...)
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int weekday number
* @access protected
*/
function getDayOfWeek($y, $m, $d)
{
return Date_Calc::dayOfWeek($d, $m, $y);
}
 
/**
* Returns a list of integer days of the week beginning 0
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return array (0, 1, 2, 3, 4, 5, 6) 1 = Monday
* @access protected
*/
function getWeekDays($y=NULL, $m=NULL, $d=NULL)
{
return array(0, 1, 2, 3, 4, 5, 6);
}
 
/**
* Returns the default first day of the week
* @param int year (2003)
* @param int month (9)
* @param int day (4)
* @return int (default 1 = Monday)
* @access protected
*/
function getFirstDayOfWeek($y=NULL, $m=NULL, $d=NULL)
{
return 1;
}
 
/**
* Returns the number of hours in a day
* @return int (24)
* @access protected
*/
function getHoursInDay($y=null,$m=null,$d=null)
{
return 24;
}
 
/**
* Returns the number of minutes in an hour
* @return int (60)
* @access protected
*/
function getMinutesInHour($y=null,$m=null,$d=null,$h=null)
{
return 60;
}
 
/**
* Returns the number of seconds in a minutes
* @return int (60)
* @access protected
*/
function getSecondsInMinute($y=null,$m=null,$d=null,$h=null,$i=null)
{
return 60;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Decorator.php
New file
0,0 → 1,557
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Decorator.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Decorator.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
/**
* Decorates any calendar class.
* Create a subclass of this class for your own "decoration".
* Used for "selections"
* <code>
* class DayDecorator extends Calendar_Decorator
* {
* function thisDay($format = 'int')
* {
.* $day = parent::thisDay('timestamp');
.* return date('D', $day);
* }
* }
* $Day = & new Calendar_Day(2003, 10, 25);
* $DayDecorator = & new DayDecorator($Day);
* echo $DayDecorator->thisDay(); // Outputs "Sat"
* </code>
* @abstract
* @package Calendar
*/
class Calendar_Decorator
{
/**
* Subclass of Calendar being decorated
* @var object
* @access private
*/
var $calendar;
 
/**
* Constructs the Calendar_Decorator
* @param object subclass to Calendar to decorate
*/
function Calendar_Decorator(& $calendar)
{
$this->calendar = & $calendar;
}
 
/**
* Defines the calendar by a Unix timestamp, replacing values
* passed to the constructor
* @param int Unix timestamp
* @return void
* @access public
*/
function setTimestamp($ts)
{
$this->calendar->setTimestamp($ts);
}
 
/**
* Returns a timestamp from the current date / time values. Format of
* timestamp depends on Calendar_Engine implementation being used
* @return int timestamp
* @access public
*/
function getTimestamp()
{
return $this->calendar->getTimeStamp();
}
 
/**
* Defines calendar object as selected (e.g. for today)
* @param boolean state whether Calendar subclass
* @return void
* @access public
*/
function setSelected($state = true)
{
$this->calendar->setSelected($state = true);
}
 
/**
* True if the calendar subclass object is selected (e.g. today)
* @return boolean
* @access public
*/
function isSelected()
{
return $this->calendar->isSelected();
}
 
/**
* Adjusts the date (helper method)
* @return void
* @access public
*/
function adjust()
{
$this->calendar->adjust();
}
 
/**
* Returns the date as an associative array (helper method)
* @param mixed timestamp (leave empty for current timestamp)
* @return array
* @access public
*/
function toArray($stamp=null)
{
return $this->calendar->toArray($stamp);
}
 
/**
* Returns the value as an associative array (helper method)
* @param string type of date object that return value represents
* @param string $format ['int' | 'array' | 'timestamp' | 'object']
* @param mixed timestamp (depending on Calendar engine being used)
* @param int integer default value (i.e. give me the answer quick)
* @return mixed
* @access private
*/
function returnValue($returnType, $format, $stamp, $default)
{
return $this->calendar->returnValue($returnType, $format, $stamp, $default);
}
 
/**
* Defines Day object as first in a week
* Only used by Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setFirst ($state = true)
{
if ( method_exists($this->calendar,'setFirst') ) {
$this->calendar->setFirst($state);
}
}
 
/**
* Defines Day object as last in a week
* Used only following Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setLast($state = true)
{
if ( method_exists($this->calendar,'setLast') ) {
$this->calendar->setLast($state);
}
}
 
/**
* Returns true if Day object is first in a Week
* Only relevant when Day is created by Calendar_Month_Weekdays::build()
* @return boolean
* @access public
*/
function isFirst() {
if ( method_exists($this->calendar,'isFirst') ) {
return $this->calendar->isFirst();
}
}
 
/**
* Returns true if Day object is last in a Week
* Only relevant when Day is created by Calendar_Month_Weekdays::build()
* @return boolean
* @access public
*/
function isLast()
{
if ( method_exists($this->calendar,'isLast') ) {
return $this->calendar->isLast();
}
}
 
/**
* Defines Day object as empty
* Only used by Calendar_Month_Weekdays::build()
* @param boolean state
* @return void
* @access private
*/
function setEmpty ($state = true)
{
if ( method_exists($this->calendar,'setEmpty') ) {
$this->calendar->setEmpty($state);
}
}
 
/**
* @return boolean
* @access public
*/
function isEmpty()
{
if ( method_exists($this->calendar,'isEmpty') ) {
return $this->calendar->isEmpty();
}
}
 
/**
* Build the children
* @param array containing Calendar objects to select (optional)
* @return boolean
* @access public
* @abstract
*/
function build($sDates = array())
{
$this->calendar->build($sDates);
}
 
/**
* Iterator method for fetching child Calendar subclass objects
* (e.g. a minute from an hour object). On reaching the end of
* the collection, returns false and resets the collection for
* further iteratations.
* @return mixed either an object subclass of Calendar or false
* @access public
*/
function fetch()
{
return $this->calendar->fetch();
}
 
/**
* Fetches all child from the current collection of children
* @return array
* @access public
*/
function fetchAll()
{
return $this->calendar->fetchAll();
}
 
/**
* Get the number Calendar subclass objects stored in the internal
* collection.
* @return int
* @access public
*/
function size()
{
return $this->calendar->size();
}
 
/**
* Determine whether this date is valid, with the bounds determined by
* the Calendar_Engine. The call is passed on to
* Calendar_Validator::isValid
* @return boolean
* @access public
*/
function isValid()
{
return $this->calendar->isValid();
}
 
/**
* Returns an instance of Calendar_Validator
* @return Calendar_Validator
* @access public
*/
function & getValidator()
{
return $this->calendar->getValidator();
}
 
/**
* Returns a reference to the current Calendar_Engine being used. Useful
* for Calendar_Table_Helper and Caledar_Validator
* @return object implementing Calendar_Engine_Inteface
* @access private
*/
function & getEngine()
{
return $this->calendar->getEngine();
}
 
/**
* Returns the value for the previous year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2002 or timestamp
* @access public
*/
function prevYear($format = 'int')
{
return $this->calendar->prevYear($format);
}
 
/**
* Returns the value for this year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2003 or timestamp
* @access public
*/
function thisYear($format = 'int')
{
return $this->calendar->thisYear($format);
}
 
/**
* Returns the value for next year
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 2004 or timestamp
* @access public
*/
function nextYear($format = 'int')
{
return $this->calendar->nextYear($format);
}
 
/**
* Returns the value for the previous month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 4 or Unix timestamp
* @access public
*/
function prevMonth($format = 'int')
{
return $this->calendar->prevMonth($format);
}
 
/**
* Returns the value for this month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 5 or timestamp
* @access public
*/
function thisMonth($format = 'int')
{
return $this->calendar->thisMonth($format);
}
 
/**
* Returns the value for next month
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 6 or timestamp
* @access public
*/
function nextMonth($format = 'int')
{
return $this->calendar->nextMonth($format);
}
 
/**
* Returns the value for the previous week
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 4 or Unix timestamp
* @access public
*/
function prevWeek($format = 'n_in_month')
{
if ( method_exists($this->calendar,'prevWeek') ) {
return $this->calendar->prevWeek($format);
} else {
require_once 'PEAR.php';
PEAR::raiseError(
'Cannot call prevWeek on Calendar object of type: '.
get_class($this->calendar), 133, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar_Decorator::prevWeek()');
return false;
}
}
 
/**
* Returns the value for this week
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 5 or timestamp
* @access public
*/
function thisWeek($format = 'n_in_month')
{
if ( method_exists($this->calendar,'thisWeek') ) {
return $this->calendar->thisWeek($format);
} else {
require_once 'PEAR.php';
PEAR::raiseError(
'Cannot call thisWeek on Calendar object of type: '.
get_class($this->calendar), 133, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar_Decorator::thisWeek()');
return false;
}
}
 
/**
* Returns the value for next week
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 6 or timestamp
* @access public
*/
function nextWeek($format = 'n_in_month')
{
if ( method_exists($this->calendar,'nextWeek') ) {
return $this->calendar->nextWeek($format);
} else {
require_once 'PEAR.php';
PEAR::raiseError(
'Cannot call thisWeek on Calendar object of type: '.
get_class($this->calendar), 133, PEAR_ERROR_TRIGGER,
E_USER_NOTICE, 'Calendar_Decorator::nextWeek()');
return false;
}
}
 
/**
* Returns the value for the previous day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 10 or timestamp
* @access public
*/
function prevDay($format = 'int') {
return $this->calendar->prevDay($format);
}
 
/**
* Returns the value for this day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 11 or timestamp
* @access public
*/
function thisDay($format = 'int')
{
return $this->calendar->thisDay($format);
}
 
/**
* Returns the value for the next day
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 12 or timestamp
* @access public
*/
function nextDay($format = 'int')
{
return $this->calendar->nextDay($format);
}
 
/**
* Returns the value for the previous hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 13 or timestamp
* @access public
*/
function prevHour($format = 'int')
{
return $this->calendar->prevHour($format);
}
 
/**
* Returns the value for this hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 14 or timestamp
* @access public
*/
function thisHour($format = 'int')
{
return $this->calendar->thisHour($format);
}
 
/**
* Returns the value for the next hour
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 14 or timestamp
* @access public
*/
function nextHour($format = 'int')
{
return $this->calendar->nextHour($format);
}
 
/**
* Returns the value for the previous minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 23 or timestamp
* @access public
*/
function prevMinute($format = 'int')
{
return $this->calendar->prevMinute($format);
}
 
/**
* Returns the value for this minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 24 or timestamp
* @access public
*/
function thisMinute($format = 'int')
{
return $this->calendar->thisMinute($format);
}
 
/**
* Returns the value for the next minute
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 25 or timestamp
* @access public
*/
function nextMinute($format = 'int')
{
return $this->calendar->nextMinute($format);
}
 
/**
* Returns the value for the previous second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 43 or timestamp
* @access public
*/
function prevSecond($format = 'int')
{
return $this->calendar->prevSecond($format);
}
 
/**
* Returns the value for this second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 44 or timestamp
* @access public
*/
function thisSecond($format = 'int')
{
return $this->calendar->thisSecond($format);
}
 
/**
* Returns the value for the next second
* @param string return value format ['int' | 'timestamp' | 'object' | 'array']
* @return int e.g. 45 or timestamp
* @access public
*/
function nextSecond($format = 'int')
{
return $this->calendar->nextSecond($format);
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Month.php
New file
0,0 → 1,113
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Month.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Month.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar base class
*/
require_once CALENDAR_ROOT.'Calendar.php';
 
/**
* Represents a Month and builds Days
* <code>
* require_once 'Calendar'.DIRECTORY_SEPARATOR.'Month.php';
* $Month = & new Calendar_Month(2003, 10); // Oct 2003
* $Month->build(); // Build Calendar_Day objects
* while ($Day = & $Month->fetch()) {
* echo $Day->thisDay().'<br />';
* }
* </code>
* @package Calendar
* @access public
*/
class Calendar_Month extends Calendar
{
/**
* Constructs Calendar_Month
* @param int year e.g. 2003
* @param int month e.g. 5
* @param int (optional) unused in this class
* @access public
*/
function Calendar_Month($y, $m, $firstDay=null)
{
Calendar::Calendar($y, $m);
}
 
/**
* Builds Day objects for this Month. Creates as many Calendar_Day objects
* as there are days in the month
* @param array (optional) Calendar_Day objects representing selected dates
* @return boolean
* @access public
*/
function build($sDates=array())
{
require_once CALENDAR_ROOT.'Day.php';
$daysInMonth = $this->cE->getDaysInMonth($this->year, $this->month);
for ($i=1; $i<=$daysInMonth; $i++) {
$this->children[$i] = new Calendar_Day($this->year, $this->month, $i);
}
if (count($sDates) > 0) {
$this->setSelection($sDates);
}
return true;
}
 
/**
* Called from build()
* @param array
* @return void
* @access private
*/
function setSelection($sDates)
{
foreach ($sDates as $sDate) {
if ($this->year == $sDate->thisYear()
&& $this->month == $sDate->thisMonth() )
{
$key = $sDate->thisDay();
if (isset($this->children[$key])) {
$sDate->setSelected();
$class = strtolower(get_class($sDate));
if ( $class == 'calendar_day' || $class == 'calendar_decorator' ) {
$sDate->setFirst($this->children[$key]->isFirst());
$sDate->setLast($this->children[$key]->isLast());
}
$this->children[$key] = $sDate;
}
}
}
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Validator.php
New file
0,0 → 1,335
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// +----------------------------------------------------------------------+
//
// $Id: Validator.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Validator.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Validation Error Messages
*/
if (!defined('CALENDAR_VALUE_TOOSMALL')) {
define('CALENDAR_VALUE_TOOSMALL', 'Too small: min = ');
}
if (!defined('CALENDAR_VALUE_TOOLARGE')) {
define('CALENDAR_VALUE_TOOLARGE', 'Too large: max = ');
}
 
/**
* Used to validate any given Calendar date object. Instances of this class
* can be obtained from any data object using the getValidator method
* @see Calendar::getValidator()
* @package Calendar
* @access public
*/
class Calendar_Validator
{
/**
* Instance of the Calendar date object to validate
* @var object
* @access private
*/
var $calendar;
 
/**
* Instance of the Calendar_Engine
* @var object
* @access private
*/
var $cE;
 
/**
* Array of errors for validation failures
* @var array
* @access private
*/
var $errors = array();
 
/**
* Constructs Calendar_Validator
* @param object subclass of Calendar
* @access public
*/
function Calendar_Validator(& $calendar)
{
$this->calendar = & $calendar;
$this->cE = & $calendar->getEngine();
}
 
/**
* Calls all the other isValidXXX() methods in the validator
* @return boolean
* @access public
*/
function isValid()
{
$checks = array('isValidYear', 'isValidMonth', 'isValidDay',
'isValidHour', 'isValidMinute', 'isValidSecond');
$valid = true;
foreach ($checks as $check) {
if (!$this->{$check}()) {
$valid = false;
}
}
return $valid;
}
 
/**
* Check whether this is a valid year
* @return boolean
* @access public
*/
function isValidYear()
{
$y = $this->calendar->thisYear();
$min = $this->cE->getMinYears();
if ($min > $y) {
$this->errors[] = new Calendar_Validation_Error(
'Year', $y, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = $this->cE->getMaxYears();
if ($y > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Year', $y, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Check whether this is a valid month
* @return boolean
* @access public
*/
function isValidMonth()
{
$m = $this->calendar->thisMonth();
$min = 1;
if ($min > $m) {
$this->errors[] = new Calendar_Validation_Error(
'Month', $m, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = $this->cE->getMonthsInYear($this->calendar->thisYear());
if ($m > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Month', $m, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Check whether this is a valid day
* @return boolean
* @access public
*/
function isValidDay()
{
$d = $this->calendar->thisDay();
$min = 1;
if ($min > $d) {
$this->errors[] = new Calendar_Validation_Error(
'Day', $d, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = $this->cE->getDaysInMonth(
$this->calendar->thisYear(), $this->calendar->thisMonth());
if ($d > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Day', $d, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Check whether this is a valid hour
* @return boolean
* @access public
*/
function isValidHour()
{
$h = $this->calendar->thisHour();
$min = 0;
if ($min > $h) {
$this->errors[] = new Calendar_Validation_Error(
'Hour', $h, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = ($this->cE->getHoursInDay($this->calendar->thisDay())-1);
if ($h > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Hour', $h, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Check whether this is a valid minute
* @return boolean
* @access public
*/
function isValidMinute()
{
$i = $this->calendar->thisMinute();
$min = 0;
if ($min > $i) {
$this->errors[] = new Calendar_Validation_Error(
'Minute', $i, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = ($this->cE->getMinutesInHour($this->calendar->thisHour())-1);
if ($i > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Minute', $i, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Check whether this is a valid second
* @return boolean
* @access public
*/
function isValidSecond()
{
$s = $this->calendar->thisSecond();
$min = 0;
if ($min > $s) {
$this->errors[] = new Calendar_Validation_Error(
'Second', $s, CALENDAR_VALUE_TOOSMALL.$min);
return false;
}
$max = ($this->cE->getSecondsInMinute($this->calendar->thisMinute())-1);
if ($s > $max) {
$this->errors[] = new Calendar_Validation_Error(
'Second', $s, CALENDAR_VALUE_TOOLARGE.$max);
return false;
}
return true;
}
 
/**
* Iterates over any validation errors
* @return mixed either Calendar_Validation_Error or false
* @access public
*/
function fetch()
{
$error = each ($this->errors);
if ($error) {
return $error['value'];
} else {
reset($this->errors);
return false;
}
}
}
 
/**
* For Validation Error messages
* @see Calendar::fetch()
* @package Calendar
* @access public
*/
class Calendar_Validation_Error
{
/**
* Date unit (e.g. month,hour,second) which failed test
* @var string
* @access private
*/
var $unit;
 
/**
* Value of unit which failed test
* @var int
* @access private
*/
var $value;
 
/**
* Validation error message
* @var string
* @access private
*/
var $message;
 
/**
* Constructs Calendar_Validation_Error
* @param string Date unit (e.g. month,hour,second)
* @param int Value of unit which failed test
* @param string Validation error message
* @access protected
*/
function Calendar_Validation_Error($unit,$value,$message)
{
$this->unit = $unit;
$this->value = $value;
$this->message = $message;
}
 
/**
* Returns the Date unit
* @return string
* @access public
*/
function getUnit()
{
return $this->unit;
}
 
/**
* Returns the value of the unit
* @return int
* @access public
*/
function getValue()
{
return $this->value;
}
 
/**
* Returns the validation error message
* @return string
* @access public
*/
function getMessage()
{
return $this->message;
}
 
/**
* Returns a string containing the unit, value and error message
* @return string
* @access public
*/
function toString ()
{
return $this->unit.' = '.$this->value.' ['.$this->message.']';
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Util/Uri.php
New file
0,0 → 1,169
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Uri.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Uri.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Utility to help building HTML links for navigating the calendar<br />
* <code>
* $Day = new Calendar_Day(2003, 10, 23);
* $Uri = & new Calendar_Util_Uri('year', 'month', 'day');
* echo $Uri->prev($Day,'month'); // Displays year=2003&amp;month=10
* echo $Uri->prev($Day,'day'); // Displays year=2003&amp;month=10&amp;day=22
* $Uri->seperator = '/';
* $Uri->scalar = true;
* echo $Uri->prev($Day,'month'); // Displays 2003/10
* echo $Uri->prev($Day,'day'); // Displays 2003/10/22
* </code>
* @package Calendar
* @access public
*/
class Calendar_Util_Uri
{
/**
* Uri fragments for year, month, day etc.
* @var array
* @access private
*/
var $uris = array();
 
/**
* String to separate fragments with.
* Set to just & for HTML.
* For a scalar URL you might use / as the seperator
* @var string (default XHTML &amp;)
* @access public
*/
var $separator = '&amp;';
 
/**
* To output a "scalar" string - variable names omitted.
* Used for urls like index.php/2004/8/12
* @var boolean (default false)
* @access public
*/
var $scalar = false;
 
/**
* Constructs Calendar_Decorator_Uri
* The term "fragment" means <i>name</i> of a calendar GET variables in the URL
* @param string URI fragment for year
* @param string (optional) URI fragment for month
* @param string (optional) URI fragment for day
* @param string (optional) URI fragment for hour
* @param string (optional) URI fragment for minute
* @param string (optional) URI fragment for second
* @access public
*/
function Calendar_Util_Uri($y, $m=null, $d=null, $h=null, $i=null, $s=null)
{
$this->setFragments($y, $m, $d, $h, $i, $s);
}
 
/**
* Sets the URI fragment names
* @param string URI fragment for year
* @param string (optional) URI fragment for month
* @param string (optional) URI fragment for day
* @param string (optional) URI fragment for hour
* @param string (optional) URI fragment for minute
* @param string (optional) URI fragment for second
* @return void
* @access public
*/
function setFragments($y, $m=null, $d=null, $h=null, $i=null, $s=null) {
if (!is_null($y)) $this->uris['Year'] = $y;
if (!is_null($m)) $this->uris['Month'] = $m;
if (!is_null($d)) $this->uris['Day'] = $d;
if (!is_null($h)) $this->uris['Hour'] = $h;
if (!is_null($i)) $this->uris['Minute'] = $i;
if (!is_null($s)) $this->uris['Second'] = $s;
}
 
/**
* Gets the URI string for the previous calendar unit
* @param object subclassed from Calendar e.g. Calendar_Month
* @param string calendar unit ( must be year, month, week, day, hour, minute or second)
* @return string
* @access public
*/
function prev($Calendar, $unit)
{
$method = 'prev'.$unit;
$stamp = $Calendar->{$method}('timestamp');
return $this->buildUriString($Calendar, $method, $stamp);
}
 
/**
* Gets the URI string for the current calendar unit
* @param object subclassed from Calendar e.g. Calendar_Month
* @param string calendar unit ( must be year, month, week, day, hour, minute or second)
* @return string
* @access public
*/
function this($Calendar, $unit)
{
$method = 'this'.$unit;
$stamp = $Calendar->{$method}('timestamp');
return $this->buildUriString($Calendar, $method, $stamp);
}
 
/**
* Gets the URI string for the next calendar unit
* @param object subclassed from Calendar e.g. Calendar_Month
* @param string calendar unit ( must be year, month, week, day, hour, minute or second)
* @return string
* @access public
*/
function next($Calendar, $unit)
{
$method = 'next'.$unit;
$stamp = $Calendar->{$method}('timestamp');
return $this->buildUriString($Calendar, $method, $stamp);
}
 
/**
* Build the URI string
* @param string method substring
* @param int timestamp
* @return string build uri string
* @access private
*/
function buildUriString($Calendar, $method, $stamp)
{
$uriString = '';
$cE = & $Calendar->getEngine();
$separator = '';
foreach ($this->uris as $unit => $uri) {
$call = 'stampTo'.$unit;
$uriString .= $separator;
if (!$this->scalar) $uriString .= $uri.'=';
$uriString .= $cE->{$call}($stamp);
$separator = $this->separator;
}
return $uriString;
}
}
?>
/branches/v1.0-menes/api/pear/Calendar/Util/Textual.php
New file
0,0 → 1,239
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/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: Harry Fuecks <hfuecks@phppatterns.com> |
// | Lorenzo Alberton <l dot alberton at quipo dot it> |
// +----------------------------------------------------------------------+
//
// $Id: Textual.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
//
/**
* @package Calendar
* @version $Id: Textual.php,v 1.1 2005-09-30 14:58:00 ddelon Exp $
*/
 
/**
* Allows Calendar include path to be redefined
* @ignore
*/
if (!defined('CALENDAR_ROOT')) {
define('CALENDAR_ROOT', 'Calendar'.DIRECTORY_SEPARATOR);
}
 
/**
* Load Calendar decorator base class
*/
require_once CALENDAR_ROOT.'Decorator.php';
 
/**
* Static utlities to help with fetching textual representations of months and
* days of the week.
* @package Calendar
* @access public
*/
class Calendar_Util_Textual
{
 
/**
* Returns an array of 12 month names (first index = 1)
* @param string (optional) format of returned months (one,two,short or long)
* @return array
* @access public
* @static
*/
function monthNames($format='long')
{
$formats = array('one'=>'%b', 'two'=>'%b', 'short'=>'%b', 'long'=>'%B');
if (!array_key_exists($format,$formats)) {
$format = 'long';
}
$months = array();
for ($i=1; $i<=12; $i++) {
$stamp = mktime(0, 0, 0, $i, 1, 2003);
$month = strftime($formats[$format], $stamp);
switch($format) {
case 'one':
$month = substr($month, 0, 1);
break;
case 'two':
$month = substr($month, 0, 2);
break;
}
$months[$i] = $month;
}
return $months;
}
 
/**
* Returns an array of 7 week day names (first index = 0)
* @param string (optional) format of returned days (one,two,short or long)
* @return array
* @access public
* @static
*/
function weekdayNames($format='long')
{
$formats = array('one'=>'%a', 'two'=>'%a', 'short'=>'%a', 'long'=>'%A');
if (!array_key_exists($format,$formats)) {
$format = 'long';
}
$days = array();
for ($i=0; $i<=6; $i++) {
$stamp = mktime(0, 0, 0, 11, $i+2, 2003);
$day = strftime($formats[$format], $stamp);
switch($format) {
case 'one':
$day = substr($day, 0, 1);
break;
case 'two':
$day = substr($day, 0, 2);
break;
}
$days[$i] = $day;
}
return $days;
}
 
/**
* Returns textual representation of the previous month of the decorated calendar object
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function prevMonthName($Calendar, $format='long')
{
$months = Calendar_Util_Textual::monthNames($format);
return $months[$Calendar->prevMonth()];
}
 
/**
* Returns textual representation of the month of the decorated calendar object
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function thisMonthName($Calendar, $format='long')
{
$months = Calendar_Util_Textual::monthNames($format);
return $months[$Calendar->thisMonth()];
}
 
/**
* Returns textual representation of the next month of the decorated calendar object
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function nextMonthName($Calendar, $format='long')
{
$months = Calendar_Util_Textual::monthNames($format);
return $months[$Calendar->nextMonth()];
}
 
/**
* Returns textual representation of the previous day of week of the decorated calendar object
* <b>Note:</b> Requires PEAR::Date
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function prevDayName($Calendar, $format='long')
{
$days = Calendar_Util_Textual::weekdayNames($format);
$stamp = $Calendar->prevDay('timestamp');
$cE = $Calendar->getEngine();
require_once 'Date/Calc.php';
$day = Date_Calc::dayOfWeek($cE->stampToDay($stamp),
$cE->stampToMonth($stamp), $cE->stampToYear($stamp));
return $days[$day];
}
 
/**
* Returns textual representation of the day of week of the decorated calendar object
* <b>Note:</b> Requires PEAR::Date
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function thisDayName($Calendar, $format='long')
{
$days = Calendar_Util_Textual::weekdayNames($format);
require_once 'Date/Calc.php';
$day = Date_Calc::dayOfWeek($Calendar->thisDay(), $Calendar->thisMonth(), $Calendar->thisYear());
return $days[$day];
}
 
/**
* Returns textual representation of the next day of week of the decorated calendar object
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return string
* @access public
* @static
*/
function nextDayName($Calendar, $format='long')
{
$days = Calendar_Util_Textual::weekdayNames($format);
$stamp = $Calendar->nextDay('timestamp');
$cE = $Calendar->getEngine();
require_once 'Date/Calc.php';
$day = Date_Calc::dayOfWeek($cE->stampToDay($stamp),
$cE->stampToMonth($stamp), $cE->stampToYear($stamp));
return $days[$day];
}
 
/**
* Returns the days of the week using the order defined in the decorated
* calendar object. Only useful for Calendar_Month_Weekdays, Calendar_Month_Weeks
* and Calendar_Week. Otherwise the returned array will begin on Sunday
* @param object subclass of Calendar e.g. Calendar_Month
* @param string (optional) format of returned months (one,two,short or long)
* @return array ordered array of week day names
* @access public
* @static
*/
function orderedWeekdays($Calendar, $format='long')
{
$days = Calendar_Util_Textual::weekdayNames($format);
// Not so good - need methods to access this information perhaps...
if (isset($Calendar->tableHelper)) {
$ordereddays = $Calendar->tableHelper->daysOfWeek;
} else {
$ordereddays = array(0, 1, 2, 3, 4, 5, 6);
}
$ordereddays = array_flip($ordereddays);
$i = 0;
$returndays = array();
foreach ($ordereddays as $key => $value) {
$returndays[$i] = $days[$key];
$i++;
}
return $returndays;
}
}
?>
/branches/v1.0-menes/api/pear/DB.php
New file
0,0 → 1,1388
<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Database independent query interface
*
* 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 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: DB.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $
* @link http://pear.php.net/package/DB
*/
 
/**
* Obtain the PEAR class so it can be extended from
*/
require_once 'PEAR.php';
 
 
// {{{ constants
// {{{ error codes
 
/**#@+
* One of PEAR DB's portable error codes.
* @see DB_common::errorCode(), DB::errorMessage()
*
* {@internal If you add an error code here, make sure you also add a textual
* version of it in DB::errorMessage().}}
*/
 
/**
* The code returned by many methods upon success
*/
define('DB_OK', 1);
 
/**
* Unkown error
*/
define('DB_ERROR', -1);
 
/**
* Syntax error
*/
define('DB_ERROR_SYNTAX', -2);
 
/**
* Tried to insert a duplicate value into a primary or unique index
*/
define('DB_ERROR_CONSTRAINT', -3);
 
/**
* An identifier in the query refers to a non-existant object
*/
define('DB_ERROR_NOT_FOUND', -4);
 
/**
* Tried to create a duplicate object
*/
define('DB_ERROR_ALREADY_EXISTS', -5);
 
/**
* The current driver does not support the action you attempted
*/
define('DB_ERROR_UNSUPPORTED', -6);
 
/**
* The number of parameters does not match the number of placeholders
*/
define('DB_ERROR_MISMATCH', -7);
 
/**
* A literal submitted did not match the data type expected
*/
define('DB_ERROR_INVALID', -8);
 
/**
* The current DBMS does not support the action you attempted
*/
define('DB_ERROR_NOT_CAPABLE', -9);
 
/**
* A literal submitted was too long so the end of it was removed
*/
define('DB_ERROR_TRUNCATED', -10);
 
/**
* A literal number submitted did not match the data type expected
*/
define('DB_ERROR_INVALID_NUMBER', -11);
 
/**
* A literal date submitted did not match the data type expected
*/
define('DB_ERROR_INVALID_DATE', -12);
 
/**
* Attempt to divide something by zero
*/
define('DB_ERROR_DIVZERO', -13);
 
/**
* A database needs to be selected
*/
define('DB_ERROR_NODBSELECTED', -14);
 
/**
* Could not create the object requested
*/
define('DB_ERROR_CANNOT_CREATE', -15);
 
/**
* Could not drop the database requested because it does not exist
*/
define('DB_ERROR_CANNOT_DROP', -17);
 
/**
* An identifier in the query refers to a non-existant table
*/
define('DB_ERROR_NOSUCHTABLE', -18);
 
/**
* An identifier in the query refers to a non-existant column
*/
define('DB_ERROR_NOSUCHFIELD', -19);
 
/**
* The data submitted to the method was inappropriate
*/
define('DB_ERROR_NEED_MORE_DATA', -20);
 
/**
* The attempt to lock the table failed
*/
define('DB_ERROR_NOT_LOCKED', -21);
 
/**
* The number of columns doesn't match the number of values
*/
define('DB_ERROR_VALUE_COUNT_ON_ROW', -22);
 
/**
* The DSN submitted has problems
*/
define('DB_ERROR_INVALID_DSN', -23);
 
/**
* Could not connect to the database
*/
define('DB_ERROR_CONNECT_FAILED', -24);
 
/**
* The PHP extension needed for this DBMS could not be found
*/
define('DB_ERROR_EXTENSION_NOT_FOUND',-25);
 
/**
* The present user has inadequate permissions to perform the task requestd
*/
define('DB_ERROR_ACCESS_VIOLATION', -26);
 
/**
* The database requested does not exist
*/
define('DB_ERROR_NOSUCHDB', -27);
 
/**
* Tried to insert a null value into a column that doesn't allow nulls
*/
define('DB_ERROR_CONSTRAINT_NOT_NULL',-29);
/**#@-*/
 
 
// }}}
// {{{ prepared statement-related
 
 
/**#@+
* Identifiers for the placeholders used in prepared statements.
* @see DB_common::prepare()
*/
 
/**
* Indicates a scalar (<kbd>?</kbd>) placeholder was used
*
* Quote and escape the value as necessary.
*/
define('DB_PARAM_SCALAR', 1);
 
/**
* Indicates an opaque (<kbd>&</kbd>) placeholder was used
*
* The value presented is a file name. Extract the contents of that file
* and place them in this column.
*/
define('DB_PARAM_OPAQUE', 2);
 
/**
* Indicates a misc (<kbd>!</kbd>) placeholder was used
*
* The value should not be quoted or escaped.
*/
define('DB_PARAM_MISC', 3);
/**#@-*/
 
 
// }}}
// {{{ binary data-related
 
 
/**#@+
* The different ways of returning binary data from queries.
*/
 
/**
* Sends the fetched data straight through to output
*/
define('DB_BINMODE_PASSTHRU', 1);
 
/**
* Lets you return data as usual
*/
define('DB_BINMODE_RETURN', 2);
 
/**
* Converts the data to hex format before returning it
*
* For example the string "123" would become "313233".
*/
define('DB_BINMODE_CONVERT', 3);
/**#@-*/
 
 
// }}}
// {{{ fetch modes
 
 
/**#@+
* Fetch Modes.
* @see DB_common::setFetchMode()
*/
 
/**
* Indicates the current default fetch mode should be used
* @see DB_common::$fetchmode
*/
define('DB_FETCHMODE_DEFAULT', 0);
 
/**
* Column data indexed by numbers, ordered from 0 and up
*/
define('DB_FETCHMODE_ORDERED', 1);
 
/**
* Column data indexed by column names
*/
define('DB_FETCHMODE_ASSOC', 2);
 
/**
* Column data as object properties
*/
define('DB_FETCHMODE_OBJECT', 3);
 
/**
* For multi-dimensional results, make the column name the first level
* of the array and put the row number in the second level of the array
*
* This is flipped from the normal behavior, which puts the row numbers
* in the first level of the array and the column names in the second level.
*/
define('DB_FETCHMODE_FLIPPED', 4);
/**#@-*/
 
/**#@+
* Old fetch modes. Left here for compatibility.
*/
define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC);
define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED);
/**#@-*/
 
 
// }}}
// {{{ tableInfo() && autoPrepare()-related
 
 
/**#@+
* The type of information to return from the tableInfo() method.
*
* Bitwised constants, so they can be combined using <kbd>|</kbd>
* and removed using <kbd>^</kbd>.
*
* @see DB_common::tableInfo()
*
* {@internal Since the TABLEINFO constants are bitwised, if more of them are
* added in the future, make sure to adjust DB_TABLEINFO_FULL accordingly.}}
*/
define('DB_TABLEINFO_ORDER', 1);
define('DB_TABLEINFO_ORDERTABLE', 2);
define('DB_TABLEINFO_FULL', 3);
/**#@-*/
 
 
/**#@+
* The type of query to create with the automatic query building methods.
* @see DB_common::autoPrepare(), DB_common::autoExecute()
*/
define('DB_AUTOQUERY_INSERT', 1);
define('DB_AUTOQUERY_UPDATE', 2);
/**#@-*/
 
 
// }}}
// {{{ portability modes
 
 
/**#@+
* Portability Modes.
*
* Bitwised constants, so they can be combined using <kbd>|</kbd>
* and removed using <kbd>^</kbd>.
*
* @see DB_common::setOption()
*
* {@internal Since the PORTABILITY constants are bitwised, if more of them are
* added in the future, make sure to adjust DB_PORTABILITY_ALL accordingly.}}
*/
 
/**
* Turn off all portability features
*/
define('DB_PORTABILITY_NONE', 0);
 
/**
* Convert names of tables and fields to lower case
* when using the get*(), fetch*() and tableInfo() methods
*/
define('DB_PORTABILITY_LOWERCASE', 1);
 
/**
* Right trim the data output by get*() and fetch*()
*/
define('DB_PORTABILITY_RTRIM', 2);
 
/**
* Force reporting the number of rows deleted
*/
define('DB_PORTABILITY_DELETE_COUNT', 4);
 
/**
* Enable hack that makes numRows() work in Oracle
*/
define('DB_PORTABILITY_NUMROWS', 8);
 
/**
* Makes certain error messages in certain drivers compatible
* with those from other DBMS's
*
* + mysql, mysqli: change unique/primary key constraints
* DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT
*
* + odbc(access): MS's ODBC driver reports 'no such field' as code
* 07001, which means 'too few parameters.' When this option is on
* that code gets mapped to DB_ERROR_NOSUCHFIELD.
*/
define('DB_PORTABILITY_ERRORS', 16);
 
/**
* Convert null values to empty strings in data output by
* get*() and fetch*()
*/
define('DB_PORTABILITY_NULL_TO_EMPTY', 32);
 
/**
* Turn on all portability features
*/
define('DB_PORTABILITY_ALL', 63);
/**#@-*/
 
// }}}
 
 
// }}}
// {{{ class DB
 
/**
* Database independent query interface
*
* The main "DB" class is simply a container class with some static
* methods for creating DB objects as well as some utility functions
* common to all parts of DB.
*
* The object model of DB is as follows (indentation means inheritance):
* <pre>
* DB The main DB class. This is simply a utility class
* with some "static" methods for creating DB objects as
* well as common utility functions for other DB classes.
*
* DB_common The base for each DB implementation. Provides default
* | implementations (in OO lingo virtual methods) for
* | the actual DB implementations as well as a bunch of
* | query utility functions.
* |
* +-DB_mysql The DB implementation for MySQL. Inherits DB_common.
* When calling DB::factory or DB::connect for MySQL
* connections, the object returned is an instance of this
* class.
* </pre>
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @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: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB
{
// {{{ &factory()
 
/**
* Create a new DB object for the specified database type but don't
* connect to the database
*
* @param string $type the database type (eg "mysql")
* @param array $options an associative array of option names and values
*
* @return object a new DB object. A DB_Error object on failure.
*
* @see DB_common::setOption()
*/
function &factory($type, $options = false)
{
if (!is_array($options)) {
$options = array('persistent' => $options);
}
 
if (isset($options['debug']) && $options['debug'] >= 2) {
// expose php errors with sufficient debug level
include_once "DB/{$type}.php";
} else {
@include_once "DB/{$type}.php";
}
 
$classname = "DB_${type}";
 
if (!class_exists($classname)) {
$tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null,
"Unable to include the DB/{$type}.php"
. " file for '$dsn'",
'DB_Error', true);
return $tmp;
}
 
@$obj =& new $classname;
 
foreach ($options as $option => $value) {
$test = $obj->setOption($option, $value);
if (DB::isError($test)) {
return $test;
}
}
 
return $obj;
}
 
// }}}
// {{{ &connect()
 
/**
* Create a new DB object including a connection to the specified database
*
* Example 1.
* <code>
* require_once 'DB.php';
*
* $dsn = 'pgsql://user:password@host/database';
* $options = array(
* 'debug' => 2,
* 'portability' => DB_PORTABILITY_ALL,
* );
*
* $db =& DB::connect($dsn, $options);
* if (PEAR::isError($db)) {
* die($db->getMessage());
* }
* </code>
*
* @param mixed $dsn the string "data source name" or array in the
* format returned by DB::parseDSN()
* @param array $options an associative array of option names and values
*
* @return object a new DB object. A DB_Error object on failure.
*
* @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(),
* DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(),
* DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(),
* DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(),
* DB_sybase::connect()
*
* @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError()
*/
function &connect($dsn, $options = array())
{
$dsninfo = DB::parseDSN($dsn);
$type = $dsninfo['phptype'];
 
if (!is_array($options)) {
/*
* For backwards compatibility. $options used to be boolean,
* indicating whether the connection should be persistent.
*/
$options = array('persistent' => $options);
}
 
if (isset($options['debug']) && $options['debug'] >= 2) {
// expose php errors with sufficient debug level
include_once "DB/${type}.php";
} else {
@include_once "DB/${type}.php";
}
 
$classname = "DB_${type}";
if (!class_exists($classname)) {
$tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null,
"Unable to include the DB/{$type}.php"
. " file for '$dsn'",
'DB_Error', true);
return $tmp;
}
 
@$obj =& new $classname;
 
foreach ($options as $option => $value) {
$test = $obj->setOption($option, $value);
if (DB::isError($test)) {
return $test;
}
}
 
$err = $obj->connect($dsninfo, $obj->getOption('persistent'));
if (DB::isError($err)) {
$err->addUserInfo($dsn);
return $err;
}
 
return $obj;
}
 
// }}}
// {{{ apiVersion()
 
/**
* Return the DB API version
*
* @return string the DB API version number
*/
function apiVersion()
{
return '@package_version@';
}
 
// }}}
// {{{ isError()
 
/**
* Determines if a variable is a DB_Error object
*
* @param mixed $value the variable to check
*
* @return bool whether $value is DB_Error object
*/
function isError($value)
{
return is_a($value, 'DB_Error');
}
 
// }}}
// {{{ isConnection()
 
/**
* Determines if a value is a DB_<driver> object
*
* @param mixed $value the value to test
*
* @return bool whether $value is a DB_<driver> object
*/
function isConnection($value)
{
return (is_object($value) &&
is_subclass_of($value, 'db_common') &&
method_exists($value, 'simpleQuery'));
}
 
// }}}
// {{{ isManip()
 
/**
* Tell whether a query is a data manipulation or data definition query
*
* Examples of data manipulation queries are INSERT, UPDATE and DELETE.
* Examples of data definition queries are CREATE, DROP, ALTER, GRANT,
* REVOKE.
*
* @param string $query the query
*
* @return boolean whether $query is a data manipulation query
*/
function isManip($query)
{
$manips = 'INSERT|UPDATE|DELETE|REPLACE|'
. 'CREATE|DROP|'
. 'LOAD DATA|SELECT .* INTO|COPY|'
. 'ALTER|GRANT|REVOKE|'
. 'LOCK|UNLOCK';
if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) {
return true;
}
return false;
}
 
// }}}
// {{{ errorMessage()
 
/**
* Return a textual error message for a DB error code
*
* @param integer $value the DB error code
*
* @return string the error message or false if the error code was
* not recognized
*/
function errorMessage($value)
{
static $errorMessages;
if (!isset($errorMessages)) {
$errorMessages = array(
DB_ERROR => 'unknown error',
DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions',
DB_ERROR_ALREADY_EXISTS => 'already exists',
DB_ERROR_CANNOT_CREATE => 'can not create',
DB_ERROR_CANNOT_DROP => 'can not drop',
DB_ERROR_CONNECT_FAILED => 'connect failed',
DB_ERROR_CONSTRAINT => 'constraint violation',
DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
DB_ERROR_DIVZERO => 'division by zero',
DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
DB_ERROR_INVALID => 'invalid',
DB_ERROR_INVALID_DATE => 'invalid date or time',
DB_ERROR_INVALID_DSN => 'invalid DSN',
DB_ERROR_INVALID_NUMBER => 'invalid number',
DB_ERROR_MISMATCH => 'mismatch',
DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied',
DB_ERROR_NODBSELECTED => 'no database selected',
DB_ERROR_NOSUCHDB => 'no such database',
DB_ERROR_NOSUCHFIELD => 'no such field',
DB_ERROR_NOSUCHTABLE => 'no such table',
DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
DB_ERROR_NOT_FOUND => 'not found',
DB_ERROR_NOT_LOCKED => 'not locked',
DB_ERROR_SYNTAX => 'syntax error',
DB_ERROR_UNSUPPORTED => 'not supported',
DB_ERROR_TRUNCATED => 'truncated',
DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
DB_OK => 'no error',
);
}
 
if (DB::isError($value)) {
$value = $value->getCode();
}
 
return isset($errorMessages[$value]) ? $errorMessages[$value]
: $errorMessages[DB_ERROR];
}
 
// }}}
// {{{ parseDSN()
 
/**
* Parse a data source name
*
* Additional keys can be added by appending a URI query string to the
* end of the DSN.
*
* The format of the supplied DSN is in its fullest form:
* <code>
* phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
* </code>
*
* Most variations are allowed:
* <code>
* phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
* phptype://username:password@hostspec/database_name
* phptype://username:password@hostspec
* phptype://username@hostspec
* phptype://hostspec/database
* phptype://hostspec
* phptype(dbsyntax)
* phptype
* </code>
*
* @param string $dsn Data Source Name to be parsed
*
* @return array an associative array with the following keys:
* + phptype: Database backend used in PHP (mysql, odbc etc.)
* + dbsyntax: Database used with regards to SQL syntax etc.
* + protocol: Communication protocol to use (tcp, unix etc.)
* + hostspec: Host specification (hostname[:port])
* + database: Database to use on the DBMS server
* + username: User name for login
* + password: Password for login
*/
function parseDSN($dsn)
{
$parsed = array(
'phptype' => false,
'dbsyntax' => false,
'username' => false,
'password' => false,
'protocol' => false,
'hostspec' => false,
'port' => false,
'socket' => false,
'database' => false,
);
 
if (is_array($dsn)) {
$dsn = array_merge($parsed, $dsn);
if (!$dsn['dbsyntax']) {
$dsn['dbsyntax'] = $dsn['phptype'];
}
return $dsn;
}
 
// Find phptype and dbsyntax
if (($pos = strpos($dsn, '://')) !== false) {
$str = substr($dsn, 0, $pos);
$dsn = substr($dsn, $pos + 3);
} else {
$str = $dsn;
$dsn = null;
}
 
// Get phptype and dbsyntax
// $str => phptype(dbsyntax)
if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
$parsed['phptype'] = $arr[1];
$parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
} else {
$parsed['phptype'] = $str;
$parsed['dbsyntax'] = $str;
}
 
if (!count($dsn)) {
return $parsed;
}
 
// Get (if found): username and password
// $dsn => username:password@protocol+hostspec/database
if (($at = strrpos($dsn,'@')) !== false) {
$str = substr($dsn, 0, $at);
$dsn = substr($dsn, $at + 1);
if (($pos = strpos($str, ':')) !== false) {
$parsed['username'] = rawurldecode(substr($str, 0, $pos));
$parsed['password'] = rawurldecode(substr($str, $pos + 1));
} else {
$parsed['username'] = rawurldecode($str);
}
}
 
// Find protocol and hostspec
 
if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
// $dsn => proto(proto_opts)/database
$proto = $match[1];
$proto_opts = $match[2] ? $match[2] : false;
$dsn = $match[3];
 
} else {
// $dsn => protocol+hostspec/database (old format)
if (strpos($dsn, '+') !== false) {
list($proto, $dsn) = explode('+', $dsn, 2);
}
if (strpos($dsn, '/') !== false) {
list($proto_opts, $dsn) = explode('/', $dsn, 2);
} else {
$proto_opts = $dsn;
$dsn = null;
}
}
 
// process the different protocol options
$parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
$proto_opts = rawurldecode($proto_opts);
if ($parsed['protocol'] == 'tcp') {
if (strpos($proto_opts, ':') !== false) {
list($parsed['hostspec'],
$parsed['port']) = explode(':', $proto_opts);
} else {
$parsed['hostspec'] = $proto_opts;
}
} elseif ($parsed['protocol'] == 'unix') {
$parsed['socket'] = $proto_opts;
}
 
// Get dabase if any
// $dsn => database
if ($dsn) {
if (($pos = strpos($dsn, '?')) === false) {
// /database
$parsed['database'] = rawurldecode($dsn);
} else {
// /database?param1=value1&param2=value2
$parsed['database'] = rawurldecode(substr($dsn, 0, $pos));
$dsn = substr($dsn, $pos + 1);
if (strpos($dsn, '&') !== false) {
$opts = explode('&', $dsn);
} else { // database?param1=value1
$opts = array($dsn);
}
foreach ($opts as $opt) {
list($key, $value) = explode('=', $opt);
if (!isset($parsed[$key])) {
// don't allow params overwrite
$parsed[$key] = rawurldecode($value);
}
}
}
}
 
return $parsed;
}
 
// }}}
}
 
// }}}
// {{{ class DB_Error
 
/**
* DB_Error implements a class for reporting portable database error
* messages
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_Error extends PEAR_Error
{
// {{{ constructor
 
/**
* DB_Error constructor
*
* @param mixed $code DB error code, or string with error message
* @param int $mode what "error mode" to operate in
* @param int $level what error level to use for $mode &
* PEAR_ERROR_TRIGGER
* @param mixed $debuginfo additional debug info, such as the last query
*
* @see PEAR_Error
*/
function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
$level = E_USER_NOTICE, $debuginfo = null)
{
if (is_int($code)) {
$this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code,
$mode, $level, $debuginfo);
} else {
$this->PEAR_Error("DB Error: $code", DB_ERROR,
$mode, $level, $debuginfo);
}
}
 
// }}}
}
 
// }}}
// {{{ class DB_result
 
/**
* This class implements a wrapper for a DB result set
*
* A new instance of this class will be returned by the DB implementation
* after processing a query that returns data.
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_result
{
// {{{ properties
 
/**
* Should results be freed automatically when there are no more rows?
* @var boolean
* @see DB_common::$options
*/
var $autofree;
 
/**
* A reference to the DB_<driver> object
* @var object
*/
var $dbh;
 
/**
* The current default fetch mode
* @var integer
* @see DB_common::$fetchmode
*/
var $fetchmode;
 
/**
* The name of the class into which results should be fetched when
* DB_FETCHMODE_OBJECT is in effect
*
* @var string
* @see DB_common::$fetchmode_object_class
*/
var $fetchmode_object_class;
 
/**
* The number of rows to fetch from a limit query
* @var integer
*/
var $limit_count = null;
 
/**
* The row to start fetching from in limit queries
* @var integer
*/
var $limit_from = null;
 
/**
* The execute parameters that created this result
* @var array
* @since Property available since Release 1.7.0
*/
var $parameters;
 
/**
* The query string that created this result
*
* Copied here incase it changes in $dbh, which is referenced
*
* @var string
* @since Property available since Release 1.7.0
*/
var $query;
 
/**
* The query result resource id created by PHP
* @var resource
*/
var $result;
 
/**
* The present row being dealt with
* @var integer
*/
var $row_counter = null;
 
/**
* The prepared statement resource id created by PHP in $dbh
*
* This resource is only available when the result set was created using
* a driver's native execute() method, not PEAR DB's emulated one.
*
* Copied here incase it changes in $dbh, which is referenced
*
* {@internal Mainly here because the InterBase/Firebird API is only
* able to retrieve data from result sets if the statemnt handle is
* still in scope.}}
*
* @var resource
* @since Property available since Release 1.7.0
*/
var $statement;
 
 
// }}}
// {{{ constructor
 
/**
* This constructor sets the object's properties
*
* @param object &$dbh the DB object reference
* @param resource $result the result resource id
* @param array $options an associative array with result options
*
* @return void
*/
function DB_result(&$dbh, $result, $options = array())
{
$this->autofree = $dbh->options['autofree'];
$this->dbh = &$dbh;
$this->fetchmode = $dbh->fetchmode;
$this->fetchmode_object_class = $dbh->fetchmode_object_class;
$this->parameters = $dbh->last_parameters;
$this->query = $dbh->last_query;
$this->result = $result;
$this->statement = empty($dbh->last_stmt) ? null : $dbh->last_stmt;
foreach ($options as $key => $value) {
$this->setOption($key, $value);
}
}
 
/**
* Set options for the DB_result object
*
* @param string $key the option to set
* @param mixed $value the value to set the option to
*
* @return void
*/
function setOption($key, $value = null)
{
switch ($key) {
case 'limit_from':
$this->limit_from = $value;
break;
case 'limit_count':
$this->limit_count = $value;
}
}
 
// }}}
// {{{ fetchRow()
 
/**
* Fetch a row of data and return it by reference into an array
*
* The type of array returned can be controlled either by setting this
* method's <var>$fetchmode</var> parameter or by changing the default
* fetch mode setFetchMode() before calling this method.
*
* There are two options for standardizing the information returned
* from databases, ensuring their values are consistent when changing
* DBMS's. These portability options can be turned on when creating a
* new DB object or by using setOption().
*
* + <var>DB_PORTABILITY_LOWERCASE</var>
* convert names of fields to lower case
*
* + <var>DB_PORTABILITY_RTRIM</var>
* right trim the data
*
* @param int $fetchmode the constant indicating how to format the data
* @param int $rownum the row number to fetch (index starts at 0)
*
* @return mixed an array or object containing the row's data,
* NULL when the end of the result set is reached
* or a DB_Error object on failure.
*
* @see DB_common::setOption(), DB_common::setFetchMode()
*/
function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null)
{
if ($fetchmode === DB_FETCHMODE_DEFAULT) {
$fetchmode = $this->fetchmode;
}
if ($fetchmode === DB_FETCHMODE_OBJECT) {
$fetchmode = DB_FETCHMODE_ASSOC;
$object_class = $this->fetchmode_object_class;
}
if ($this->limit_from !== null) {
if ($this->row_counter === null) {
$this->row_counter = $this->limit_from;
// Skip rows
if ($this->dbh->features['limit'] === false) {
$i = 0;
while ($i++ < $this->limit_from) {
$this->dbh->fetchInto($this->result, $arr, $fetchmode);
}
}
}
if ($this->row_counter >= ($this->limit_from + $this->limit_count))
{
if ($this->autofree) {
$this->free();
}
$tmp = null;
return $tmp;
}
if ($this->dbh->features['limit'] === 'emulate') {
$rownum = $this->row_counter;
}
$this->row_counter++;
}
$res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
if ($res === DB_OK) {
if (isset($object_class)) {
// The default mode is specified in the
// DB_common::fetchmode_object_class property
if ($object_class == 'stdClass') {
$arr = (object) $arr;
} else {
$arr = &new $object_class($arr);
}
}
return $arr;
}
if ($res == null && $this->autofree) {
$this->free();
}
return $res;
}
 
// }}}
// {{{ fetchInto()
 
/**
* Fetch a row of data into an array which is passed by reference
*
* The type of array returned can be controlled either by setting this
* method's <var>$fetchmode</var> parameter or by changing the default
* fetch mode setFetchMode() before calling this method.
*
* There are two options for standardizing the information returned
* from databases, ensuring their values are consistent when changing
* DBMS's. These portability options can be turned on when creating a
* new DB object or by using setOption().
*
* + <var>DB_PORTABILITY_LOWERCASE</var>
* convert names of fields to lower case
*
* + <var>DB_PORTABILITY_RTRIM</var>
* right trim the data
*
* @param array &$arr the variable where the data should be placed
* @param int $fetchmode the constant indicating how to format the data
* @param int $rownum the row number to fetch (index starts at 0)
*
* @return mixed DB_OK if a row is processed, NULL when the end of the
* result set is reached or a DB_Error object on failure
*
* @see DB_common::setOption(), DB_common::setFetchMode()
*/
function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null)
{
if ($fetchmode === DB_FETCHMODE_DEFAULT) {
$fetchmode = $this->fetchmode;
}
if ($fetchmode === DB_FETCHMODE_OBJECT) {
$fetchmode = DB_FETCHMODE_ASSOC;
$object_class = $this->fetchmode_object_class;
}
if ($this->limit_from !== null) {
if ($this->row_counter === null) {
$this->row_counter = $this->limit_from;
// Skip rows
if ($this->dbh->features['limit'] === false) {
$i = 0;
while ($i++ < $this->limit_from) {
$this->dbh->fetchInto($this->result, $arr, $fetchmode);
}
}
}
if ($this->row_counter >= (
$this->limit_from + $this->limit_count))
{
if ($this->autofree) {
$this->free();
}
return null;
}
if ($this->dbh->features['limit'] === 'emulate') {
$rownum = $this->row_counter;
}
 
$this->row_counter++;
}
$res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
if ($res === DB_OK) {
if (isset($object_class)) {
// default mode specified in the
// DB_common::fetchmode_object_class property
if ($object_class == 'stdClass') {
$arr = (object) $arr;
} else {
$arr = new $object_class($arr);
}
}
return DB_OK;
}
if ($res == null && $this->autofree) {
$this->free();
}
return $res;
}
 
// }}}
// {{{ numCols()
 
/**
* Get the the number of columns in a result set
*
* @return int the number of columns. A DB_Error object on failure.
*/
function numCols()
{
return $this->dbh->numCols($this->result);
}
 
// }}}
// {{{ numRows()
 
/**
* Get the number of rows in a result set
*
* @return int the number of rows. A DB_Error object on failure.
*/
function numRows()
{
if ($this->dbh->features['numrows'] === 'emulate'
&& $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS)
{
if ($this->dbh->features['prepare']) {
$res = $this->dbh->query($this->query, $this->parameters);
} else {
$res = $this->dbh->query($this->query);
}
if (DB::isError($res)) {
return $res;
}
$i = 0;
while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) {
$i++;
}
return $i;
} else {
return $this->dbh->numRows($this->result);
}
}
 
// }}}
// {{{ nextResult()
 
/**
* Get the next result if a batch of queries was executed
*
* @return bool true if a new result is available or false if not
*/
function nextResult()
{
return $this->dbh->nextResult($this->result);
}
 
// }}}
// {{{ free()
 
/**
* Frees the resources allocated for this result set
*
* @return bool true on success. A DB_Error object on failure.
*/
function free()
{
$err = $this->dbh->freeResult($this->result);
if (DB::isError($err)) {
return $err;
}
$this->result = false;
$this->statement = false;
return true;
}
 
// }}}
// {{{ tableInfo()
 
/**
* @see DB_common::tableInfo()
* @deprecated Method deprecated some time before Release 1.2
*/
function tableInfo($mode = null)
{
if (is_string($mode)) {
return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA);
}
return $this->dbh->tableInfo($this, $mode);
}
 
// }}}
// {{{ getQuery()
 
/**
* Determine the query string that created this result
*
* @return string the query string
*
* @since Method available since Release 1.7.0
*/
function getQuery()
{
return $this->query;
}
 
// }}}
// {{{ getRowCounter()
 
/**
* Tells which row number is currently being processed
*
* @return integer the current row being looked at. Starts at 1.
*/
function getRowCounter()
{
return $this->row_counter;
}
 
// }}}
}
 
// }}}
// {{{ class DB_row
 
/**
* PEAR DB Row Object
*
* The object contains a row of data from a result set. Each column's data
* is placed in a property named for the column.
*
* @category Database
* @package DB
* @author Stig Bakken <ssb@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: @package_version@
* @link http://pear.php.net/package/DB
* @see DB_common::setFetchMode()
*/
class DB_row
{
// {{{ constructor
 
/**
* The constructor places a row's data into properties of this object
*
* @param array the array containing the row's data
*
* @return void
*/
function DB_row(&$arr)
{
foreach ($arr as $key => $value) {
$this->$key = &$arr[$key];
}
}
 
// }}}
}
 
// }}}
 
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
 
?>
/branches/v1.0-menes/api/pear/PEAR.php
New file
0,0 → 1,1055
<?php
//
// +--------------------------------------------------------------------+
// | PEAR, the PHP Extension and Application Repository |
// +--------------------------------------------------------------------+
// | 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: Sterling Hughes <sterling@php.net> |
// | Stig Bakken <ssb@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// +--------------------------------------------------------------------+
//
// $Id: PEAR.php,v 1.1 2005-03-30 08:50:19 jpm Exp $
//
 
define('PEAR_ERROR_RETURN', 1);
define('PEAR_ERROR_PRINT', 2);
define('PEAR_ERROR_TRIGGER', 4);
define('PEAR_ERROR_DIE', 8);
define('PEAR_ERROR_CALLBACK', 16);
/**
* WARNING: obsolete
* @deprecated
*/
define('PEAR_ERROR_EXCEPTION', 32);
define('PEAR_ZE2', (function_exists('version_compare') &&
version_compare(zend_version(), "2-dev", "ge")));
 
if (substr(PHP_OS, 0, 3) == 'WIN') {
define('OS_WINDOWS', true);
define('OS_UNIX', false);
define('PEAR_OS', 'Windows');
} else {
define('OS_WINDOWS', false);
define('OS_UNIX', true);
define('PEAR_OS', 'Unix'); // blatant assumption
}
 
// instant backwards compatibility
if (!defined('PATH_SEPARATOR')) {
if (OS_WINDOWS) {
define('PATH_SEPARATOR', ';');
} else {
define('PATH_SEPARATOR', ':');
}
}
 
$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
$GLOBALS['_PEAR_destructor_object_list'] = array();
$GLOBALS['_PEAR_shutdown_funcs'] = array();
$GLOBALS['_PEAR_error_handler_stack'] = array();
 
@ini_set('track_errors', true);
 
/**
* Base class for other PEAR classes. Provides rudimentary
* emulation of destructors.
*
* If you want a destructor in your class, inherit PEAR and make a
* destructor method called _yourclassname (same name as the
* constructor, but with a "_" prefix). Also, in your constructor you
* have to call the PEAR constructor: $this->PEAR();.
* The destructor method will be called without parameters. Note that
* at in some SAPI implementations (such as Apache), any output during
* the request shutdown (in which destructors are called) seems to be
* discarded. If you need to get any debug information from your
* destructor, use error_log(), syslog() or something similar.
*
* IMPORTANT! To use the emulated destructors you need to create the
* objects by reference: $obj =& new PEAR_child;
*
* @since PHP 4.0.2
* @author Stig Bakken <ssb@php.net>
* @see http://pear.php.net/manual/
*/
class PEAR
{
// {{{ properties
 
/**
* Whether to enable internal debug messages.
*
* @var bool
* @access private
*/
var $_debug = false;
 
/**
* Default error mode for this object.
*
* @var int
* @access private
*/
var $_default_error_mode = null;
 
/**
* Default error options used for this object when error mode
* is PEAR_ERROR_TRIGGER.
*
* @var int
* @access private
*/
var $_default_error_options = null;
 
/**
* Default error handler (callback) for this object, if error mode is
* PEAR_ERROR_CALLBACK.
*
* @var string
* @access private
*/
var $_default_error_handler = '';
 
/**
* Which class to use for error objects.
*
* @var string
* @access private
*/
var $_error_class = 'PEAR_Error';
 
/**
* An array of expected errors.
*
* @var array
* @access private
*/
var $_expected_errors = array();
 
// }}}
 
// {{{ constructor
 
/**
* Constructor. Registers this object in
* $_PEAR_destructor_object_list for destructor emulation if a
* destructor object exists.
*
* @param string $error_class (optional) which class to use for
* error objects, defaults to PEAR_Error.
* @access public
* @return void
*/
function PEAR($error_class = null)
{
$classname = strtolower(get_class($this));
if ($this->_debug) {
print "PEAR constructor called, class=$classname\n";
}
if ($error_class !== null) {
$this->_error_class = $error_class;
}
while ($classname && strcasecmp($classname, "pear")) {
$destructor = "_$classname";
if (method_exists($this, $destructor)) {
global $_PEAR_destructor_object_list;
$_PEAR_destructor_object_list[] = &$this;
if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
register_shutdown_function("_PEAR_call_destructors");
$GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
}
break;
} else {
$classname = get_parent_class($classname);
}
}
}
 
// }}}
// {{{ destructor
 
/**
* Destructor (the emulated type of...). Does nothing right now,
* but is included for forward compatibility, so subclass
* destructors should always call it.
*
* See the note in the class desciption about output from
* destructors.
*
* @access public
* @return void
*/
function _PEAR() {
if ($this->_debug) {
printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
}
}
 
// }}}
// {{{ getStaticProperty()
 
/**
* If you have a class that's mostly/entirely static, and you need static
* properties, you can use this method to simulate them. Eg. in your method(s)
* do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
* You MUST use a reference, or they will not persist!
*
* @access public
* @param string $class The calling classname, to prevent clashes
* @param string $var The variable to retrieve.
* @return mixed A reference to the variable. If not set it will be
* auto initialised to NULL.
*/
function &getStaticProperty($class, $var)
{
static $properties;
return $properties[$class][$var];
}
 
// }}}
// {{{ registerShutdownFunc()
 
/**
* Use this function to register a shutdown method for static
* classes.
*
* @access public
* @param mixed $func The function name (or array of class/method) to call
* @param mixed $args The arguments to pass to the function
* @return void
*/
function registerShutdownFunc($func, $args = array())
{
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
}
 
// }}}
// {{{ isError()
 
/**
* Tell whether a value is a PEAR error.
*
* @param mixed $data the value to test
* @param int $code if $data is an error object, return true
* only if $code is a string and
* $obj->getMessage() == $code or
* $code is an integer and $obj->getCode() == $code
* @access public
* @return bool true if parameter is an error
*/
function isError($data, $code = null)
{
if (is_a($data, 'PEAR_Error')) {
if (is_null($code)) {
return true;
} elseif (is_string($code)) {
return $data->getMessage() == $code;
} else {
return $data->getCode() == $code;
}
}
return false;
}
 
// }}}
// {{{ setErrorHandling()
 
/**
* Sets how errors generated by this object should be handled.
* Can be invoked both in objects and statically. If called
* statically, setErrorHandling sets the default behaviour for all
* PEAR objects. If called in an object, setErrorHandling sets
* the default behaviour for that object.
*
* @param int $mode
* One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
*
* @param mixed $options
* When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
* of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
*
* When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
* to be the callback function or method. A callback
* function is a string with the name of the function, a
* callback method is an array of two elements: the element
* at index 0 is the object, and the element at index 1 is
* the name of the method to call in the object.
*
* When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
* a printf format string used when printing the error
* message.
*
* @access public
* @return void
* @see PEAR_ERROR_RETURN
* @see PEAR_ERROR_PRINT
* @see PEAR_ERROR_TRIGGER
* @see PEAR_ERROR_DIE
* @see PEAR_ERROR_CALLBACK
* @see PEAR_ERROR_EXCEPTION
*
* @since PHP 4.0.5
*/
 
function setErrorHandling($mode = null, $options = null)
{
if (isset($this) && is_a($this, 'PEAR')) {
$setmode = &$this->_default_error_mode;
$setoptions = &$this->_default_error_options;
} else {
$setmode = &$GLOBALS['_PEAR_default_error_mode'];
$setoptions = &$GLOBALS['_PEAR_default_error_options'];
}
 
switch ($mode) {
case PEAR_ERROR_EXCEPTION:
case PEAR_ERROR_RETURN:
case PEAR_ERROR_PRINT:
case PEAR_ERROR_TRIGGER:
case PEAR_ERROR_DIE:
case null:
$setmode = $mode;
$setoptions = $options;
break;
 
case PEAR_ERROR_CALLBACK:
$setmode = $mode;
// class/object method callback
if (is_callable($options)) {
$setoptions = $options;
} else {
trigger_error("invalid error callback", E_USER_WARNING);
}
break;
 
default:
trigger_error("invalid error mode", E_USER_WARNING);
break;
}
}
 
// }}}
// {{{ expectError()
 
/**
* This method is used to tell which errors you expect to get.
* Expected errors are always returned with error mode
* PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
* and this method pushes a new element onto it. The list of
* expected errors are in effect until they are popped off the
* stack with the popExpect() method.
*
* Note that this method can not be called statically
*
* @param mixed $code a single error code or an array of error codes to expect
*
* @return int the new depth of the "expected errors" stack
* @access public
*/
function expectError($code = '*')
{
if (is_array($code)) {
array_push($this->_expected_errors, $code);
} else {
array_push($this->_expected_errors, array($code));
}
return sizeof($this->_expected_errors);
}
 
// }}}
// {{{ popExpect()
 
/**
* This method pops one element off the expected error codes
* stack.
*
* @return array the list of error codes that were popped
*/
function popExpect()
{
return array_pop($this->_expected_errors);
}
 
// }}}
// {{{ _checkDelExpect()
 
/**
* This method checks unsets an error code if available
*
* @param mixed error code
* @return bool true if the error code was unset, false otherwise
* @access private
* @since PHP 4.3.0
*/
function _checkDelExpect($error_code)
{
$deleted = false;
 
foreach ($this->_expected_errors AS $key => $error_array) {
if (in_array($error_code, $error_array)) {
unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
$deleted = true;
}
 
// clean up empty arrays
if (0 == count($this->_expected_errors[$key])) {
unset($this->_expected_errors[$key]);
}
}
return $deleted;
}
 
// }}}
// {{{ delExpect()
 
/**
* This method deletes all occurences of the specified element from
* the expected error codes stack.
*
* @param mixed $error_code error code that should be deleted
* @return mixed list of error codes that were deleted or error
* @access public
* @since PHP 4.3.0
*/
function delExpect($error_code)
{
$deleted = false;
 
if ((is_array($error_code) && (0 != count($error_code)))) {
// $error_code is a non-empty array here;
// we walk through it trying to unset all
// values
foreach($error_code as $key => $error) {
if ($this->_checkDelExpect($error)) {
$deleted = true;
} else {
$deleted = false;
}
}
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
} elseif (!empty($error_code)) {
// $error_code comes alone, trying to unset it
if ($this->_checkDelExpect($error_code)) {
return true;
} else {
return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
}
} else {
// $error_code is empty
return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
}
}
 
// }}}
// {{{ raiseError()
 
/**
* This method is a wrapper that returns an instance of the
* configured error class with this object's default error
* handling applied. If the $mode and $options parameters are not
* specified, the object's defaults are used.
*
* @param mixed $message a text error message or a PEAR error object
*
* @param int $code a numeric error code (it is up to your class
* to define these if you want to use codes)
*
* @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
* PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
*
* @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
* specifies the PHP-internal error level (one of
* E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
* If $mode is PEAR_ERROR_CALLBACK, this
* parameter specifies the callback function or
* method. In other error modes this parameter
* is ignored.
*
* @param string $userinfo If you need to pass along for example debug
* information, this parameter is meant for that.
*
* @param string $error_class The returned error object will be
* instantiated from this class, if specified.
*
* @param bool $skipmsg If true, raiseError will only pass error codes,
* the error message parameter will be dropped.
*
* @access public
* @return object a PEAR error object
* @see PEAR::setErrorHandling
* @since PHP 4.0.5
*/
function raiseError($message = null,
$code = null,
$mode = null,
$options = null,
$userinfo = null,
$error_class = null,
$skipmsg = false)
{
// The error is yet a PEAR error object
if (is_object($message)) {
$code = $message->getCode();
$userinfo = $message->getUserInfo();
$error_class = $message->getType();
$message->error_message_prefix = '';
$message = $message->getMessage();
}
 
if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
if ($exp[0] == "*" ||
(is_int(reset($exp)) && in_array($code, $exp)) ||
(is_string(reset($exp)) && in_array($message, $exp))) {
$mode = PEAR_ERROR_RETURN;
}
}
// No mode given, try global ones
if ($mode === null) {
// Class error handler
if (isset($this) && isset($this->_default_error_mode)) {
$mode = $this->_default_error_mode;
$options = $this->_default_error_options;
// Global error handler
} elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
$mode = $GLOBALS['_PEAR_default_error_mode'];
$options = $GLOBALS['_PEAR_default_error_options'];
}
}
 
if ($error_class !== null) {
$ec = $error_class;
} elseif (isset($this) && isset($this->_error_class)) {
$ec = $this->_error_class;
} else {
$ec = 'PEAR_Error';
}
if ($skipmsg) {
return new $ec($code, $mode, $options, $userinfo);
} else {
return new $ec($message, $code, $mode, $options, $userinfo);
}
}
 
// }}}
// {{{ throwError()
 
/**
* Simpler form of raiseError with fewer options. In most cases
* message, code and userinfo are enough.
*
* @param string $message
*
*/
function throwError($message = null,
$code = null,
$userinfo = null)
{
if (isset($this) && is_a($this, 'PEAR')) {
return $this->raiseError($message, $code, null, null, $userinfo);
} else {
return PEAR::raiseError($message, $code, null, null, $userinfo);
}
}
 
// }}}
function staticPushErrorHandling($mode, $options = null)
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
$def_mode = &$GLOBALS['_PEAR_default_error_mode'];
$def_options = &$GLOBALS['_PEAR_default_error_options'];
$stack[] = array($def_mode, $def_options);
switch ($mode) {
case PEAR_ERROR_EXCEPTION:
case PEAR_ERROR_RETURN:
case PEAR_ERROR_PRINT:
case PEAR_ERROR_TRIGGER:
case PEAR_ERROR_DIE:
case null:
$def_mode = $mode;
$def_options = $options;
break;
 
case PEAR_ERROR_CALLBACK:
$def_mode = $mode;
// class/object method callback
if (is_callable($options)) {
$def_options = $options;
} else {
trigger_error("invalid error callback", E_USER_WARNING);
}
break;
 
default:
trigger_error("invalid error mode", E_USER_WARNING);
break;
}
$stack[] = array($mode, $options);
return true;
}
 
function staticPopErrorHandling()
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
$setmode = &$GLOBALS['_PEAR_default_error_mode'];
$setoptions = &$GLOBALS['_PEAR_default_error_options'];
array_pop($stack);
list($mode, $options) = $stack[sizeof($stack) - 1];
array_pop($stack);
switch ($mode) {
case PEAR_ERROR_EXCEPTION:
case PEAR_ERROR_RETURN:
case PEAR_ERROR_PRINT:
case PEAR_ERROR_TRIGGER:
case PEAR_ERROR_DIE:
case null:
$setmode = $mode;
$setoptions = $options;
break;
 
case PEAR_ERROR_CALLBACK:
$setmode = $mode;
// class/object method callback
if (is_callable($options)) {
$setoptions = $options;
} else {
trigger_error("invalid error callback", E_USER_WARNING);
}
break;
 
default:
trigger_error("invalid error mode", E_USER_WARNING);
break;
}
return true;
}
 
// {{{ pushErrorHandling()
 
/**
* Push a new error handler on top of the error handler options stack. With this
* you can easily override the actual error handler for some code and restore
* it later with popErrorHandling.
*
* @param mixed $mode (same as setErrorHandling)
* @param mixed $options (same as setErrorHandling)
*
* @return bool Always true
*
* @see PEAR::setErrorHandling
*/
function pushErrorHandling($mode, $options = null)
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
if (isset($this) && is_a($this, 'PEAR')) {
$def_mode = &$this->_default_error_mode;
$def_options = &$this->_default_error_options;
} else {
$def_mode = &$GLOBALS['_PEAR_default_error_mode'];
$def_options = &$GLOBALS['_PEAR_default_error_options'];
}
$stack[] = array($def_mode, $def_options);
 
if (isset($this) && is_a($this, 'PEAR')) {
$this->setErrorHandling($mode, $options);
} else {
PEAR::setErrorHandling($mode, $options);
}
$stack[] = array($mode, $options);
return true;
}
 
// }}}
// {{{ popErrorHandling()
 
/**
* Pop the last error handler used
*
* @return bool Always true
*
* @see PEAR::pushErrorHandling
*/
function popErrorHandling()
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
array_pop($stack);
list($mode, $options) = $stack[sizeof($stack) - 1];
array_pop($stack);
if (isset($this) && is_a($this, 'PEAR')) {
$this->setErrorHandling($mode, $options);
} else {
PEAR::setErrorHandling($mode, $options);
}
return true;
}
 
// }}}
// {{{ loadExtension()
 
/**
* OS independant PHP extension load. Remember to take care
* on the correct extension name for case sensitive OSes.
*
* @param string $ext The extension name
* @return bool Success or not on the dl() call
*/
function loadExtension($ext)
{
if (!extension_loaded($ext)) {
// if either returns true dl() will produce a FATAL error, stop that
if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
return false;
}
if (OS_WINDOWS) {
$suffix = '.dll';
} elseif (PHP_OS == 'HP-UX') {
$suffix = '.sl';
} elseif (PHP_OS == 'AIX') {
$suffix = '.a';
} elseif (PHP_OS == 'OSX') {
$suffix = '.bundle';
} else {
$suffix = '.so';
}
return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
}
return true;
}
 
// }}}
}
 
// {{{ _PEAR_call_destructors()
 
function _PEAR_call_destructors()
{
global $_PEAR_destructor_object_list;
if (is_array($_PEAR_destructor_object_list) &&
sizeof($_PEAR_destructor_object_list))
{
reset($_PEAR_destructor_object_list);
if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) {
$_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
}
while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
$classname = get_class($objref);
while ($classname) {
$destructor = "_$classname";
if (method_exists($objref, $destructor)) {
$objref->$destructor();
break;
} else {
$classname = get_parent_class($classname);
}
}
}
// Empty the object list to ensure that destructors are
// not called more than once.
$_PEAR_destructor_object_list = array();
}
 
// Now call the shutdown functions
if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
call_user_func_array($value[0], $value[1]);
}
}
}
 
// }}}
 
class PEAR_Error
{
// {{{ properties
 
var $error_message_prefix = '';
var $mode = PEAR_ERROR_RETURN;
var $level = E_USER_NOTICE;
var $code = -1;
var $message = '';
var $userinfo = '';
var $backtrace = null;
 
// }}}
// {{{ constructor
 
/**
* PEAR_Error constructor
*
* @param string $message message
*
* @param int $code (optional) error code
*
* @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
* PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
*
* @param mixed $options (optional) error level, _OR_ in the case of
* PEAR_ERROR_CALLBACK, the callback function or object/method
* tuple.
*
* @param string $userinfo (optional) additional user/debug info
*
* @access public
*
*/
function PEAR_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
if ($mode === null) {
$mode = PEAR_ERROR_RETURN;
}
$this->message = $message;
$this->code = $code;
$this->mode = $mode;
$this->userinfo = $userinfo;
if (function_exists("debug_backtrace")) {
if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
$this->backtrace = debug_backtrace();
}
}
if ($mode & PEAR_ERROR_CALLBACK) {
$this->level = E_USER_NOTICE;
$this->callback = $options;
} else {
if ($options === null) {
$options = E_USER_NOTICE;
}
$this->level = $options;
$this->callback = null;
}
if ($this->mode & PEAR_ERROR_PRINT) {
if (is_null($options) || is_int($options)) {
$format = "%s";
} else {
$format = $options;
}
printf($format, $this->getMessage());
}
if ($this->mode & PEAR_ERROR_TRIGGER) {
trigger_error($this->getMessage(), $this->level);
}
if ($this->mode & PEAR_ERROR_DIE) {
$msg = $this->getMessage();
if (is_null($options) || is_int($options)) {
$format = "%s";
if (substr($msg, -1) != "\n") {
$msg .= "\n";
}
} else {
$format = $options;
}
die(sprintf($format, $msg));
}
if ($this->mode & PEAR_ERROR_CALLBACK) {
if (is_callable($this->callback)) {
call_user_func($this->callback, $this);
}
}
if ($this->mode & PEAR_ERROR_EXCEPTION) {
trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING);
eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);');
}
}
 
// }}}
// {{{ getMode()
 
/**
* Get the error mode from an error object.
*
* @return int error mode
* @access public
*/
function getMode() {
return $this->mode;
}
 
// }}}
// {{{ getCallback()
 
/**
* Get the callback function/method from an error object.
*
* @return mixed callback function or object/method array
* @access public
*/
function getCallback() {
return $this->callback;
}
 
// }}}
// {{{ getMessage()
 
 
/**
* Get the error message from an error object.
*
* @return string full error message
* @access public
*/
function getMessage()
{
return ($this->error_message_prefix . $this->message);
}
 
 
// }}}
// {{{ getCode()
 
/**
* Get error code from an error object
*
* @return int error code
* @access public
*/
function getCode()
{
return $this->code;
}
 
// }}}
// {{{ getType()
 
/**
* Get the name of this error/exception.
*
* @return string error/exception name (type)
* @access public
*/
function getType()
{
return get_class($this);
}
 
// }}}
// {{{ getUserInfo()
 
/**
* Get additional user-supplied information.
*
* @return string user-supplied information
* @access public
*/
function getUserInfo()
{
return $this->userinfo;
}
 
// }}}
// {{{ getDebugInfo()
 
/**
* Get additional debug information supplied by the application.
*
* @return string debug information
* @access public
*/
function getDebugInfo()
{
return $this->getUserInfo();
}
 
// }}}
// {{{ getBacktrace()
 
/**
* Get the call backtrace from where the error was generated.
* Supported with PHP 4.3.0 or newer.
*
* @param int $frame (optional) what frame to fetch
* @return array Backtrace, or NULL if not available.
* @access public
*/
function getBacktrace($frame = null)
{
if ($frame === null) {
return $this->backtrace;
}
return $this->backtrace[$frame];
}
 
// }}}
// {{{ addUserInfo()
 
function addUserInfo($info)
{
if (empty($this->userinfo)) {
$this->userinfo = $info;
} else {
$this->userinfo .= " ** $info";
}
}
 
// }}}
// {{{ toString()
 
/**
* Make a string representation of this object.
*
* @return string a string with an object summary
* @access public
*/
function toString() {
$modes = array();
$levels = array(E_USER_NOTICE => 'notice',
E_USER_WARNING => 'warning',
E_USER_ERROR => 'error');
if ($this->mode & PEAR_ERROR_CALLBACK) {
if (is_array($this->callback)) {
$callback = (is_object($this->callback[0]) ?
strtolower(get_class($this->callback[0])) :
$this->callback[0]) . '::' .
$this->callback[1];
} else {
$callback = $this->callback;
}
return sprintf('[%s: message="%s" code=%d mode=callback '.
'callback=%s prefix="%s" info="%s"]',
strtolower(get_class($this)), $this->message, $this->code,
$callback, $this->error_message_prefix,
$this->userinfo);
}
if ($this->mode & PEAR_ERROR_PRINT) {
$modes[] = 'print';
}
if ($this->mode & PEAR_ERROR_TRIGGER) {
$modes[] = 'trigger';
}
if ($this->mode & PEAR_ERROR_DIE) {
$modes[] = 'die';
}
if ($this->mode & PEAR_ERROR_RETURN) {
$modes[] = 'return';
}
return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
'prefix="%s" info="%s"]',
strtolower(get_class($this)), $this->message, $this->code,
implode("|", $modes), $levels[$this->level],
$this->error_message_prefix,
$this->userinfo);
}
 
// }}}
}
 
/*
* Local Variables:
* mode: php
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_jumping_noData_test.php
New file
0,0 → 1,36
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerJumpingNoData extends UnitTestCase {
var $pager;
function TestOfPagerJumpingNoData($name='Test of Pager_Jumping - no data') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'totalItems' => 0,
'perPage' => 2,
'mode' => 'Jumping',
);
$this->pager = Pager::factory($options);
}
function tearDown() {
unset($this->pager);
}
function testOffsetByPageId() {
$this->assertEqual(array(1, 0), $this->pager->getOffsetByPageId());
}
function testPageIdByOffset() {
$this->assertEqual(false, $this->pager->getPageIdByOffset(0));
}
function testPageIdByOffset2() {
$this->assertEqual(1, $this->pager->getPageIdByOffset(1));
}
function testPageIdByOffset3() {
$this->assertEqual(1, $this->pager->getPageIdByOffset(2));
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_tests.php
New file
0,0 → 1,20
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class PagerTests extends GroupTest {
function PagerTests() {
$this->GroupTest('Pager Tests');
$this->addTestFile('pager_test.php');
$this->addTestFile('pager_noData_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new PagerTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/multibyte_post.php
New file
0,0 → 1,48
<?php
require_once 'Pager/Pager.php';
 
//create dummy array of data
$myData = array();
for ($i=0; $i<200; $i++) {
$myData[] = $i;
}
 
//set a string
$test_strings_encoded = array(
'encoded1' => '&#27979;&#35797;',
'encoded2' => '&#50504;&#45397;',
);
$test_strings_plain = array(
'plain1' => '안녕',
'plain2' => '더보기',
// 'plain3' => '이젠 전화도
//로 걸면 무료',
);
$params = array(
'itemData' => $myData,
'perPage' => 10,
'delta' => 2,
'append' => true,
'clearIfVoid' => false,
'extraVars' => array_merge($test_strings_plain, $test_strings_encoded),
'httpMethod' => 'POST',
'path' => 'http://'.$_SERVER['HTTP_HOST'].substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/')),
'fileName' => basename(__FILE__),
);
//var_dump($params['fileName']);exit;
$pager = & Pager::factory($params);
$page_data = $pager->getPageData();
?>
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Pager Test: page <?php echo $pager->getCurrentPageID(); ?></title>
</head>
<body>
<?php echo $pager->links; ?>
<hr />
<pre><?php print_r($page_data); ?></pre>
</body>
</html>
/branches/v1.0-menes/api/pear/Pager/tests/pager_noData_test.php
New file
0,0 → 1,48
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerNoData extends UnitTestCase {
var $pager;
function TestOfPagerNoData($name='Test of Pager - no data') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'totalItems' => 0,
'perPage' => 5,
'mode' => 'Sliding',
);
$this->pager = Pager::factory($options);
}
function tearDown() {
unset($this->pager);
}
function testCurrentPageID () {
$this->assertEqual(0, $this->pager->getCurrentPageID());
}
function testNextPageID () {
$this->assertEqual(false, $this->pager->getNextPageID());
}
function testPrevPageID () {
$this->assertEqual(false, $this->pager->getPreviousPageID());
}
function testNumItems () {
$this->assertEqual(0, $this->pager->numItems());
}
function testNumPages () {
$this->assertEqual(0, $this->pager->numPages());
}
function testFirstPage () {
$this->assertEqual(true, $this->pager->isFirstPage());
}
function testLastPage () {
$this->assertEqual(true, $this->pager->isLastPage());
}
function testLastPageComplete () {
$this->assertEqual(true, $this->pager->isLastPageComplete());
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_post_tests.php
New file
0,0 → 1,11
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
$test = &new GroupTest('Pager POST tests');
$test->addTestFile('pager_post_test.php');
exit ($test->run(new HTMLReporter()) ? 0 : 1);
 
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_jumping_test.php
New file
0,0 → 1,83
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerJumping extends UnitTestCase {
var $pager;
function TestOfPagerJumping($name='Test of Pager_Jumping') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
'perPage' => 5,
'mode' => 'Jumping',
'delta' => 2
);
$this->pager = Pager::factory($options);
}
function tearDown() {
unset($this->pager);
}
function testPageIdByOffset1() {
$this->assertEqual(1, $this->pager->getPageIdByOffset(1));
}
function testPageIdByOffset5() {
$this->assertEqual(1, $this->pager->getPageIdByOffset(5));
}
function testPageIdByOffset6() {
$this->assertEqual(2, $this->pager->getPageIdByOffset(6));
}
function testPageRangeByPageId1() {
$this->assertEqual(array(1, 2), $this->pager->getPageRangeByPageId(1));
}
function testPageRangeByPageId2() {
$this->assertEqual(array(1, 2), $this->pager->getPageRangeByPageId(2));
}
function testPageRangeByPageId3() {
$this->assertEqual(array(3, 3), $this->pager->getPageRangeByPageId(3));
}
function testPageRangeByPageId_outOfRange() {
$this->assertEqual(array(0, 0), $this->pager->getPageRangeByPageId(20));
}
function testGetPageData() {
$this->assertEqual(array(0=>1, 1=>2, 2=>3, 3=>4, 4=>5), $this->pager->getPageData());
}
function testGetPageData2() {
$this->assertEqual(array(5=>6, 6=>7, 7=>8, 8=>9, 9=>10), $this->pager->getPageData(2));
}
function testGetPageData_OutOfRange() {
$this->assertEqual(false, $this->pager->getPageData(4));
}
/**
* Returns offsets for given pageID. Eg, if you pass pageID=5 and your
* delta is 2, it will return 3 and 7. A pageID of 6 would give you 4 and 8
* If the method is called without parameter, pageID is set to currentPage#.
*
* Given a PageId, it returns the limits of the range of pages displayed.
* While getOffsetByPageId() returns the offset of the data within the current
* page, this method returns the offsets of the page numbers interval.
* E.g., if you have perPage=10 and pageId=3, it will return you 1 and 10.
* PageID of 8 would give you 1 and 10 as well, because 1 <= 8 <= 10.
* PageID of 11 would give you 11 and 20.
*
* @param pageID PageID to get offsets for
* @return array First and last offsets
* @access public
*/
/**
* Given a PageId, it returns the limits of the range of pages displayed.
* While getOffsetByPageId() returns the offset of the data within the
* current page, this method returns the offsets of the page numbers interval.
* E.g., if you have perPage=10 and pageId=3, it will return you 1 and 10.
* PageID of 8 would give you 1 and 10 as well, because 1 <= 8 <= 10.
* PageID of 11 would give you 11 and 20.
*
* @param pageID PageID to get offsets for
* @return array First and last offsets
* @access public
*/
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_sliding_tests.php
New file
0,0 → 1,21
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class PagerSlidingTests extends GroupTest {
function PagerSlidingTests() {
$this->GroupTest('Pager_Sliding Tests');
$this->addTestFile('pager_sliding_test.php');
$this->addTestFile('pager_sliding_notExpanded_test.php');
$this->addTestFile('pager_sliding_noData_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new PagerTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/all_tests.php
New file
0,0 → 1,25
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
define('TEST_RUNNING', true);
 
require_once './pager_tests.php';
require_once './pager_jumping_tests.php';
require_once './pager_sliding_tests.php';
 
 
class AllTests extends GroupTest {
function AllTests() {
$this->GroupTest('All PEAR::Pager Tests');
$this->AddTestCase(new PagerTests());
$this->AddTestCase(new PagerJumpingTests());
$this->AddTestCase(new PagerSlidingTests());
}
}
 
$test = &new AllTests();
$test->run(new HtmlReporter());
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_test_xss.php
New file
0,0 → 1,43
<?php
// $Id$
 
//override url
$_SERVER['PHP_SELF'] = '">test';
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerXSS extends UnitTestCase {
var $pager;
var $baseurl;
function TestOfPagerXSS($name='Test of Pager - XSS attacks') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
);
$this->pager = Pager::factory($options);
$this->baseurl = substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
}
function tearDown() {
unset($this->pager);
}
function testXSS() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'nextImg' => '&raquo;'
);
$this->pager = Pager::factory($options);
$expected = '&nbsp;<a href="./&quot;&gt;test?pageID=2" title="next page">&raquo;</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_getNextLink());
}
}
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfPagerXSS();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/simple_include.php
New file
0,0 → 1,17
<?php
// $Id$
//
// This testsuite requires SimpleTest.
// You can find it here:
// http://www.lastcraft.com/simple_test.php
//
if (!defined('SIMPLE_TEST')) {
define('SIMPLE_TEST', '../simpletest/');
}
 
require_once(SIMPLE_TEST . 'unit_tester.php');
require_once(SIMPLE_TEST . 'reporter.php');
require_once(SIMPLE_TEST . 'mock_objects.php');
require_once(SIMPLE_TEST . 'web_tester.php');
require_once(SIMPLE_TEST . 'reporter.php');
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_sliding_noData_test.php
New file
0,0 → 1,30
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerSlidingNoData extends UnitTestCase {
var $pager;
function TestOfPagerSlidingNoData($name='Test of Pager_Sliding - no data') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'totalItems' => 0,
'perPage' => 2,
'mode' => 'Sliding',
);
$this->pager = Pager::factory($options);
}
function tearDown() {
unset($this->pager);
}
function testOffsetByPageId() {
$this->assertEqual(array(1, 0), $this->pager->getOffsetByPageId());
}
function testPageIdByOffset() {
$this->assertNull($this->pager->getPageIdByOffset());
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_wrapper_test.php
New file
0,0 → 1,205
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_wrapper_include.php';
 
class TestOfPagerWrapper extends UnitTestCase
{
function TestOfPagerWrapper($name='Test of Pager_Wrapper') {
$this->UnitTestCase($name);
}
function setUp() { }
function tearDown() { }
 
/**
* Basic tests for rewriteCountQuery()
*/
function testRewriteCountQuery() {
//test LIMIT
$query = 'SELECT a, b, c, d FROM mytable WHERE a=1 AND c="g" LIMIT 2';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
//test ORDER BY and quotes
$query = 'SELECT a, b, c, d FROM mytable WHERE a=1 AND c="g" ORDER BY (a, b)';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
//test CR/LF
$query = 'SELECT a, b, c, d FROM mytable
WHERE a=1
AND c="g"
ORDER BY (a, b)';
$expected = 'SELECT COUNT(*) FROM mytable
WHERE a=1
AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
//test GROUP BY
$query = 'SELECT a, b, c, d FROM mytable WHERE a=1 GROUP BY c';
$this->assertFalse(rewriteCountQuery($query));
 
//test DISTINCT
$query = 'SELECT DISTINCT a, b, c, d FROM mytable WHERE a=1 GROUP BY c';
$this->assertFalse(rewriteCountQuery($query));
 
//test MiXeD Keyword CaSe
$query = 'SELECT a, b, c, d from mytable WHERE a=1 AND c="g"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
//test function speed... this query used to be very slow to parse
$query = "SELECT i.item_id,
ia.addition,
u.username,
i.date_created,
i.start_date,
i.expiry_date
FROM item i, item_addition ia, item_type it, item_type_mapping itm, usr u, category c
WHERE ia.item_type_mapping_id = itm.item_type_mapping_id
AND i.updated_by_id = u.usr_id
AND it.item_type_id = itm.item_type_id
AND i.item_id = ia.item_id
AND i.item_type_id = it.item_type_id
AND itm.field_name = 'title' AND it.item_type_id = 2 AND i.category_id = 1 AND i.status = 4
AND i.category_id = c.category_id
AND 0 NOT IN (COALESCE(c.perms, '-1'))
ORDER BY i.last_updated DESC";
$expected = "SELECT COUNT(*) FROM item i, item_addition ia, item_type it, item_type_mapping itm, usr u, category c
WHERE ia.item_type_mapping_id = itm.item_type_mapping_id
AND i.updated_by_id = u.usr_id
AND it.item_type_id = itm.item_type_id
AND i.item_id = ia.item_id
AND i.item_type_id = it.item_type_id
AND itm.field_name = 'title' AND it.item_type_id = 2 AND i.category_id = 1 AND i.status = 4
AND i.category_id = c.category_id
AND 0 NOT IN (COALESCE(c.perms, '-1'))";
$this->assertEqual($expected, rewriteCountQuery($query));
}
/**
* Test rewriteCountQuery() with queries having a subquery in the SELECT clause
*/
function testRewriteCountQuery_SubqueriesInSelectClause() {
$query = 'SELECT a, (SELECT a FROM b) AS b, c, d FROM mytable WHERE a=1 AND c="g" LIMIT 2';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertFalse(rewriteCountQuery($query));
 
$query = 'SELECT a, (SELECT a FROM b) AS b, (SELECT c FROM c) AS c, d FROM mytable WHERE a=1 AND c="g" LIMIT 2';
//$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertFalse(rewriteCountQuery($query));
 
$query = 'SELECT `id`, `ip`, (
SELECT TIMEDIFF(MAX(P.`time`), MIN(P.`time`))
FROM `przejscia` as P
WHERE P.`id_wejscia`=W.`id`
) as `czas`
FROM `wejscia` as W
WHERE W.id_domeny=?
ORDER BY W.czas_wejscia DESC';
$expected = 'SELECT COUNT(*)
FROM `wejscia` as W
WHERE W.id_domeny=?
ORDER BY W.czas_wejscia DESC';
$this->assertFalse(rewriteCountQuery($query));
}
/**
* Test rewriteCountQuery() with queries having a subquery in the FROM clause
*/
function testRewriteCountQuery_SubqueriesInFromClause() {
$query = 'SELECT a, b, c, d FROM (SELECT a, b, c, d FROM mytable WHERE a=1) AS tbl_alias WHERE a=1';
$expected = 'SELECT COUNT(*) FROM (SELECT a, b, c, d FROM mytable WHERE a=1) AS tbl_alias WHERE a=1';
$this->assertEqual($expected, rewriteCountQuery($query));
}
/**
* Test rewriteCountQuery() with queries having a subquery in the WHERE clause
*/
function testRewriteCountQuery_SubqueriesInWhereClause() {
//this one is not rewritten: subqueries with ORDER BY clauses might get truncated
$query = 'SELECT Version.VersionId, Version.Identifier,News.*
FROM VersionBroker
JOIN ObjectType ON ObjectType.ObjectTypeId = VersionBroker.ObjectTypeId
JOIN Version ON VersionBroker.Identifier = Version.Identifier
JOIN News ON Version.ObjectId = News.NewsId
WHERE Version.Status = \'Approved\'
AND ObjectType.Name = \'News\'
AND Version.ApprovedTS = (
SELECT SubV.ApprovedTS
FROM Version SubV
WHERE SubV.Identifier = VersionBroker.Identifier
ORDER BY ApprovedTS DESC
LIMIT 1)
ORDER BY ApprovedTS DESC';
 
$expected = 'SELECT COUNT(*)
FROM VersionBroker
JOIN ObjectType ON ObjectType.ObjectTypeId = VersionBroker.ObjectTypeId
JOIN Version ON VersionBroker.Identifier = Version.Identifier
JOIN News ON Version.ObjectId = News.NewsId
WHERE Version.Status = \'Approved\'
AND ObjectType.Name = \'News\'
AND Version.ApprovedTS = (
SELECT SubV.ApprovedTS
FROM Version SubV
WHERE SubV.Identifier = VersionBroker.Identifier
ORDER BY ApprovedTS DESC
LIMIT 1)
ORDER BY ApprovedTS DESC';
//$this->assertEqual($expected, rewriteCountQuery($query));
$this->assertFalse(rewriteCountQuery($query));
//this one should pass... subquery without ORDER BY or LIMIT clause
$query = 'SELECT Version.VersionId, Version.Identifier,News.* FROM VersionBroker JOIN
ObjectType ON ObjectType.ObjectTypeId = VersionBroker.ObjectTypeId JOIN
Version ON VersionBroker.Identifier = Version.Identifier JOIN News ON
Version.ObjectId = News.NewsId WHERE Version.Status = \'Approved\' AND
ObjectType.Name = \'News\' AND Version.ApprovedTS = ( SELECT SubV.ApprovedTS
FROM Version SubV WHERE SubV.Identifier = VersionBroker.Identifier ) ORDER BY ApprovedTS DESC';
 
$expected = 'SELECT COUNT(*) FROM VersionBroker JOIN
ObjectType ON ObjectType.ObjectTypeId = VersionBroker.ObjectTypeId JOIN
Version ON VersionBroker.Identifier = Version.Identifier JOIN News ON
Version.ObjectId = News.NewsId WHERE Version.Status = \'Approved\' AND
ObjectType.Name = \'News\' AND Version.ApprovedTS = ( SELECT SubV.ApprovedTS
FROM Version SubV WHERE SubV.Identifier = VersionBroker.Identifier )';
$this->assertEqual($expected, rewriteCountQuery($query));
}
 
/**
* Test rewriteCountQuery() with queries having keywords embedded in other words
*/
function testRewriteCountQuery_EmbeddedKeywords() {
$query = 'SELECT afieldFROM, b, c, d FROM mytable WHERE a=1 AND c="g"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
$query = 'SELECT FROMafield, b, c, d FROM mytable WHERE a=1 AND c="g"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
$query = 'SELECT afieldFROMaaa, b, c, d FROM mytable WHERE a=1 AND c="gLIMIT"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="gLIMIT"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
$query = 'SELECT DISTINCTaaa, b, c, d FROM mytable WHERE a=1 AND c="g"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g"';
$this->assertEqual($expected, rewriteCountQuery($query));
 
//this one fails... the regexp should NOT match keywords within quotes.
//we need a full blown stack-based parser to catch this...
$query = 'SELECT afieldFROMaaa, b, c, d FROM mytable WHERE a=1 AND c="g LIMIT a"';
$expected = 'SELECT COUNT(*) FROM mytable WHERE a=1 AND c="g LIMIT a"';
$this->assertEqual($expected, rewriteCountQuery($query));
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new TestOfPagerWrapper();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_test.php
New file
0,0 → 1,553
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPager extends UnitTestCase {
var $pager;
var $baseurl;
function TestOfPager($name='Test of Pager') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
);
$this->pager = Pager::factory($options);
$this->baseurl = substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
}
function tearDown() {
unset($this->pager);
}
function testCurrentPageID () {
$this->assertEqual(1, $this->pager->getCurrentPageID());
}
function testNextPageID () {
$this->assertEqual(2, $this->pager->getNextPageID());
}
function testPrevPageID () {
$this->assertEqual(false, $this->pager->getPreviousPageID());
}
function testNumItems () {
$this->assertEqual(10, $this->pager->numItems());
}
function testNumPages () {
$this->assertEqual(2, $this->pager->numPages());
}
function testFirstPage () {
$this->assertEqual(true, $this->pager->isFirstPage());
}
function testLastPage () {
$this->assertEqual(false, $this->pager->isLastPage());
}
function testLastPageComplete () {
$this->assertEqual(true, $this->pager->isLastPageComplete());
}
function testOffsetByPageId() {
$this->assertEqual(array(1, 5), $this->pager->getOffsetByPageId(1));
$this->assertEqual(array(6, 10), $this->pager->getOffsetByPageId(2));
}
function testOffsetByPageId_outOfRange() {
$this->assertEqual(array(0, 0), $this->pager->getOffsetByPageId(20));
}
function testGetPageData() {
$this->assertEqual(array(0=>1, 1=>2, 2=>3, 3=>4, 4=>5), $this->pager->getPageData());
$this->assertEqual(array(5=>6, 6=>7, 7=>8, 8=>9, 9=>10), $this->pager->getPageData(2));
}
function testGetPageData_OutOfRange() {
$this->assertEqual(array(), $this->pager->getPageData(3));
}
function testSelectBox() {
$selectBox = '<select name="'.$this->pager->_sessionVar.'">';
$selectBox .= '<option value="5" selected="selected">5</option>';
$selectBox .= '<option value="10">10</option>';
$selectBox .= '<option value="15">15</option>';
$selectBox .= '</select>';
$this->assertEqual($selectBox, $this->pager->getPerPageSelectBox(5, 15, 5));
}
function testSelectBoxWithString() {
$selectBox = '<select name="'.$this->pager->_sessionVar.'">';
$selectBox .= '<option value="5" selected="selected">5 bugs</option>';
$selectBox .= '<option value="10">10 bugs</option>';
$selectBox .= '<option value="15">15 bugs</option>';
$selectBox .= '</select>';
$this->assertEqual($selectBox, $this->pager->getPerPageSelectBox(5, 15, 5, false, '%d bugs'));
}
function testSelectBoxWithShowAll() {
$selectBox = '<select name="'.$this->pager->_sessionVar.'">';
$selectBox .= '<option value="3">3</option>';
$selectBox .= '<option value="4">4</option>';
$selectBox .= '<option value="5" selected="selected">5</option>';
$selectBox .= '<option value="6">6</option>';
$selectBox .= '<option value="10">10</option>';
$selectBox .= '</select>';
$this->assertEqual($selectBox, $this->pager->getPerPageSelectBox(3, 6, 1, true));
}
function testSelectBoxWithShowAllAndText() {
$this->pager->_showAllText = 'Show All';
$selectBox = '<select name="'.$this->pager->_sessionVar.'">';
$selectBox .= '<option value="3">3 bugs</option>';
$selectBox .= '<option value="4">4 bugs</option>';
$selectBox .= '<option value="5" selected="selected">5 bugs</option>';
$selectBox .= '<option value="6">6 bugs</option>';
$selectBox .= '<option value="10">Show All</option>';
$selectBox .= '</select>';
$this->assertEqual($selectBox, $this->pager->getPerPageSelectBox(3, 6, 1, true, '%d bugs'));
}
function testSelectBoxWithShowAllWithExtraAttribs() {
$this->pager->_showAllText = 'Show All';
$selectBox = '<select name="'.$this->pager->_sessionVar.'" onmouseover="doSth">';
$selectBox .= '<option value="3">3 bugs</option>';
$selectBox .= '<option value="4">4 bugs</option>';
$selectBox .= '<option value="5" selected="selected">5 bugs</option>';
$selectBox .= '<option value="6">6 bugs</option>';
$selectBox .= '<option value="10">Show All</option>';
$selectBox .= '</select>';
$params = array('optionText' => '%d bugs', 'attributes' => 'onmouseover="doSth"');
$this->assertEqual($selectBox, $this->pager->getPerPageSelectBox(3, 6, 1, true, $params));
}
function testSelectBoxInvalid() {
$err = $this->pager->getPerPageSelectBox(5, 15, 5, false, '%s bugs');
$this->assertEqual(ERROR_PAGER_INVALID_PLACEHOLDER, $err->getCode());
}
function testAppendInvalid() {
$options = array(
'totalItems' => 10,
'append' => false,
'fileName' => 'invalidFileName'
);
$err =& Pager::factory($options); //ERROR_PAGER_INVALID_USAGE
$this->assertError();
}
function testAppendValid() {
$options = array(
'totalItems' => 10,
'append' => false,
'fileName' => 'valid_%d_FileName'
);
$err =& Pager::factory($options);
$this->assertNoErrors();
}
function testEscapeEntities() {
//encode special chars
$options = array(
'extraVars' => array(
'request' => array('aRequest'),
'escape' => 'äö%<>+',
),
'perPage' => 5,
);
$this->pager =& Pager::factory($options);
//$expected = '?request[]=aRequest&amp;escape=&auml;&ouml;%&lt;&gt;+&amp;pageID=';
//$this->assertEqual($expected, $this->pager->_getLinksUrl());
 
$expected = 'request%5B0%5D=aRequest&amp;escape=%E4%F6%25%3C%3E%2B';
$rendered = $this->pager->_renderLink('', '');
preg_match('/href="(.*)"/U', $rendered, $matches);
$actual = str_replace($_SERVER['PHP_SELF'].'?', '', $matches[1]);
$this->assertEqual($expected, $actual);
 
//don't encode slashes
$options = array(
'extraVars' => array(
'request' => 'cat/subcat',
),
'perPage' => 5,
);
$this->pager =& Pager::factory($options);
//$expected = '?request=cat/subcat&amp;pageID=';
//$this->assertEqual($expected, $this->pager->_getLinksUrl());
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?request=cat/subcat" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
}
function testMultibyteStrings() {
$options = array(
'extraVars' => array(
'test' => '&#27979;&#35797;',
),
'perPage' => 5,
);
$this->pager =& Pager::factory($options);
//$expected = '<a href="'.$_SERVER['PHP_SELF'].'?test=&#27979;&#35797;" title=""></a>';
$rendered = $this->pager->_renderLink('', '');
preg_match('/href="(.*)"/U', $rendered, $matches);
$actual = str_replace($_SERVER['PHP_SELF'].'?test=', '', $matches[1]);
$this->assertEqual(urlencode($options['extraVars']['test']), $actual);
}
function testCurrentPage() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 2,
'currentPage' => 2,
);
$this->pager =& Pager::factory($options);
$this->assertEqual(3, $this->pager->getNextPageID());
$this->assertEqual(1, $this->pager->getPreviousPageID());
$this->assertEqual(2, $this->pager->_currentPage);
}
function testArrayExtraVars() {
$arr = array(
'apple',
'orange',
);
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'extraVars' => array('arr' => $arr, 'no' => 'test'),
);
$this->pager =& Pager::factory($options);
/*
//old
$expected = '?arr[0]=apple&amp;arr[1]=orange&amp;pageID=';
$this->assertEqual($expected, $this->pager->_getLinksUrl());
*/
$expected = $options['extraVars'];
$this->assertEqual($expected, $this->pager->_getLinksData());
 
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?arr%5B0%5D=apple&amp;arr%5B1%5D=orange&amp;no=test&amp;pageID=2" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
}
function testExcludeVars() {
$arr = array(
'apple',
'orange',
);
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'extraVars' => array('arr' => $arr, 'no' => 'test'),
'excludeVars' => array('no'),
);
$this->pager =& Pager::factory($options);
$expected = array(
'arr' => array(
0 => 'apple',
1 => 'orange'
),
);
$actual = $this->pager->_getLinksData();
$this->assertEqual($expected, $this->pager->_getLinksData());
 
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?arr%5B0%5D=apple&amp;arr%5B1%5D=orange&amp;pageID=2" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
}
function testArgSeparator() {
$bkp_arg_separator = ini_get('arg_separator.output');
ini_set('arg_separator.output', '&amp;');
 
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'extraVars' => array('apple' => 1),
);
$this->pager =& Pager::factory($options);
 
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?apple=1&amp;pageID=2" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
 
ini_set('arg_separator.output', $bkp_arg_separator);
}
function testAttributes() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'linkClass' => 'testclass',
'attributes' => 'target="_blank"',
);
$this->pager =& Pager::factory($options);
 
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?pageID=2" class="testclass" target="_blank" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
}
function testImportQuery() {
//add some fake url vars
$_GET['arr'] = array(
'apple',
'orange',
);
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'importQuery' => false,
);
$this->pager =& Pager::factory($options);
$expected = array();
$actual = $this->pager->_getLinksData();
$this->assertEqual($expected, $this->pager->_getLinksData());
 
$expected = '<a href="'.$_SERVER['PHP_SELF'].'?pageID=2" title=""></a>';
$actual = $this->pager->_renderLink('', '');
$this->assertEqual($expected, $actual);
//remove fake url vars
unset($_GET['arr']);
}
function testGetNextLinkTag() {
//append = true
$expected = '<link rel="next" href="'.$_SERVER['PHP_SELF'].'?pageID=2" title="next page" />'."\n";
$this->assertEqual($expected, $this->pager->_getNextLinkTag());
//append = false
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 1,
'append' => false,
'fileName' => 'myfile.%d.php',
);
$this->pager = Pager::factory($options);
$expected = '<link rel="next" href="'.$this->baseurl.'/myfile.2.php" title="next page" />'."\n";
$this->assertEqual($expected, $this->pager->_getNextLinkTag());
//test empty tag
$options['currentPage'] = 2;
$this->pager = Pager::factory($options);
$this->assertEqual('', $this->pager->_getNextLinkTag());
}
function testGetLastLinkTag() {
//append = true
$expected = '<link rel="last" href="'.$_SERVER['PHP_SELF'].'?pageID=2" title="last page" />'."\n";
$this->assertEqual($expected, $this->pager->_getLastLinkTag());
 
//append = false
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 1,
'append' => false,
'fileName' => 'myfile.%d.php',
);
$this->pager = Pager::factory($options);
$expected = '<link rel="last" href="'.$this->baseurl.'/myfile.2.php" title="last page" />'."\n";
$this->assertEqual($expected, $this->pager->_getLastLinkTag());
 
//test empty tag
$options['currentPage'] = 2;
$this->pager = Pager::factory($options);
$this->assertEqual('', $this->pager->_getLastLinkTag());
}
function testGetFirstLinkTag() {
//append = true
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
);
$this->pager = Pager::factory($options);
$expected = '<link rel="first" href="'.$_SERVER['PHP_SELF'].'?pageID=1" title="first page" />'."\n";
$this->assertEqual($expected, $this->pager->_getFirstLinkTag());
 
//append = false
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
'append' => false,
'fileName' => 'myfile.%d.php',
);
$this->pager = Pager::factory($options);
$expected = '<link rel="first" href="'.$this->baseurl.'/myfile.1.php" title="first page" />'."\n";
$this->assertEqual($expected, $this->pager->_getFirstLinkTag());
 
//test empty tag
$options['currentPage'] = 1;
$this->pager = Pager::factory($options);
$this->assertEqual('', $this->pager->_getFirstLinkTag());
}
function testGetPrevLinkTag() {
//append = true
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
);
$this->pager = Pager::factory($options);
$expected = '<link rel="previous" href="'.$_SERVER['PHP_SELF'].'?pageID=1" title="previous page" />'."\n";
$this->assertEqual($expected, $this->pager->_getPrevLinkTag());
 
//append = false
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
'append' => false,
'fileName' => 'myfile.%d.php',
);
$this->pager = Pager::factory($options);
$expected = '<link rel="previous" href="'.$this->baseurl.'/myfile.1.php" title="previous page" />'."\n";
$this->assertEqual($expected, $this->pager->_getPrevLinkTag());
 
//test empty tag
$options['currentPage'] = 1;
$this->pager = Pager::factory($options);
$this->assertEqual('', $this->pager->_getPrevLinkTag());
}
function testPrintFirstPage() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
);
$this->pager = Pager::factory($options);
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=1" title="first page">[1]</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_printFirstPage());
 
$this->pager->_firstPageText = 'FIRST';
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=1" title="first page">[FIRST]</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_printFirstPage());
 
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
'altFirst' => 'page %d',
);
$this->pager = Pager::factory($options);
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=1" title="page 1">[1]</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_printFirstPage());
}
function testPrintLastPage() {
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=2" title="last page">[2]</a>';
$this->assertEqual($expected, $this->pager->_printLastPage());
 
$this->pager->_lastPageText = 'LAST';
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=2" title="last page">[LAST]</a>';
$this->assertEqual($expected, $this->pager->_printLastPage());
 
$this->pager->_altLast = 'page %d';
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=2" title="page 2">[LAST]</a>';
$this->assertEqual($expected, $this->pager->_printLastPage());
}
function testGetBackLink() {
$img = '&laquo;';
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 2,
'prevImg' => $img,
);
$this->pager = Pager::factory($options);
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=1" title="previous page">'.$img.'</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_getBackLink());
}
function testGetNexLink() {
$img = '&raquo;';
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'currentPage' => 1,
'nextImg' => $img,
);
$this->pager = Pager::factory($options);
$expected = '&nbsp;<a href="' . $_SERVER['PHP_SELF'] . '?pageID=2" title="next page">'.$img.'</a>&nbsp;';
$this->assertEqual($expected, $this->pager->_getNextLink());
}
function testHttpMethodAutoDetect() {
$_POST['pageID'] = 3;
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
);
$this->pager = Pager::factory($options);
$this->assertEqual('POST', $this->pager->_httpMethod);
 
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'httpMethod' => 'GET',
);
$this->pager = Pager::factory($options);
$this->assertEqual('GET', $this->pager->_httpMethod);
 
unset($_POST['pageID']);
 
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'httpMethod' => 'POST',
);
$this->pager = Pager::factory($options);
$this->assertEqual('POST', $this->pager->_httpMethod);
 
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
);
$this->pager = Pager::factory($options);
$this->assertEqual('GET', $this->pager->_httpMethod);
}
function testAccesskey() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 5,
'accesskey' => true,
);
$this->pager = Pager::factory($options);
$this->assertWantedPattern('/accesskey="\d"/i', $this->pager->links);
//var_dump($this->pager->links);
}
function testIsEncoded() {
//var_dump(urlencode('&#50504;&#45397;'));
$test_strings_encoded = array(
'encoded0' => '&#35797;',
'encoded1' => '&#27979;&#35797;',
'encoded2' => '&#50504;&#45397;',
'encoded3' => '&#50504; &#45397;',
'encoded4' => '&#50504;
&#45397;',
);
$test_strings_plain = array(
'plain1' => '안녕',
'plain2' => '더보기',
// 'plain3' => '이젠 전화도
//로 걸면 무료',
'plain4' => 'abcde', //not multibyte
'plain5' => '&#abcfg;', //invalid hex-encoded char
'plain5' => '&#50504; nasty &#45397;', //mixed plain/encoded text
);
foreach ($test_strings_encoded as $string) {
//echo '<hr />'.str_replace('&', '&amp;', $string);
$this->assertTrue($this->pager->_isEncoded($string));
}
foreach ($test_strings_plain as $string) {
$this->assertFalse($this->pager->_isEncoded($string));
}
}
function testGetOption() {
$this->assertEqual(5, $this->pager->getOption('perPage'));
$err = $this->pager->getOption('non_existent_option');
$this->assertEqual(ERROR_PAGER_INVALID, $err->getCode());
}
function testGetOptions() {
$options = $this->pager->getOptions();
$this->assertTrue(is_array($options));
$this->assertEqual(5, $options['perPage']);
}
function testSetOptionsAndBuild() {
$options = array(
'perPage' => 2,
);
$this->pager->setOptions($options);
$this->pager->build();
$this->assertEqual(2, $this->pager->getOption('perPage'));
$this->assertEqual(array(0=>1, 1=>2), $this->pager->getPageData());
$this->assertEqual(array(2=>3, 3=>4), $this->pager->getPageData(2));
 
$options = array(
'currentPage' => 2,
'append' => false,
'fileName' => 'myfile.%d.php',
);
$this->pager->setOptions($options);
$this->pager->build();
$expected = '<link rel="previous" href="'.$this->baseurl.'/myfile.1.php" title="previous page" />'."\n";
$this->assertEqual($expected, $this->pager->_getPrevLinkTag());
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_sliding_notExpanded_test.php
New file
0,0 → 1,49
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerSlidingNotExpanded extends UnitTestCase {
var $pager;
function TestOfPagerSlidingNotExpanded($name='Test of Pager_Sliding - expanded=false') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21),
'perPage' => 2,
'mode' => 'Sliding',
'expanded' => false
);
$this->pager = new Pager($options);
}
function tearDown() {
unset($this->pager);
}
function testPageRangeByPageId1() {
$this->assertEqual(array(1, 3), $this->pager->getPageRangeByPageId(1));
}
function testPageRangeByPageId2() {
$this->assertEqual(array(1, 4), $this->pager->getPageRangeByPageId(2));
}
function testPageRangeByPageId3() {
$this->assertEqual(array(1, 5), $this->pager->getPageRangeByPageId(3));
}
function testPageRangeByPageId4() {
$this->assertEqual(array(2, 6), $this->pager->getPageRangeByPageId(4));
}
function testPageRangeByPageId9() {
$this->assertEqual(array(7, 11), $this->pager->getPageRangeByPageId(9));
}
function testPageRangeByPageId10() {
$this->assertEqual(array(8, 11), $this->pager->getPageRangeByPageId(10));
}
function testPageRangeByPageId11() {
$this->assertEqual(array(9, 11), $this->pager->getPageRangeByPageId(11));
}
function testPageRangeByPageId_outOfRange() {
$this->assertEqual(array(0, 0), $this->pager->getPageRangeByPageId(20));
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_include.php
New file
0,0 → 1,4
<?php
// $Id$
require_once 'Pager/Pager.php';
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_wrapper_include.php
New file
0,0 → 1,5
<?php
// $Id$
require_once 'Pager/Pager.php';
require_once 'Pager/Wrapper.php';
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_post_test.php
New file
0,0 → 1,67
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerPOST extends WebTestCase {
var $pager;
var $baseurl;
var $options = array();
 
function TestOfPagerPOST($name='Test of Pager with httpMethod="POST"') {
$this->WebTestCase($name);
}
function setUp() {
$this->options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
'perPage' => 1,
'clearIfVoid' => false,
'httpMethod' => 'POST',
);
//$this->pager = Pager::factory($this->options);
$this->baseurl = 'http://'.$_SERVER['HTTP_HOST'].substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
}
function tearDown() {
unset($this->pager);
}
 
function testMultibyteEncoded() {
$test_strings_encoded = array(
'encoded1' => '&#27979;&#35797;',
'encoded2' => '&#50504;&#45397;',
);
$loaded = $this->get($this->baseurl.'/multibyte_post.php');
$this->assertTrue($loaded);
$this->assertResponse(200);
$this->assertTitle('Pager Test: page 1');
$this->assertNoLink('1');
$this->assertLink('2');
$this->assertLink('Next >>');
//$this->showSource();
foreach ($test_strings_encoded as $name => $value) {
$this->assertWantedPattern('/'.$name.'.*'.preg_quote(str_replace('&', '&amp;', $value)).'/Uims');
}
}
 
function testMultibytePlain() {
$test_strings_plain = array(
'plain1' => '안녕',
'plain2' => '더보기',
// 'plain3' => '이젠 전화도
//로 걸면 무료',
);
$loaded = $this->get($this->baseurl.'/multibyte_post.php');
$this->assertTrue($loaded);
$this->assertResponse(200);
$this->assertTitle('Pager Test: page 1');
$this->assertNoLink('1');
$this->assertLink('2');
$this->assertLink('Next >>');
//$this->showSource();
foreach ($test_strings_plain as $name => $value) {
$this->assertWantedPattern('/'.$name.'.*'.preg_quote(urlencode($value)).'/Uims');
}
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/pager_sliding_test.php
New file
0,0 → 1,56
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class TestOfPagerSliding extends UnitTestCase {
var $pager;
function TestOfPagerSliding($name='Test of Pager_Sliding') {
$this->UnitTestCase($name);
}
function setUp() {
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
'perPage' => 2,
'mode' => 'Sliding',
);
$this->pager = Pager::factory($options);
}
function tearDown() {
unset($this->pager);
}
function testPageRangeByPageId1() {
$this->assertEqual(array(1, 5), $this->pager->getPageRangeByPageId(1));
}
function testPageRangeByPageId4() {
$this->assertEqual(array(2, 6), $this->pager->getPageRangeByPageId(4));
}
function testPageRangeByPageId_outOfRange() {
$this->assertEqual(array(0, 0), $this->pager->getPageRangeByPageId(20));
}
function testPageRangeByPageId2() {
$this->assertEqual(array(2, 6), $this->pager->getPageRangeByPageId(4));
}
function testGetPageData() {
$this->assertEqual(array(0=>1, 1=>2), $this->pager->getPageData());
}
function testGetPageData2() {
$this->assertEqual(array(2=>3, 3=>4), $this->pager->getPageData(2));
}
function testGetPageData_OutOfRange() {
$this->assertEqual(false, $this->pager->getPageData(20));
}
function testClearIfVoid() {
$this->assertTrue(strlen($this->pager->links) > 0);
$options = array(
'itemData' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
'perPage' => 20,
'mode' => 'Sliding',
);
$this->pager = Pager::factory($options);
$this->assertEqual('', $this->pager->links);
}
}
?>
/branches/v1.0-menes/api/pear/Pager/tests/README
New file
0,0 → 1,5
These tests require Simple Test: http://www.lastcraft.com/simple_test.php
 
- edit the simple_include.php script and set your SimpleTest install dir;
- edit the pager_include.php and pager_wrapper_include.php scripts to set
your Pager directory.
/branches/v1.0-menes/api/pear/Pager/tests/pager_jumping_tests.php
New file
0,0 → 1,20
<?php
// $Id$
 
require_once 'simple_include.php';
require_once 'pager_include.php';
 
class PagerJumpingTests extends GroupTest {
function PagerJumpingTests() {
$this->GroupTest('Pager_Jumping Tests');
$this->addTestFile('pager_jumping_test.php');
$this->addTestFile('pager_jumping_noData_test.php');
}
}
 
if (!defined('TEST_RUNNING')) {
define('TEST_RUNNING', true);
$test = &new PagerTests();
$test->run(new HtmlReporter());
}
?>
/branches/v1.0-menes/api/pear/Pager/Pager.php
New file
0,0 → 1,193
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the Pager class
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 FREEBSD PROJECT 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 HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>
* @copyright 2003-2006 Lorenzo Alberton, Richard Heyes
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Pager
*/
 
/**
* Pager - Wrapper class for [Sliding|Jumping]-window Pager
* Usage examples can be found in the PEAR manual
*
* @category HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>,
* @copyright 2003-2005 Lorenzo Alberton, Richard Heyes
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Pager
*/
class Pager
{
// {{{ Pager()
 
/**
* Constructor
*
* -------------------------------------------------------------------------
* VALID options are (default values are set some lines before):
* - mode (string): "Jumping" or "Sliding" -window - It determines
* pager behaviour. See the manual for more details
* - totalItems (int): # of items to page.
* - perPage (int): # of items per page.
* - delta (int): # of page #s to show before and after the current
* one
* - linkClass (string): name of CSS class used for link styling.
* - append (bool): if true pageID is appended as GET value to the
* URL - if false it is embedded in the URL
* according to "fileName" specs
* - httpMethod (string): Specifies the HTTP method to use. Valid values
* are 'GET' or 'POST'
* according to "fileName" specs
* - importQuery (bool): if true (default behaviour), variables and
* values are imported from the submitted data
* (query string) and used in the generated links
* otherwise they're ignored completely
* - path (string): complete path to the page (without the page name)
* - fileName (string): name of the page, with a %d if append=true
* - urlVar (string): name of pageNumber URL var, for example "pageID"
* - altPrev (string): alt text to display for prev page, on prev link.
* - altNext (string): alt text to display for next page, on next link.
* - altPage (string): alt text to display before the page number.
* - prevImg (string): sth (it can be text such as "<< PREV" or an
* <img/> as well...) to display instead of "<<".
* - nextImg (string): same as prevImg, used for NEXT link, instead of
* the default value, which is ">>".
* - separator (string): what to use to separate numbers (can be an
* <img/>, a comma, an hyphen, or whatever.
* - spacesBeforeSeparator
* (int): number of spaces before the separator.
* - firstPagePre (string):
* string used before first page number (can be an
* <img/>, a "{", an empty string, or whatever.
* - firstPageText (string):
* string used in place of first page number
* - firstPagePost (string):
* string used after first page number (can be an
* <img/>, a "}", an empty string, or whatever.
* - lastPagePre (string):
* similar to firstPagePre.
* - lastPageText (string):
* similar to firstPageText.
* - lastPagePost (string):
* similar to firstPagePost.
* - spacesAfterSeparator
* (int): number of spaces after the separator.
* - firstLinkTitle (string):
* string used as title in <link rel="first"> tag
* - lastLinkTitle (string):
* string used as title in <link rel="last"> tag
* - prevLinkTitle (string):
* string used as title in <link rel="prev"> tag
* - nextLinkTitle (string):
* string used as title in <link rel="next"> tag
* - curPageLinkClassName
* (string): name of CSS class used for current page link.
* - clearIfVoid(bool): if there's only one page, don't display pager.
* - extraVars (array): additional URL vars to be added to the querystring
* - excludeVars (array): URL vars to be excluded in the querystring
* - itemData (array): array of items to page.
* - useSessions (bool): if true, number of items to display per page is
* stored in the $_SESSION[$_sessionVar] var.
* - closeSession (bool): if true, the session is closed just after R/W.
* - sessionVar (string): name of the session var for perPage value.
* A value != from default can be useful when
* using more than one Pager istance in the page.
* - pearErrorMode (constant):
* PEAR_ERROR mode for raiseError().
* Default is PEAR_ERROR_RETURN.
* -------------------------------------------------------------------------
* REQUIRED options are:
* - fileName IF append==false (default is true)
* - itemData OR totalItems (if itemData is set, totalItems is overwritten)
* -------------------------------------------------------------------------
*
* @param mixed $options An associative array of option names and
* their values.
* @access public
*/
function Pager($options = array())
{
//this check evaluates to true on 5.0.0RC-dev,
//so i'm using another one, for now...
//if (version_compare(phpversion(), '5.0.0') == -1) {
if (get_class($this) == 'pager') { //php4 lowers class names
// assign factoried method to this for PHP 4
eval('$this = Pager::factory($options);');
} else { //php5 is case sensitive
$msg = 'Pager constructor is deprecated.'
.' You must use the "Pager::factory($params)" method'
.' instead of "new Pager($params)"';
trigger_error($msg, E_USER_ERROR);
}
}
 
// }}}
// {{{ factory()
 
/**
* Return a pager based on $mode and $options
*
* @param array $options Optional parameters for the storage class
* @return object Object Storage object
* @static
* @access public
*/
function &factory($options = array())
{
$mode = (isset($options['mode']) ? ucfirst($options['mode']) : 'Jumping');
$classname = 'Pager_' . $mode;
$classfile = 'Pager' . DIRECTORY_SEPARATOR . $mode . '.php';
 
// Attempt to include a custom version of the named class, but don't treat
// a failure as fatal. The caller may have already included their own
// version of the named class.
if (!class_exists($classname)) {
include_once $classfile;
}
 
// If the class exists, return a new instance of it.
if (class_exists($classname)) {
$pager =& new $classname($options);
return $pager;
}
 
$null = null;
return $null;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Pager/Common.php
New file
0,0 → 1,1502
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the Pager_Common class
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 FREEBSD PROJECT 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 HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>
* @copyright 2003-2006 Lorenzo Alberton, Richard Heyes
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Pager
*/
 
/**
* Two constants used to guess the path- and file-name of the page
* when the user doesn't set any other value
*/
if (substr($_SERVER['PHP_SELF'], -1) == '/') {
define('CURRENT_FILENAME', '');
define('CURRENT_PATHNAME', 'http://'.$_SERVER['HTTP_HOST'].str_replace('\\', '/', $_SERVER['PHP_SELF']));
} else {
define('CURRENT_FILENAME', preg_replace('/(.*)\?.*/', '\\1', basename($_SERVER['PHP_SELF'])));
define('CURRENT_PATHNAME', str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])));
}
/**
* Error codes
*/
define('PAGER_OK', 0);
define('ERROR_PAGER', -1);
define('ERROR_PAGER_INVALID', -2);
define('ERROR_PAGER_INVALID_PLACEHOLDER', -3);
define('ERROR_PAGER_INVALID_USAGE', -4);
define('ERROR_PAGER_NOT_IMPLEMENTED', -5);
 
/**
* Pager_Common - Common base class for [Sliding|Jumping] Window Pager
* Extend this class to write a custom paging class
*
* @category HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>
* @copyright 2003-2005 Lorenzo Alberton, Richard Heyes
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Pager
*/
class Pager_Common
{
// {{{ class vars
 
/**
* @var integer number of items
* @access private
*/
var $_totalItems;
 
/**
* @var integer number of items per page
* @access private
*/
var $_perPage = 10;
 
/**
* @var integer number of page links for each window
* @access private
*/
var $_delta = 10;
 
/**
* @var integer current page number
* @access private
*/
var $_currentPage = 1;
 
/**
* @var integer total pages number
* @access private
*/
var $_totalPages = 1;
 
/**
* @var string CSS class for links
* @access private
*/
var $_linkClass = '';
 
/**
* @var string wrapper for CSS class name
* @access private
*/
var $_classString = '';
 
/**
* @var string path name
* @access private
*/
var $_path = CURRENT_PATHNAME;
 
/**
* @var string file name
* @access private
*/
var $_fileName = CURRENT_FILENAME;
/**
* @var boolean If false, don't override the fileName option. Use at your own risk.
* @access private
*/
var $_fixFileName = true;
 
/**
* @var boolean you have to use FALSE with mod_rewrite
* @access private
*/
var $_append = true;
 
/**
* @var string specifies which HTTP method to use
* @access private
*/
var $_httpMethod = 'GET';
/**
* @var string specifies which HTML form to use
* @access private
*/
var $_formID = '';
 
/**
* @var boolean whether or not to import submitted data
* @access private
*/
var $_importQuery = true;
 
/**
* @var string name of the querystring var for pageID
* @access private
*/
var $_urlVar = 'pageID';
 
/**
* @var array data to pass through the link
* @access private
*/
var $_linkData = array();
 
/**
* @var array additional URL vars
* @access private
*/
var $_extraVars = array();
/**
* @var array URL vars to ignore
* @access private
*/
var $_excludeVars = array();
 
/**
* @var boolean TRUE => expanded mode (for Pager_Sliding)
* @access private
*/
var $_expanded = true;
/**
* @var boolean TRUE => show accesskey attribute on <a> tags
* @access private
*/
var $_accesskey = false;
 
/**
* @var string extra attributes for the <a> tag
* @access private
*/
var $_attributes = '';
 
/**
* @var string alt text for "first page" (use "%d" placeholder for page number)
* @access private
*/
var $_altFirst = 'first page';
 
/**
* @var string alt text for "previous page"
* @access private
*/
var $_altPrev = 'previous page';
 
/**
* @var string alt text for "next page"
* @access private
*/
var $_altNext = 'next page';
 
/**
* @var string alt text for "last page" (use "%d" placeholder for page number)
* @access private
*/
var $_altLast = 'last page';
 
/**
* @var string alt text for "page"
* @access private
*/
var $_altPage = 'page';
 
/**
* @var string image/text to use as "prev" link
* @access private
*/
var $_prevImg = '&lt;&lt; Back';
 
/**
* @var string image/text to use as "next" link
* @access private
*/
var $_nextImg = 'Next &gt;&gt;';
 
/**
* @var string link separator
* @access private
*/
var $_separator = '';
 
/**
* @var integer number of spaces before separator
* @access private
*/
var $_spacesBeforeSeparator = 0;
 
/**
* @var integer number of spaces after separator
* @access private
*/
var $_spacesAfterSeparator = 1;
 
/**
* @var string CSS class name for current page link
* @access private
*/
var $_curPageLinkClassName = '';
 
/**
* @var string Text before current page link
* @access private
*/
var $_curPageSpanPre = '';
 
/**
* @var string Text after current page link
* @access private
*/
var $_curPageSpanPost = '';
 
/**
* @var string Text before first page link
* @access private
*/
var $_firstPagePre = '[';
 
/**
* @var string Text to be used for first page link
* @access private
*/
var $_firstPageText = '';
 
/**
* @var string Text after first page link
* @access private
*/
var $_firstPagePost = ']';
 
/**
* @var string Text before last page link
* @access private
*/
var $_lastPagePre = '[';
 
/**
* @var string Text to be used for last page link
* @access private
*/
var $_lastPageText = '';
 
/**
* @var string Text after last page link
* @access private
*/
var $_lastPagePost = ']';
 
/**
* @var string Will contain the HTML code for the spaces
* @access private
*/
var $_spacesBefore = '';
 
/**
* @var string Will contain the HTML code for the spaces
* @access private
*/
var $_spacesAfter = '';
 
/**
* @var string $_firstLinkTitle
* @access private
*/
var $_firstLinkTitle = 'first page';
 
/**
* @var string $_nextLinkTitle
* @access private
*/
var $_nextLinkTitle = 'next page';
 
/**
* @var string $_prevLinkTitle
* @access private
*/
var $_prevLinkTitle = 'previous page';
 
/**
* @var string $_lastLinkTitle
* @access private
*/
var $_lastLinkTitle = 'last page';
 
/**
* @var string Text to be used for the 'show all' option in the select box
* @access private
*/
var $_showAllText = '';
 
/**
* @var array data to be paged
* @access private
*/
var $_itemData = null;
 
/**
* @var boolean If TRUE and there's only one page, links aren't shown
* @access private
*/
var $_clearIfVoid = true;
 
/**
* @var boolean Use session for storing the number of items per page
* @access private
*/
var $_useSessions = false;
 
/**
* @var boolean Close the session when finished reading/writing data
* @access private
*/
var $_closeSession = false;
 
/**
* @var string name of the session var for number of items per page
* @access private
*/
var $_sessionVar = 'setPerPage';
 
/**
* Pear error mode (when raiseError is called)
* (see PEAR doc)
*
* @var int $_pearErrorMode
* @access private
*/
var $_pearErrorMode = null;
 
// }}}
// {{{ public vars
 
/**
* @var string Complete set of links
* @access public
*/
var $links = '';
 
/**
* @var string Complete set of link tags
* @access public
*/
var $linkTags = '';
 
/**
* @var array Array with a key => value pair representing
* page# => bool value (true if key==currentPageNumber).
* can be used for extreme customization.
* @access public
*/
var $range = array();
/**
* @var array list of available options (safety check)
* @access private
*/
var $_allowed_options = array(
'totalItems',
'perPage',
'delta',
'linkClass',
'path',
'fileName',
'fixFileName',
'append',
'httpMethod',
'formID',
'importQuery',
'urlVar',
'altFirst',
'altPrev',
'altNext',
'altLast',
'altPage',
'prevImg',
'nextImg',
'expanded',
'accesskey',
'attributes',
'separator',
'spacesBeforeSeparator',
'spacesAfterSeparator',
'curPageLinkClassName',
'curPageSpanPre',
'curPageSpanPost',
'firstPagePre',
'firstPageText',
'firstPagePost',
'lastPagePre',
'lastPageText',
'lastPagePost',
'firstLinkTitle',
'nextLinkTitle',
'prevLinkTitle',
'lastLinkTitle',
'showAllText',
'itemData',
'clearIfVoid',
'useSessions',
'closeSession',
'sessionVar',
'pearErrorMode',
'extraVars',
'excludeVars',
'currentPage',
);
 
// }}}
// {{{ build()
/**
* Generate or refresh the links and paged data after a call to setOptions()
*
* @access public
*/
function build()
{
$msg = '<b>PEAR::Pager Error:</b>'
.' function "build()" not implemented.';
return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
}
 
// }}}
// {{{ getPageData()
 
/**
* Returns an array of current pages data
*
* @param $pageID Desired page ID (optional)
* @return array Page data
* @access public
*/
function getPageData($pageID = null)
{
$pageID = empty($pageID) ? $this->_currentPage : $pageID;
 
if (!isset($this->_pageData)) {
$this->_generatePageData();
}
if (!empty($this->_pageData[$pageID])) {
return $this->_pageData[$pageID];
}
return array();
}
 
// }}}
// {{{ getPageIdByOffset()
 
/**
* Returns pageID for given offset
*
* @param $index Offset to get pageID for
* @return int PageID for given offset
*/
function getPageIdByOffset($index)
{
$msg = '<b>PEAR::Pager Error:</b>'
.' function "getPageIdByOffset()" not implemented.';
return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
}
 
// }}}
// {{{ getOffsetByPageId()
 
/**
* Returns offsets for given pageID. Eg, if you
* pass it pageID one and your perPage limit is 10
* it will return (1, 10). PageID of 2 would
* give you (11, 20).
*
* @param integer PageID to get offsets for
* @return array First and last offsets
* @access public
*/
function getOffsetByPageId($pageid = null)
{
$pageid = isset($pageid) ? $pageid : $this->_currentPage;
if (!isset($this->_pageData)) {
$this->_generatePageData();
}
 
if (isset($this->_pageData[$pageid]) || is_null($this->_itemData)) {
return array(
max(($this->_perPage * ($pageid - 1)) + 1, 1),
min($this->_totalItems, $this->_perPage * $pageid)
);
} else {
return array(0, 0);
}
}
 
// }}}
// {{{ getPageRangeByPageId()
 
/**
* @param integer PageID to get offsets for
* @return array First and last offsets
*/
function getPageRangeByPageId($pageID)
{
$msg = '<b>PEAR::Pager Error:</b>'
.' function "getPageRangeByPageId()" not implemented.';
return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
}
 
// }}}
// {{{ getLinks()
 
/**
* Returns back/next/first/last and page links,
* both as ordered and associative array.
*
* NB: in original PEAR::Pager this method accepted two parameters,
* $back_html and $next_html. Now the only parameter accepted is
* an integer ($pageID), since the html text for prev/next links can
* be set in the factory. If a second parameter is provided, then
* the method act as it previously did. This hack was done to mantain
* backward compatibility only.
*
* @param integer $pageID Optional pageID. If specified, links
* for that page are provided instead of current one. [ADDED IN NEW PAGER VERSION]
* @param string $next_html HTML to put inside the next link [deprecated: use the factory instead]
* @return array back/next/first/last and page links
*/
function getLinks($pageID=null, $next_html='')
{
$msg = '<b>PEAR::Pager Error:</b>'
.' function "getLinks()" not implemented.';
return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
}
 
// }}}
// {{{ getCurrentPageID()
 
/**
* Returns ID of current page
*
* @return integer ID of current page
*/
function getCurrentPageID()
{
return $this->_currentPage;
}
 
// }}}
// {{{ getNextPageID()
 
/**
* Returns next page ID. If current page is last page
* this function returns FALSE
*
* @return mixed Next page ID
*/
function getNextPageID()
{
return ($this->getCurrentPageID() == $this->numPages() ? false : $this->getCurrentPageID() + 1);
}
 
// }}}
// {{{ getPreviousPageID()
 
/**
* Returns previous page ID. If current page is first page
* this function returns FALSE
*
* @return mixed Previous pages' ID
*/
function getPreviousPageID()
{
return $this->isFirstPage() ? false : $this->getCurrentPageID() - 1;
}
 
// }}}
// {{{ numItems()
 
/**
* Returns number of items
*
* @return int Number of items
*/
function numItems()
{
return $this->_totalItems;
}
 
// }}}
// {{{ numPages()
 
/**
* Returns number of pages
*
* @return int Number of pages
*/
function numPages()
{
return (int)$this->_totalPages;
}
 
// }}}
// {{{ isFirstPage()
 
/**
* Returns whether current page is first page
*
* @return bool First page or not
*/
function isFirstPage()
{
return ($this->_currentPage < 2);
}
 
// }}}
// {{{ isLastPage()
 
/**
* Returns whether current page is last page
*
* @return bool Last page or not
*/
function isLastPage()
{
return ($this->_currentPage == $this->_totalPages);
}
 
// }}}
// {{{ isLastPageComplete()
 
/**
* Returns whether last page is complete
*
* @return bool Last age complete or not
*/
function isLastPageComplete()
{
return !($this->_totalItems % $this->_perPage);
}
 
// }}}
// {{{ _generatePageData()
 
/**
* Calculates all page data
* @access private
*/
function _generatePageData()
{
// Been supplied an array of data?
if (!is_null($this->_itemData)) {
$this->_totalItems = count($this->_itemData);
}
$this->_totalPages = ceil((float)$this->_totalItems / (float)$this->_perPage);
$i = 1;
if (!empty($this->_itemData)) {
foreach ($this->_itemData as $key => $value) {
$this->_pageData[$i][$key] = $value;
if (count($this->_pageData[$i]) >= $this->_perPage) {
$i++;
}
}
} else {
$this->_pageData = array();
}
 
//prevent URL modification
$this->_currentPage = min($this->_currentPage, $this->_totalPages);
}
 
// }}}
// {{{ _renderLink()
 
/**
* Renders a link using the appropriate method
*
* @param altText Alternative text for this link (title property)
* @param linkText Text contained by this link
* @return string The link in string form
* @access private
*/
function _renderLink($altText, $linkText)
{
if ($this->_httpMethod == 'GET') {
if ($this->_append) {
$href = '?' . $this->_http_build_query_wrapper($this->_linkData);
} else {
$href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
}
return sprintf('<a href="%s"%s%s%s title="%s">%s</a>',
htmlentities($this->_url . $href),
empty($this->_classString) ? '' : ' '.$this->_classString,
empty($this->_attributes) ? '' : ' '.$this->_attributes,
empty($this->_accesskey) ? '' : ' accesskey="'.$this->_linkData[$this->_urlVar].'"',
$altText,
$linkText
);
} elseif ($this->_httpMethod == 'POST') {
return sprintf("<a href='javascript:void(0)' onclick='%s'%s%s%s title='%s'>%s</a>",
$this->_generateFormOnClick($this->_url, $this->_linkData),
empty($this->_classString) ? '' : ' '.$this->_classString,
empty($this->_attributes) ? '' : ' '.$this->_attributes,
empty($this->_accesskey) ? '' : ' accesskey=\''.$this->_linkData[$this->_urlVar].'\'',
$altText,
$linkText
);
}
return '';
}
 
// }}}
// {{{ _generateFormOnClick()
 
/**
* Mimics http_build_query() behavior in the way the data
* in $data will appear when it makes it back to the server.
* For example:
* $arr = array('array' => array(array('hello', 'world'),
* 'things' => array('stuff', 'junk'));
* http_build_query($arr)
* and _generateFormOnClick('foo.php', $arr)
* will yield
* $_REQUEST['array'][0][0] === 'hello'
* $_REQUEST['array'][0][1] === 'world'
* $_REQUEST['array']['things'][0] === 'stuff'
* $_REQUEST['array']['things'][1] === 'junk'
*
* However, instead of generating a query string, it generates
* Javascript to create and submit a form.
*
* @param string $formAction where the form should be submitted
* @param array $data the associative array of names and values
* @return string A string of javascript that generates a form and submits it
* @access private
*/
function _generateFormOnClick($formAction, $data)
{
// Check we have an array to work with
if (!is_array($data)) {
trigger_error(
'_generateForm() Parameter 1 expected to be Array or Object. Incorrect value given.',
E_USER_WARNING
);
return false;
}
 
if (!empty($this->_formID)) {
$str = 'var form = document.getElementById("'.$this->_formID.'"); var input = ""; ';
} else {
$str = 'var form = document.createElement("form"); var input = ""; ';
}
// We /shouldn't/ need to escape the URL ...
$str .= sprintf('form.action = "%s"; ', htmlentities($formAction));
$str .= sprintf('form.method = "%s"; ', $this->_httpMethod);
foreach ($data as $key => $val) {
$str .= $this->_generateFormOnClickHelper($val, $key);
}
 
if (empty($this->_formID)) {
$str .= 'document.getElementsByTagName("body")[0].appendChild(form);';
}
$str .= 'form.submit(); return false;';
return $str;
}
 
// }}}
// {{{ _generateFormOnClickHelper
 
/**
* This is used by _generateFormOnClick().
* Recursively processes the arrays, objects, and literal values.
*
* @param data Data that should be rendered
* @param prev The name so far
* @return string A string of Javascript that creates form inputs
* representing the data
* @access private
*/
function _generateFormOnClickHelper($data, $prev = '')
{
$str = '';
if (is_array($data) || is_object($data)) {
// foreach key/visible member
foreach ((array)$data as $key => $val) {
// append [$key] to prev
$tempKey = sprintf('%s[%s]', $prev, $key);
$str .= $this->_generateFormOnClickHelper($val, $tempKey);
}
} else { // must be a literal value
// escape newlines and carriage returns
$search = array("\n", "\r");
$replace = array('\n', '\n');
$escapedData = str_replace($search, $replace, $data);
// am I forgetting any dangerous whitespace?
// would a regex be faster?
// if it's already encoded, don't encode it again
if (!$this->_isEncoded($escapedData)) {
$escapedData = urlencode($escapedData);
}
$escapedData = htmlentities($escapedData, ENT_QUOTES, 'UTF-8');
 
$str .= 'input = document.createElement("input"); ';
$str .= 'input.type = "hidden"; ';
$str .= sprintf('input.name = "%s"; ', $prev);
$str .= sprintf('input.value = "%s"; ', $escapedData);
$str .= 'form.appendChild(input); ';
}
return $str;
}
 
// }}}
// {{{ _getLinksData()
 
/**
* Returns the correct link for the back/pages/next links
*
* @return array Data
* @access private
*/
function _getLinksData()
{
$qs = array();
if ($this->_importQuery) {
if ($this->_httpMethod == 'POST') {
$qs = $_POST;
} elseif ($this->_httpMethod == 'GET') {
$qs = $_GET;
}
}
if (count($this->_extraVars)){
$this->_recursive_urldecode($this->_extraVars);
}
$qs = array_merge($qs, $this->_extraVars);
foreach ($this->_excludeVars as $exclude) {
if (array_key_exists($exclude, $qs)) {
unset($qs[$exclude]);
}
}
if (count($qs) && get_magic_quotes_gpc()){
$this->_recursive_stripslashes($qs);
}
return $qs;
}
 
// }}}
// {{{ _recursive_stripslashes()
/**
* Helper method
* @param mixed $var
* @access private
*/
function _recursive_stripslashes(&$var)
{
if (is_array($var)) {
foreach (array_keys($var) as $k) {
$this->_recursive_stripslashes($var[$k]);
}
} else {
$var = stripslashes($var);
}
}
 
// }}}
// {{{ _recursive_urldecode()
 
/**
* Helper method
* @param mixed $var
* @access private
*/
function _recursive_urldecode(&$var)
{
if (is_array($var)) {
foreach (array_keys($var) as $k) {
$this->_recursive_urldecode($var[$k]);
}
} else {
$trans_tbl = array_flip(get_html_translation_table(HTML_ENTITIES));
$var = strtr($var, $trans_tbl);
}
}
 
// }}}
// {{{ _getBackLink()
 
/**
* Returns back link
*
* @param $url URL to use in the link [deprecated: use the factory instead]
* @param $link HTML to use as the link [deprecated: use the factory instead]
* @return string The link
* @access private
*/
function _getBackLink($url='', $link='')
{
//legacy settings... the preferred way to set an option
//now is passing it to the factory
if (!empty($url)) {
$this->_path = $url;
}
if (!empty($link)) {
$this->_prevImg = $link;
}
$back = '';
if ($this->_currentPage > 1) {
$this->_linkData[$this->_urlVar] = $this->getPreviousPageID();
$back = $this->_renderLink($this->_altPrev, $this->_prevImg)
. $this->_spacesBefore . $this->_spacesAfter;
}
return $back;
}
 
// }}}
// {{{ _getPageLinks()
 
/**
* Returns pages link
*
* @param $url URL to use in the link [deprecated: use the factory instead]
* @return string Links
* @access private
*/
function _getPageLinks($url='')
{
$msg = '<b>PEAR::Pager Error:</b>'
.' function "_getPageLinks()" not implemented.';
return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
}
 
// }}}
// {{{ _getNextLink()
 
/**
* Returns next link
*
* @param $url URL to use in the link [deprecated: use the factory instead]
* @param $link HTML to use as the link [deprecated: use the factory instead]
* @return string The link
* @access private
*/
function _getNextLink($url='', $link='')
{
//legacy settings... the preferred way to set an option
//now is passing it to the factory
if (!empty($url)) {
$this->_path = $url;
}
if (!empty($link)) {
$this->_nextImg = $link;
}
$next = '';
if ($this->_currentPage < $this->_totalPages) {
$this->_linkData[$this->_urlVar] = $this->getNextPageID();
$next = $this->_spacesAfter
. $this->_renderLink($this->_altNext, $this->_nextImg)
. $this->_spacesBefore . $this->_spacesAfter;
}
return $next;
}
 
// }}}
// {{{ _getFirstLinkTag()
 
/**
* @return string
* @access private
*/
function _getFirstLinkTag()
{
if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
return '';
}
return sprintf('<link rel="first" href="%s" title="%s" />'."\n",
$this->_getLinkTagUrl(1),
$this->_firstLinkTitle
);
}
 
// }}}
// {{{ _getPrevLinkTag()
 
/**
* Returns previous link tag
*
* @return string the link tag
* @access private
*/
function _getPrevLinkTag()
{
if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
return '';
}
return sprintf('<link rel="previous" href="%s" title="%s" />'."\n",
$this->_getLinkTagUrl($this->getPreviousPageID()),
$this->_prevLinkTitle
);
}
 
// }}}
// {{{ _getNextLinkTag()
 
/**
* Returns next link tag
*
* @return string the link tag
* @access private
*/
function _getNextLinkTag()
{
if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
return '';
}
return sprintf('<link rel="next" href="%s" title="%s" />'."\n",
$this->_getLinkTagUrl($this->getNextPageID()),
$this->_nextLinkTitle
);
}
 
// }}}
// {{{ _getLastLinkTag()
 
/**
* @return string the link tag
* @access private
*/
function _getLastLinkTag()
{
if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
return '';
}
return sprintf('<link rel="last" href="%s" title="%s" />'."\n",
$this->_getLinkTagUrl($this->_totalPages),
$this->_lastLinkTitle
);
}
 
// }}}
// {{{ _getLinkTagUrl()
 
/**
* Helper method
* @return string the link tag url
* @access private
*/
function _getLinkTagUrl($pageID)
{
$this->_linkData[$this->_urlVar] = $pageID;
if ($this->_append) {
$href = '?' . $this->_http_build_query_wrapper($this->_linkData);
} else {
$href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
}
return htmlentities($this->_url . $href);
}
// }}}
// {{{ getPerPageSelectBox()
 
/**
* Returns a string with a XHTML SELECT menu,
* useful for letting the user choose how many items per page should be
* displayed. If parameter useSessions is TRUE, this value is stored in
* a session var. The string isn't echoed right now so you can use it
* with template engines.
*
* @param integer $start
* @param integer $end
* @param integer $step
* @param boolean $showAllData If true, perPage is set equal to totalItems.
* @param array (or string $optionText for BC reasons)
* - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'attributes': (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* <select> tag
* @return string xhtml select box
* @access public
*/
function getPerPageSelectBox($start=5, $end=30, $step=5, $showAllData=false, $extraParams=array())
{
require_once 'Pager/HtmlWidgets.php';
$widget =& new Pager_HtmlWidgets($this);
return $widget->getPerPageSelectBox($start, $end, $step, $showAllData, $extraParams);
}
 
// }}}
// {{{ getPageSelectBox()
 
/**
* Returns a string with a XHTML SELECT menu with the page numbers,
* useful as an alternative to the links
*
* @param array - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'autoSubmit': if TRUE, add some js code to submit the
* form on the onChange event
* @param string $extraAttributes (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* <select> tag
* @return string xhtml select box
* @access public
*/
function getPageSelectBox($params = array(), $extraAttributes = '')
{
require_once 'Pager/HtmlWidgets.php';
$widget =& new Pager_HtmlWidgets($this);
return $widget->getPageSelectBox($params, $extraAttributes);
}
 
// }}}
// {{{ _printFirstPage()
 
/**
* Print [1]
*
* @return string String with link to 1st page,
* or empty string if this is the 1st page.
* @access private
*/
function _printFirstPage()
{
if ($this->isFirstPage()) {
return '';
}
$this->_linkData[$this->_urlVar] = 1;
return $this->_renderLink(
str_replace('%d', 1, $this->_altFirst),
$this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost
) . $this->_spacesBefore . $this->_spacesAfter;
}
 
// }}}
// {{{ _printLastPage()
 
/**
* Print [numPages()]
*
* @return string String with link to last page,
* or empty string if this is the 1st page.
* @access private
*/
function _printLastPage()
{
if ($this->isLastPage()) {
return '';
}
$this->_linkData[$this->_urlVar] = $this->_totalPages;
return $this->_renderLink(
str_replace('%d', $this->_totalPages, $this->_altLast),
$this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost
);
}
 
// }}}
// {{{ _setFirstLastText()
 
/**
* sets the private _firstPageText, _lastPageText variables
* based on whether they were set in the options
*
* @access private
*/
function _setFirstLastText()
{
if ($this->_firstPageText == '') {
$this->_firstPageText = '1';
}
if ($this->_lastPageText == '') {
$this->_lastPageText = $this->_totalPages;
}
}
 
// }}}
// {{{ _http_build_query_wrapper()
/**
* This is a slightly modified version of the http_build_query() function;
* it heavily borrows code from PHP_Compat's http_build_query().
* The main change is the usage of htmlentities instead of urlencode,
* since it's too aggressive
*
* @author Stephan Schmidt <schst@php.net>
* @author Aidan Lister <aidan@php.net>
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @param array $data
* @return string
* @access private
*/
function _http_build_query_wrapper($data)
{
$data = (array)$data;
if (empty($data)) {
return '';
}
$separator = ini_get('arg_separator.output');
if ($separator == '&amp;') {
$separator = '&'; //the string is escaped by htmlentities anyway...
}
$tmp = array ();
foreach ($data as $key => $val) {
if (is_scalar($val)) {
//array_push($tmp, $key.'='.$val);
$val = urlencode($val);
array_push($tmp, $key .'='. str_replace('%2F', '/', $val));
continue;
}
// If the value is an array, recursively parse it
if (is_array($val)) {
array_push($tmp, $this->__http_build_query($val, htmlentities($key)));
continue;
}
}
return implode($separator, $tmp);
}
 
// }}}
// {{{ __http_build_query()
 
/**
* Helper function
* @author Stephan Schmidt <schst@php.net>
* @author Aidan Lister <aidan@php.net>
* @access private
*/
function __http_build_query($array, $name)
{
$tmp = array ();
foreach ($array as $key => $value) {
if (is_array($value)) {
//array_push($tmp, $this->__http_build_query($value, sprintf('%s[%s]', $name, $key)));
array_push($tmp, $this->__http_build_query($value, $name.'%5B'.$key.'%5D'));
} elseif (is_scalar($value)) {
//array_push($tmp, sprintf('%s[%s]=%s', $name, htmlentities($key), htmlentities($value)));
array_push($tmp, $name.'%5B'.htmlentities($key).'%5D='.htmlentities($value));
} elseif (is_object($value)) {
//array_push($tmp, $this->__http_build_query(get_object_vars($value), sprintf('%s[%s]', $name, $key)));
array_push($tmp, $this->__http_build_query(get_object_vars($value), $name.'%5B'.$key.'%5D'));
}
}
return implode(ini_get('arg_separator.output'), $tmp);
}
 
// }}}
// {{{ _isEncoded()
 
/**
* Helper function
* Check if a string is an encoded multibyte string
* @param string $string
* @return boolean
* @access private
*/
function _isEncoded($string)
{
$hexchar = '&#[\dA-Fx]{2,};';
return preg_match("/^(\s|($hexchar))*$/Uims", $string) ? true : false;
}
 
// }}}
// {{{ raiseError()
 
/**
* conditionally includes PEAR base class and raise an error
*
* @param string $msg Error message
* @param int $code Error code
* @access private
*/
function raiseError($msg, $code)
{
include_once 'PEAR.php';
if (empty($this->_pearErrorMode)) {
$this->_pearErrorMode = PEAR_ERROR_RETURN;
}
return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
}
 
// }}}
// {{{ setOptions()
 
/**
* Set and sanitize options
*
* @param mixed $options An associative array of option names and
* their values.
* @return integer error code (PAGER_OK on success)
* @access public
*/
function setOptions($options)
{
foreach ($options as $key => $value) {
if (in_array($key, $this->_allowed_options) && (!is_null($value))) {
$this->{'_' . $key} = $value;
}
}
 
//autodetect http method
if (!isset($options['httpMethod'])
&& !isset($_GET[$this->_urlVar])
&& isset($_POST[$this->_urlVar])
) {
$this->_httpMethod = 'POST';
} else {
$this->_httpMethod = strtoupper($this->_httpMethod);
}
 
$this->_fileName = ltrim($this->_fileName, '/'); //strip leading slash
$this->_path = rtrim($this->_path, '/'); //strip trailing slash
 
if ($this->_append) {
if ($this->_fixFileName) {
$this->_fileName = CURRENT_FILENAME; //avoid possible user error;
}
$this->_url = $this->_path.'/'.$this->_fileName;
} else {
$this->_url = $this->_path;
if (strncasecmp($this->_fileName, 'javascript', 10) != 0) {
$this->_url .= '/';
}
if (!strstr($this->_fileName, '%d')) {
trigger_error($this->errorMessage(ERROR_PAGER_INVALID_USAGE), E_USER_WARNING);
}
}
 
$this->_classString = '';
if (strlen($this->_linkClass)) {
$this->_classString = 'class="'.$this->_linkClass.'"';
}
 
if (strlen($this->_curPageLinkClassName)) {
$this->_curPageSpanPre = '<span class="'.$this->_curPageLinkClassName.'">';
$this->_curPageSpanPost = '</span>';
}
 
$this->_perPage = max($this->_perPage, 1); //avoid possible user errors
 
if ($this->_useSessions && !isset($_SESSION)) {
session_start();
}
if (!empty($_REQUEST[$this->_sessionVar])) {
$this->_perPage = max(1, (int)$_REQUEST[$this->_sessionVar]);
if ($this->_useSessions) {
$_SESSION[$this->_sessionVar] = $this->_perPage;
}
}
 
if (!empty($_SESSION[$this->_sessionVar])) {
$this->_perPage = $_SESSION[$this->_sessionVar];
}
 
if ($this->_closeSession) {
session_write_close();
}
 
$this->_spacesBefore = str_repeat('&nbsp;', $this->_spacesBeforeSeparator);
$this->_spacesAfter = str_repeat('&nbsp;', $this->_spacesAfterSeparator);
 
if (isset($_REQUEST[$this->_urlVar]) && empty($options['currentPage'])) {
$this->_currentPage = (int)$_REQUEST[$this->_urlVar];
}
$this->_currentPage = max($this->_currentPage, 1);
$this->_linkData = $this->_getLinksData();
 
return PAGER_OK;
}
 
// }}}
// {{{ getOption()
/**
* Return the current value of a given option
*
* @param string option name
* @return mixed option value
*/
function getOption($name)
{
if (!in_array($name, $this->_allowed_options)) {
$msg = '<b>PEAR::Pager Error:</b>'
.' invalid option: '.$name;
return $this->raiseError($msg, ERROR_PAGER_INVALID);
}
return $this->{'_' . $name};
}
 
// }}}
// {{{ getOptions()
 
/**
* Return an array with all the current pager options
*
* @return array list of all the pager options
*/
function getOptions()
{
$options = array();
foreach ($this->_allowed_options as $option) {
$options[$option] = $this->{'_' . $option};
}
return $options;
}
 
// }}}
// {{{ errorMessage()
 
/**
* Return a textual error message for a PAGER error code
*
* @param int $code error code
* @return string error message
* @access public
*/
function errorMessage($code)
{
static $errorMessages;
if (!isset($errorMessages)) {
$errorMessages = array(
ERROR_PAGER => 'unknown error',
ERROR_PAGER_INVALID => 'invalid',
ERROR_PAGER_INVALID_PLACEHOLDER => 'invalid format - use "%d" as placeholder.',
ERROR_PAGER_INVALID_USAGE => 'if $options[\'append\'] is set to false, '
.' $options[\'fileName\'] MUST contain the "%d" placeholder.',
ERROR_PAGER_NOT_IMPLEMENTED => 'not implemented'
);
}
 
return '<b>PEAR::Pager error:</b> '. (isset($errorMessages[$code]) ?
$errorMessages[$code] : $errorMessages[ERROR_PAGER]);
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Pager/examples/example.php
New file
0,0 → 1,78
<?php
require_once 'Pager/Pager.php';
 
//create dummy array of data
$myData = array();
for ($i=0; $i<200; $i++) {
$myData[] = $i;
}
 
$params = array(
'itemData' => $myData,
'perPage' => 10,
'delta' => 8, // for 'Jumping'-style a lower number is better
'append' => true,
//'separator' => ' | ',
'clearIfVoid' => false,
'urlVar' => 'entrant',
'useSessions' => true,
'closeSession' => true,
//'mode' => 'Sliding', //try switching modes
'mode' => 'Jumping',
 
);
$pager = & Pager::factory($params);
$page_data = $pager->getPageData();
$links = $pager->getLinks();
 
$selectBox = $pager->getPerPageSelectBox();
?>
 
<html>
<head>
<title>new PEAR::Pager example</title>
</head>
<body>
 
<table border="1" width="500" summary="example 1">
<tr>
<td colspan="3" align="center">
<?php echo $links['all']; ?>
</td>
</tr>
 
 
<tr>
<td colspan="3">
<pre><?php print_r($page_data); ?></pre>
</td>
</tr>
</table>
 
<h4>Results from methods:</h4>
 
<pre>
getCurrentPageID()...: <?php var_dump($pager->getCurrentPageID()); ?>
getNextPageID()......: <?php var_dump($pager->getNextPageID()); ?>
getPreviousPageID()..: <?php var_dump($pager->getPreviousPageID()); ?>
numItems()...........: <?php var_dump($pager->numItems()); ?>
numPages()...........: <?php var_dump($pager->numPages()); ?>
isFirstPage()........: <?php var_dump($pager->isFirstPage()); ?>
isLastPage().........: <?php var_dump($pager->isLastPage()); ?>
isLastPageComplete().: <?php var_dump($pager->isLastPageComplete()); ?>
$pager->range........: <?php var_dump($pager->range); ?>
</pre>
 
 
<hr />
 
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET">
Select how many items per page should be shown:<br />
<?php echo $selectBox; ?> &nbsp;
<input type="submit" value="submit" />
</form>
 
<hr />
 
</body>
</html>
/branches/v1.0-menes/api/pear/Pager/examples/Pager_Wrapper.php
New file
0,0 → 1,339
<?php
// CVS: $Id$
//
// Pager_Wrapper
// -------------
//
// Ready-to-use wrappers for paging the result of a query,
// when fetching the whole resultset is NOT an option.
// This is a performance- and memory-savvy method
// to use PEAR::Pager with a database.
// With this approach, the network load can be
// consistently smaller than with PEAR::DB_Pager.
//
// The following wrappers are provided: one for each PEAR
// db abstraction layer (DB, MDB and MDB2), one for
// PEAR::DB_DataObject, and one for the PHP Eclipse library
//
//
// SAMPLE USAGE
// ------------
//
// $query = 'SELECT this, that FROM mytable';
// require_once 'Pager_Wrapper.php'; //this file
// $pagerOptions = array(
// 'mode' => 'Sliding',
// 'delta' => 2,
// 'perPage' => 15,
// );
// $paged_data = Pager_Wrapper_MDB2($db, $query, $pagerOptions);
// //$paged_data['data']; //paged data
// //$paged_data['links']; //xhtml links for page navigation
// //$paged_data['page_numbers']; //array('current', 'total');
//
 
/**
* Helper method - Rewrite the query into a "SELECT COUNT(*)" query.
* @param string $sql query
* @return string rewritten query OR false if the query can't be rewritten
* @access private
*/
function rewriteCountQuery($sql)
{
if (preg_match('/^\s*SELECT\s+\bDISTINCT\b/is', $sql) || preg_match('/\s+GROUP\s+BY\s+/is', $sql)) {
return false;
}
$open_parenthesis = '(?:\()';
$close_parenthesis = '(?:\))';
$subquery_in_select = $open_parenthesis.'.*\bFROM\b.*'.$close_parenthesis;
$pattern = '/(?:.*'.$subquery_in_select.'.*)\bFROM\b\s+/Uims';
if (preg_match($pattern, $sql)) {
return false;
}
$subquery_with_limit_order = $open_parenthesis.'.*\b(LIMIT|ORDER)\b.*'.$close_parenthesis;
$pattern = '/.*\bFROM\b.*(?:.*'.$subquery_with_limit_order.'.*).*/Uims';
if (preg_match($pattern, $sql)) {
return false;
}
$queryCount = preg_replace('/(?:.*)\bFROM\b\s+/Uims', 'SELECT COUNT(*) FROM ', $sql, 1);
list($queryCount, ) = preg_split('/\s+ORDER\s+BY\s+/is', $queryCount);
list($queryCount, ) = preg_split('/\bLIMIT\b/is', $queryCount);
return trim($queryCount);
}
 
/**
* @param object PEAR::DB instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @param mixed parameters for query placeholders
* If you use placeholders for table names or column names, please
* count the # of items returned by the query and pass it as an option:
* $pager_options['totalItems'] = count_records('some query');
* @return array with links and paged data
*/
function Pager_Wrapper_DB(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = DB_FETCHMODE_ASSOC, $dbparams = null)
{
if (!array_key_exists('totalItems', $pager_options)) {
// be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->getOne($countQuery, $dbparams);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
$res =& $db->query($query, $dbparams);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = (int)$res->numRows();
$res->free();
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
 
$page = array();
$page['totalItems'] = $pager_options['totalItems'];
$page['links'] = $pager->links;
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
 
$res = ($disabled)
? $db->limitQuery($query, 0, $totalItems, $dbparams)
: $db->limitQuery($query, $page['from']-1, $pager_options['perPage'], $dbparams);
 
if (PEAR::isError($res)) {
return $res;
}
$page['data'] = array();
while ($res->fetchInto($row, $fetchMode)) {
$page['data'][] = $row;
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
 
/**
* @param object PEAR::MDB instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @return array with links and paged data
*/
function Pager_Wrapper_MDB(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = MDB_FETCHMODE_ASSOC)
{
if (!array_key_exists('totalItems', $pager_options)) {
//be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->queryOne($countQuery);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
$res = $db->query($query);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = (int)$db->numRows($res);
$db->freeResult($res);
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
 
$page = array();
$page['totalItems'] = $pager_options['totalItems'];
$page['links'] = $pager->links;
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
 
$res = ($disabled)
? $db->limitQuery($query, null, 0, $totalItems)
: $db->limitQuery($query, null, $page['from']-1, $pager_options['perPage']);
 
if (PEAR::isError($res)) {
return $res;
}
$page['data'] = array();
while ($row = $db->fetchInto($res, $fetchMode)) {
$page['data'][] = $row;
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
 
/**
* @param object PEAR::MDB2 instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @return array with links and paged data
*/
function Pager_Wrapper_MDB2(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = MDB2_FETCHMODE_ASSOC)
{
if (!array_key_exists('totalItems', $pager_options)) {
//be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->queryOne($countQuery);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
//GROUP BY => fetch the whole resultset and count the rows returned
$res =& $db->queryCol($query);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = count($res);
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
 
$page = array();
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] +1;
if (!$disabled) {
$db->setLimit($pager_options['perPage'], $page['from']-1);
}
$page['data'] = $db->queryAll($query, null, $fetchMode);
if (PEAR::isError($page['data'])) {
return $page['data'];
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
 
/**
* @param object PEAR::DataObject instance
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @return array with links and paged data
* @author Massimiliano Arione <garak@studenti.it>
*/
function Pager_Wrapper_DBDO(&$db, $pager_options = array(), $disabled = false)
{
if (!array_key_exists('totalItems', $pager_options)) {
$totalItems = $db->count();
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
 
$page = array();
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] + 1;
if (!$disabled) {
$db->limit($page['from'] - 1, $pager_options['perPage']);
}
$db->find();
while ($db->fetch()) {
$db->getLinks();
$page['data'][] = $db->toArray('%s', true);
}
return $page;
}
 
/**
* @param object PHP Eclipse instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @return array with links and paged data
* @author Matte Edens <matte@arubanetworks.com>
* @see http://sourceforge.net/projects/eclipselib/
*/
function Pager_Wrapper_Eclipse(&$db, $query, $pager_options = array(), $disabled = false)
{
if (!$disabled) {
require_once(ECLIPSE_ROOT . 'PagedQuery.php');
$query =& new PagedQuery($db->query($query), $pager_options['perPage']);
$totalrows = $query->getRowCount();
$numpages = $query->getPageCount();
$whichpage = isset($_GET[$pager_options['urlVar']]) ? (int)$_GET[$pager_options['urlVar']] - 1 : 0;
if ($whichpage >= $numpages) {
$whichpage = $numpages - 1;
}
$result = $query->getPage($whichpage);
} else {
$result = $db->query($query);
$totalrows = $result->getRowCount();
$numpages = 1;
}
if (!$result->isSuccess()) {
return PEAR::raiseError($result->getErrorMessage());
}
if (!array_key_exists('totalItems', $pager_options)) {
$pager_options['totalItems'] = $totalrows;
}
 
$page = array();
require_once(ECLIPSE_ROOT . 'QueryIterator.php');
for ($it =& new QueryIterator($result); $it->isValid(); $it->next()) {
$page['data'][] =& $it->getCurrent();
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
 
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $numpages
);
$page['perPageSelectBox'] = $pager->getperpageselectbox();
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] +1;
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
?>
/branches/v1.0-menes/api/pear/Pager/Jumping.php
New file
0,0 → 1,280
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the Pager_Jumping class
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 FREEBSD PROJECT 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 HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>,
* @copyright 2003-2006 Lorenzo Alberton, Richard Heyes
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Pager
*/
 
/**
* require PEAR::Pager_Common base class
*/
require_once 'Pager/Common.php';
 
/**
* Pager_Jumping - Generic data paging class ("jumping window" style)
* Handles paging a set of data. For usage see the example.php provided.
*
* @category HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>,
* @copyright 2003-2005 Lorenzo Alberton, Richard Heyes
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Pager
*/
class Pager_Jumping extends Pager_Common
{
// {{{ Pager_Jumping()
 
/**
* Constructor
*
* @param array $options An associative array of option names
* and their values
* @access public
*/
function Pager_Jumping($options = array())
{
$err = $this->setOptions($options);
if ($err !== PAGER_OK) {
return $this->raiseError($this->errorMessage($err), $err);
}
$this->build();
}
 
// }}}
// {{{ build()
 
/**
* Generate or refresh the links and paged data after a call to setOptions()
*
* @access public
*/
function build()
{
//reset
$this->_pageData = array();
$this->links = '';
 
$this->_generatePageData();
$this->_setFirstLastText();
 
$this->links .= $this->_getBackLink();
$this->links .= $this->_getPageLinks();
$this->links .= $this->_getNextLink();
 
$this->linkTags .= $this->_getFirstLinkTag();
$this->linkTags .= $this->_getPrevLinkTag();
$this->linkTags .= $this->_getNextLinkTag();
$this->linkTags .= $this->_getLastLinkTag();
}
 
// }}}
// {{{ getPageIdByOffset()
 
/**
* Returns pageID for given offset
*
* @param $index Offset to get pageID for
* @return int PageID for given offset
*/
function getPageIdByOffset($index)
{
if (!isset($this->_pageData)) {
$this->_generatePageData();
}
 
if (($index % $this->_perPage) > 0) {
$pageID = ceil((float)$index / (float)$this->_perPage);
} else {
$pageID = $index / $this->_perPage;
}
return $pageID;
}
 
// }}}
// {{{ getPageRangeByPageId()
 
/**
* Given a PageId, it returns the limits of the range of pages displayed.
* While getOffsetByPageId() returns the offset of the data within the
* current page, this method returns the offsets of the page numbers interval.
* E.g., if you have pageId=3 and delta=10, it will return (1, 10).
* PageID of 8 would give you (1, 10) as well, because 1 <= 8 <= 10.
* PageID of 11 would give you (11, 20).
* If the method is called without parameter, pageID is set to currentPage#.
*
* @param integer PageID to get offsets for
* @return array First and last offsets
* @access public
*/
function getPageRangeByPageId($pageid = null)
{
$pageid = isset($pageid) ? (int)$pageid : $this->_currentPage;
if (isset($this->_pageData[$pageid]) || is_null($this->_itemData)) {
// I'm sure I'm missing something here, but this formula works
// so I'm using it until I find something simpler.
$start = ((($pageid + (($this->_delta - ($pageid % $this->_delta))) % $this->_delta) / $this->_delta) - 1) * $this->_delta +1;
return array(
max($start, 1),
min($start+$this->_delta-1, $this->_totalPages)
);
} else {
return array(0, 0);
}
}
 
// }}}
// {{{ getLinks()
 
/**
* Returns back/next/first/last and page links,
* both as ordered and associative array.
*
* NB: in original PEAR::Pager this method accepted two parameters,
* $back_html and $next_html. Now the only parameter accepted is
* an integer ($pageID), since the html text for prev/next links can
* be set in the constructor. If a second parameter is provided, then
* the method act as it previously did. This hack's only purpose is to
* mantain backward compatibility.
*
* @param integer $pageID Optional pageID. If specified, links
* for that page are provided instead of current one.
* [ADDED IN NEW PAGER VERSION]
* @param string $next_html HTML to put inside the next link
* [deprecated: use the constructor instead]
* @return array Back/pages/next links
*/
function getLinks($pageID=null, $next_html='')
{
//BC hack
if (!empty($next_html)) {
$back_html = $pageID;
$pageID = null;
} else {
$back_html = '';
}
 
if (!is_null($pageID)) {
$_sav = $this->_currentPage;
$this->_currentPage = $pageID;
 
$this->links = '';
if ($this->_totalPages > $this->_delta) {
$this->links .= $this->_printFirstPage();
}
$this->links .= $this->_getBackLink('', $back_html);
$this->links .= $this->_getPageLinks();
$this->links .= $this->_getNextLink('', $next_html);
if ($this->_totalPages > $this->_delta) {
$this->links .= $this->_printLastPage();
}
}
 
$back = str_replace('&nbsp;', '', $this->_getBackLink());
$next = str_replace('&nbsp;', '', $this->_getNextLink());
$pages = $this->_getPageLinks();
$first = $this->_printFirstPage();
$last = $this->_printLastPage();
$all = $this->links;
$linkTags = $this->linkTags;
 
if (!is_null($pageID)) {
$this->_currentPage = $_sav;
}
 
return array(
$back,
$pages,
trim($next),
$first,
$last,
$all,
$linkTags,
'back' => $back,
'pages' => $pages,
'next' => $next,
'first' => $first,
'last' => $last,
'all' => $all,
'linktags' => $linkTags
);
}
 
// }}}
// {{{ _getPageLinks()
 
/**
* Returns pages link
*
* @param $url URL to use in the link
* [deprecated: use the constructor instead]
* @return string Links
* @access private
*/
function _getPageLinks($url = '')
{
//legacy setting... the preferred way to set an option now
//is adding it to the constuctor
if (!empty($url)) {
$this->_path = $url;
}
 
//If there's only one page, don't display links
if ($this->_clearIfVoid && ($this->_totalPages < 2)) {
return '';
}
 
$links = '';
$limits = $this->getPageRangeByPageId($this->_currentPage);
 
for ($i=$limits[0]; $i<=min($limits[1], $this->_totalPages); $i++) {
if ($i != $this->_currentPage) {
$this->range[$i] = false;
$this->_linkData[$this->_urlVar] = $i;
$links .= $this->_renderLink($this->_altPage.' '.$i, $i);
} else {
$this->range[$i] = true;
$links .= $this->_curPageSpanPre . $i . $this->_curPageSpanPost;
}
$links .= $this->_spacesBefore
. (($i != $this->_totalPages) ? $this->_separator.$this->_spacesAfter : '');
}
return $links;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Pager/Sliding.php
New file
0,0 → 1,324
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the Pager_Sliding class
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 FREEBSD PROJECT 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 HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @copyright 2003-2006 Lorenzo Alberton
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Pager
*/
 
/**
* require PEAR::Pager_Common base class
*/
require_once 'Pager/Common.php';
 
/**
* Pager_Sliding - Generic data paging class ("sliding window" style)
* Usage examples can be found in the PEAR manual
*
* @category HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @copyright 2003-2005 Lorenzo Alberton
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Pager
*/
class Pager_Sliding extends Pager_Common
{
// {{{ Pager_Sliding()
 
/**
* Constructor
*
* @param array $options An associative array of option names
* and their values
* @access public
*/
function Pager_Sliding($options = array())
{
//set default Pager_Sliding options
$this->_delta = 2;
$this->_prevImg = '&laquo;';
$this->_nextImg = '&raquo;';
$this->_separator = '|';
$this->_spacesBeforeSeparator = 3;
$this->_spacesAfterSeparator = 3;
$this->_curPageSpanPre = '<b><u>';
$this->_curPageSpanPost = '</u></b>';
 
//set custom options
$err = $this->setOptions($options);
if ($err !== PAGER_OK) {
return $this->raiseError($this->errorMessage($err), $err);
}
$this->build();
}
 
// }}}
// {{{ build()
 
/**
* Generate or refresh the links and paged data after a call to setOptions()
*
* @access public
*/
function build()
{
//reset
$this->_pageData = array();
$this->links = '';
 
$this->_generatePageData();
$this->_setFirstLastText();
 
if ($this->_totalPages > (2 * $this->_delta + 1)) {
$this->links .= $this->_printFirstPage();
}
 
$this->links .= $this->_getBackLink();
$this->links .= $this->_getPageLinks();
$this->links .= $this->_getNextLink();
 
$this->linkTags .= $this->_getFirstLinkTag();
$this->linkTags .= $this->_getPrevLinkTag();
$this->linkTags .= $this->_getNextLinkTag();
$this->linkTags .= $this->_getLastLinkTag();
 
if ($this->_totalPages > (2 * $this->_delta + 1)) {
$this->links .= $this->_printLastPage();
}
}
 
// }}}
// {{{ getPageIdByOffset()
 
/**
* "Overload" PEAR::Pager method. VOID. Not needed here...
* @param integer $index Offset to get pageID for
* @deprecated
* @access public
*/
function getPageIdByOffset($index=null) { }
 
// }}}
// {{{ getPageRangeByPageId()
 
/**
* Given a PageId, it returns the limits of the range of pages displayed.
* While getOffsetByPageId() returns the offset of the data within the
* current page, this method returns the offsets of the page numbers interval.
* E.g., if you have pageId=5 and delta=2, it will return (3, 7).
* PageID of 9 would give you (4, 8).
* If the method is called without parameter, pageID is set to currentPage#.
*
* @param integer PageID to get offsets for
* @return array First and last offsets
* @access public
*/
function getPageRangeByPageId($pageid = null)
{
$pageid = isset($pageid) ? (int)$pageid : $this->_currentPage;
if (!isset($this->_pageData)) {
$this->_generatePageData();
}
if (isset($this->_pageData[$pageid]) || is_null($this->_itemData)) {
if ($this->_expanded) {
$min_surplus = ($pageid <= $this->_delta) ? ($this->_delta - $pageid + 1) : 0;
$max_surplus = ($pageid >= ($this->_totalPages - $this->_delta)) ?
($pageid - ($this->_totalPages - $this->_delta)) : 0;
} else {
$min_surplus = $max_surplus = 0;
}
return array(
max($pageid - $this->_delta - $max_surplus, 1),
min($pageid + $this->_delta + $min_surplus, $this->_totalPages)
);
}
return array(0, 0);
}
 
// }}}
// {{{ getLinks()
 
/**
* Returns back/next/first/last and page links,
* both as ordered and associative array.
*
* @param integer $pageID Optional pageID. If specified, links
* for that page are provided instead of current one.
* @return array back/pages/next/first/last/all links
* @access public
*/
function getLinks($pageID = null)
{
if ($pageID != null) {
$_sav = $this->_currentPage;
$this->_currentPage = $pageID;
 
$this->links = '';
if ($this->_totalPages > (2 * $this->_delta + 1)) {
$this->links .= $this->_printFirstPage();
}
$this->links .= $this->_getBackLink();
$this->links .= $this->_getPageLinks();
$this->links .= $this->_getNextLink();
if ($this->_totalPages > (2 * $this->_delta + 1)) {
$this->links .= $this->_printLastPage();
}
}
 
$back = str_replace('&nbsp;', '', $this->_getBackLink());
$next = str_replace('&nbsp;', '', $this->_getNextLink());
$pages = $this->_getPageLinks();
$first = $this->_printFirstPage();
$last = $this->_printLastPage();
$all = $this->links;
$linkTags = $this->linkTags;
 
if ($pageID != null) {
$this->_currentPage = $_sav;
}
 
return array(
$back,
$pages,
trim($next),
$first,
$last,
$all,
$linkTags,
'back' => $back,
'pages' => $pages,
'next' => $next,
'first' => $first,
'last' => $last,
'all' => $all,
'linktags' => $linkTags
);
}
 
// }}}
// {{{ _getPageLinks()
 
/**
* Returns pages link
*
* @return string Links
* @access private
*/
function _getPageLinks($url = '')
{
//legacy setting... the preferred way to set an option now
//is adding it to the constuctor
if (!empty($url)) {
$this->_path = $url;
}
//If there's only one page, don't display links
if ($this->_clearIfVoid && ($this->_totalPages < 2)) {
return '';
}
 
$links = '';
if ($this->_totalPages > (2 * $this->_delta + 1)) {
if ($this->_expanded) {
if (($this->_totalPages - $this->_delta) <= $this->_currentPage) {
$expansion_before = $this->_currentPage - ($this->_totalPages - $this->_delta);
} else {
$expansion_before = 0;
}
for ($i = $this->_currentPage - $this->_delta - $expansion_before; $expansion_before; $expansion_before--, $i++) {
$print_separator_flag = ($i != $this->_currentPage + $this->_delta); // && ($i != $this->_totalPages - 1)
$this->range[$i] = false;
$this->_linkData[$this->_urlVar] = $i;
$links .= $this->_renderLink($this->_altPage.' '.$i, $i)
. $this->_spacesBefore
. ($print_separator_flag ? $this->_separator.$this->_spacesAfter : '');
}
}
 
$expansion_after = 0;
for ($i = $this->_currentPage - $this->_delta; ($i <= $this->_currentPage + $this->_delta) && ($i <= $this->_totalPages); $i++) {
if ($i < 1) {
++$expansion_after;
continue;
}
 
// check when to print separator
$print_separator_flag = (($i != $this->_currentPage + $this->_delta) && ($i != $this->_totalPages));
 
if ($i == $this->_currentPage) {
$this->range[$i] = true;
$links .= $this->_curPageSpanPre . $i . $this->_curPageSpanPost;
} else {
$this->range[$i] = false;
$this->_linkData[$this->_urlVar] = $i;
$links .= $this->_renderLink($this->_altPage.' '.$i, $i);
}
$links .= $this->_spacesBefore
. ($print_separator_flag ? $this->_separator.$this->_spacesAfter : '');
}
 
if ($this->_expanded && $expansion_after) {
$links .= $this->_separator . $this->_spacesAfter;
for ($i = $this->_currentPage + $this->_delta +1; $expansion_after; $expansion_after--, $i++) {
$print_separator_flag = ($expansion_after != 1);
$this->range[$i] = false;
$this->_linkData[$this->_urlVar] = $i;
$links .= $this->_renderLink($this->_altPage.' '.$i, $i)
. $this->_spacesBefore
. ($print_separator_flag ? $this->_separator.$this->_spacesAfter : '');
}
}
 
} else {
//if $this->_totalPages <= (2*Delta+1) show them all
for ($i=1; $i<=$this->_totalPages; $i++) {
if ($i != $this->_currentPage) {
$this->range[$i] = false;
$this->_linkData[$this->_urlVar] = $i;
$links .= $this->_renderLink($this->_altPage.' '.$i, $i);
} else {
$this->range[$i] = true;
$links .= $this->_curPageSpanPre . $i . $this->_curPageSpanPost;
}
$links .= $this->_spacesBefore
. (($i != $this->_totalPages) ? $this->_separator.$this->_spacesAfter : '');
}
}
return $links;
}
 
// }}}
}
?>
/branches/v1.0-menes/api/pear/Pager/HtmlWidgets.php
New file
0,0 → 1,217
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Contains the Pager_HtmlWidgets class
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 FREEBSD PROJECT 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 HTML
* @package Pager
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @copyright 2003-2006 Lorenzo Alberton
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Pager
*/
 
/**
* Two constants used to guess the path- and file-name of the page
* when the user doesn't set any other value
*/
class Pager_HtmlWidgets
{
var $pager = null;
// {{{ constructor
function Pager_HtmlWidgets(&$pager)
{
$this->pager =& $pager;
}
// }}}
// {{{ getPerPageSelectBox()
 
/**
* Returns a string with a XHTML SELECT menu,
* useful for letting the user choose how many items per page should be
* displayed. If parameter useSessions is TRUE, this value is stored in
* a session var. The string isn't echoed right now so you can use it
* with template engines.
*
* @param integer $start
* @param integer $end
* @param integer $step
* @param boolean $showAllData If true, perPage is set equal to totalItems.
* @param array (or string $optionText for BC reasons)
* - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'attributes': (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* <select> tag
* @return string xhtml select box
* @access public
*/
function getPerPageSelectBox($start=5, $end=30, $step=5, $showAllData=false, $extraParams=array())
{
// FIXME: needs POST support
$optionText = '%d';
$attributes = '';
if (is_string($extraParams)) {
//old behavior, BC maintained
$optionText = $extraParams;
} else {
if (array_key_exists('optionText', $extraParams)) {
$optionText = $extraParams['optionText'];
}
if (array_key_exists('attributes', $extraParams)) {
$attributes = $extraParams['attributes'];
}
}
 
if (!strstr($optionText, '%d')) {
return $this->pager->raiseError(
$this->pager->errorMessage(ERROR_PAGER_INVALID_PLACEHOLDER),
ERROR_PAGER_INVALID_PLACEHOLDER
);
}
$start = (int)$start;
$end = (int)$end;
$step = (int)$step;
if (!empty($_SESSION[$this->pager->_sessionVar])) {
$selected = (int)$_SESSION[$this->pager->_sessionVar];
} else {
$selected = $this->pager->_perPage;
}
 
$tmp = '<select name="'.$this->pager->_sessionVar.'"';
if (!empty($attributes)) {
$tmp .= ' '.$attributes;
}
$tmp .= '>';
for ($i=$start; $i<=$end; $i+=$step) {
$tmp .= '<option value="'.$i.'"';
if ($i == $selected) {
$tmp .= ' selected="selected"';
}
$tmp .= '>'.sprintf($optionText, $i).'</option>';
}
if ($showAllData && $end < $this->pager->_totalItems) {
$tmp .= '<option value="'.$this->pager->_totalItems.'"';
if ($this->pager->_totalItems == $selected) {
$tmp .= ' selected="selected"';
}
$tmp .= '>';
if (empty($this->pager->_showAllText)) {
$tmp .= str_replace('%d', $this->pager->_totalItems, $optionText);
} else {
$tmp .= $this->pager->_showAllText;
}
$tmp .= '</option>';
}
$tmp .= '</select>';
return $tmp;
}
 
// }}}
// {{{ getPageSelectBox()
 
/**
* Returns a string with a XHTML SELECT menu with the page numbers,
* useful as an alternative to the links
*
* @param array - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'autoSubmit': if TRUE, add some js code to submit the
* form on the onChange event
* @param string $extraAttributes (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* <select> tag
* @return string xhtml select box
* @access public
*/
function getPageSelectBox($params = array(), $extraAttributes = '')
{
$optionText = '%d';
if (array_key_exists('optionText', $params)) {
$optionText = $params['optionText'];
}
 
if (!strstr($optionText, '%d')) {
return $this->pager->raiseError(
$this->pager->errorMessage(ERROR_PAGER_INVALID_PLACEHOLDER),
ERROR_PAGER_INVALID_PLACEHOLDER
);
}
$tmp = '<select name="'.$this->pager->_urlVar.'"';
if (!empty($extraAttributes)) {
$tmp .= ' '.$extraAttributes;
}
if (!empty($params['autoSubmit'])) {
if ($this->pager->_httpMethod == 'GET') {
$selector = '\' + '.'this.options[this.selectedIndex].value + \'';
if ($this->pager->_append) {
$href = '?' . $this->pager->_http_build_query_wrapper($this->pager->_linkData);
$href = htmlentities($this->pager->_url). preg_replace(
'/(&|&amp;|\?)('.$this->pager->_urlVar.'=)(\d+)/',
'\\1\\2'.$selector,
htmlentities($href)
);
} else {
$href = htmlentities($this->pager->_url . str_replace('%d', $selector, $this->pager->_fileName));
}
$tmp .= ' onchange="document.location.href=\''
. $href .'\''
. '"';
} elseif ($this->pager->_httpMethod == 'POST') {
$tmp .= " onchange='"
. $this->pager->_generateFormOnClick($this->pager->_url, $this->pager->_linkData)
. "'";
$tmp = preg_replace(
'/(input\.name = \"'.$this->pager->_urlVar.'\"; input\.value =) \"(\d+)\";/',
'\\1 this.options[this.selectedIndex].value;',
$tmp
);
}
}
$tmp .= '>';
$start = 1;
$end = $this->pager->numPages();
$selected = $this->pager->getCurrentPageID();
for ($i=$start; $i<=$end; $i++) {
$tmp .= '<option value="'.$i.'"';
if ($i == $selected) {
$tmp .= ' selected="selected"';
}
$tmp .= '>'.sprintf($optionText, $i).'</option>';
}
$tmp .= '</select>';
return $tmp;
}
// }}}
}
?>
/branches/v1.0-menes/api/pear/XML/Tree/Node.php
New file
0,0 → 1,354
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Bernd Römer <berndr@bonn.edu> |
// | Sebastian Bergmann <sb@sebastian-bergmann.de> |
// | Christian Kühn <ck@chkuehn.de> (escape xml entities) |
// +----------------------------------------------------------------------+
//
// $Id: Node.php,v 1.1 2005-04-18 16:13:31 jpm Exp $
//
 
/**
* PEAR::XML_Tree_Node
*
* @author Bernd Römer <berndr@bonn.edu>
* @package XML_Tree
* @version 1.0 16-Aug-2001
*/
class XML_Tree_Node {
/**
* Attributes of this node
*
* @var array
*/
var $attributes;
 
/**
* Children of this node
*
* @var array
*/
var $children;
 
/**
* Content
*
* @var string
*/
var $content;
 
/**
* Name
*
* @var string
*/
var $name;
 
/**
* Constructor
*
* @param string name
* @param string content
* @param array attributes
*/
function XML_Tree_Node($name, $content = '', $attributes = array()) {
$this->attributes = $attributes;
$this->children = array();
$this->set_content($content);
$this->name = $name;
}
 
/**
* Adds a child node to this node.
*
* @param mixed child
* @param string content
* @param array attributes
* @return object reference to new child node
*/
function &addChild($child, $content = '', $attributes = array()) {
$index = sizeof($this->children);
 
if (is_object($child)) {
if (strtolower(get_class($child)) == 'xml_tree_node') {
$this->children[$index] = $child;
}
 
if (strtolower(get_class($child)) == 'xml_tree' && isset($child->root)) {
$this->children[$index] = $child->root->get_element();
}
} else {
$this->children[$index] = new XML_Tree_Node($child, $content, $attributes);
}
 
return $this->children[$index];
}
 
/**
* @deprecated
*/
function &add_child($child, $content = '', $attributes = array()) {
return $this->addChild($child, $content, $attributes);
}
 
/**
* clone node and all its children (recursive)
*
* @return object reference to the clone-node
*/
function &clone() {
$clone=new XML_Tree_Node($this->name,$this->content,$this->attributes);
 
$max_child=count($this->children);
for($i=0;$i<$max_child;$i++) {
$clone->children[]=$this->children[$i]->clone();
}
 
/* for future use....
// clone all other vars
$temp=get_object_vars($this);
foreach($temp as $varname => $value)
if (!in_array($varname,array('name','content','attributes','children')))
$clone->$varname=$value;
*/
 
return($clone);
}
 
/**
* inserts child ($child) to a specified child-position ($pos)
*
* @return inserted node
*/
function &insertChild($path,$pos,&$child, $content = '', $attributes = array()) {
// direct insert of objects useing array_splice() faild :(
array_splice($this->children,$pos,0,'dummy');
if (is_object($child)) { // child offered is not instanziated
// insert a single node
if (strtolower(get_class($child)) == 'xml_tree_node') {
$this->children[$pos]=&$child;
}
// insert a tree i.e insert root-element
if (strtolower(get_class($child)) == 'xml_tree' && isset($child->root)) {
$this->children[$pos]=$child->root->get_element();
}
} else { // child offered is not instanziated
$this->children[$pos]=new XML_Tree_Node($child, $content, $attributes);
}
return($this);
}
 
/**
* @deprecated
*/
function &insert_child($path,$pos,&$child, $content = '', $attributes = array()) {
return $this->insertChild($path,$pos,$child, $content, $attributes);
}
 
/**
* removes child ($pos)
*
* @param integer pos position of child in children-list
*
* @return removed node
*/
function &removeChild($pos) {
// array_splice() instead of a simple unset() to maintain index-integrity
return(array_splice($this->children,$pos,1));
}
 
/**
* @deprecated
*/
function &remove_child($pos) {
return $this->removeChild($pos);
}
 
/**
* Returns text representation of this node.
*
* @return string xml
*/
function &get()
{
static $deep = -1;
static $do_ident = true;
$deep++;
if ($this->name !== null) {
$ident = str_repeat(' ', $deep);
if ($do_ident) {
$out = $ident . '<' . $this->name;
} else {
$out = '<' . $this->name;
}
foreach ($this->attributes as $name => $value) {
$out .= ' ' . $name . '="' . $value . '"';
}
 
$out .= '>' . $this->content;
 
if (sizeof($this->children) > 0) {
$out .= "\n";
foreach ($this->children as $child) {
$out .= $child->get();
}
} else {
$ident = '';
}
if ($do_ident) {
$out .= $ident . '</' . $this->name . ">\n";
} else {
$out .= '</' . $this->name . '>';
}
$do_ident = true;
} else {
$out = $this->content;
$do_ident = false;
}
$deep--;
return $out;
}
 
/**
* Gets an attribute by its name.
*
* @param string name
* @return string attribute
*/
function getAttribute($name) {
return $this->attributes[strtolower($name)];
}
 
/**
* @deprecated
*/
function get_attribute($name) {
return $this->getAttribute($name);
}
 
/**
* Gets an element by its 'path'.
*
* @param string path
* @return object element
*/
function &getElement($path) {
if (sizeof($path) == 0) {
return $this;
}
 
$next = array_shift($path);
 
return $this->children[$next]->get_element($path);
}
 
/**
* @deprecated
*/
function &get_element($path) {
return $this->getElement($path);
}
 
/**
* Sets an attribute.
*
* @param string name
* @param string value
*/
function setAttribute($name, $value = '') {
$this->attributes[strtolower($name)] = $value;
}
 
/**
* @deprecated
*/
function set_attribute($name, $value = '') {
return $this->setAttribute($name, $value);
}
 
/**
* Unsets an attribute.
*
* @param string name
*/
function unsetAttribute($name) {
unset($this->attributes[strtolower($name)]);
}
 
/**
* @deprecated
*/
function unset_attribute($name) {
return $this->unsetAttribute($name);
}
 
/**
*
*
*/
function setContent(&$content)
{
$this->content = $this->_xml_entities($content);
}
 
function set_content(&$content)
{
return $this->setContent($content);
}
 
/**
* Escape XML entities.
*
* @param string xml
* @return string xml
* @access private
*/
function _xml_entities($xml) {
$xml = str_replace(array('ü', 'Ü', 'ö',
'Ö', 'ä', 'Ä',
'ß'
),
array('&#252;', '&#220;', '&#246;',
'&#214;', '&#228;', '&#196;',
'&#223;'
),
$xml
);
 
$xml = preg_replace(array("/\&([a-z\d\#]+)\;/i",
"/\&/",
"/\#\|\|([a-z\d\#]+)\|\|\#/i",
"/([^a-zA-Z\d\s\<\>\&\;\.\:\=\"\-\/\%\?\!\'\(\)\[\]\{\}\$\#\+\,\@_])/e"
),
array("#||\\1||#",
"&amp;",
"&\\1;",
"'&#'.ord('\\1').';'"
),
$xml
);
 
return $xml;
}
 
/**
* Print text representation of XML tree.
*/
function dump() {
echo $this->get();
}
}
?>
/branches/v1.0-menes/api/pear/XML/Parser.php
New file
0,0 → 1,684
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | 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 at through the world-wide-web at |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@fast.no> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | Stephan Schmidt <schst@php-tools.net> |
// +----------------------------------------------------------------------+
//
// $Id: Parser.php,v 1.1 2005-04-18 16:13:31 jpm Exp $
 
/**
* XML Parser class.
*
* This is an XML parser based on PHP's "xml" extension,
* based on the bundled expat library.
*
* @category XML
* @package XML_Parser
* @author Stig Bakken <ssb@fast.no>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Stephan Schmidt <schst@php-tools.net>
*/
 
/**
* uses PEAR's error handling
*/
require_once 'PEAR.php';
 
/**
* resource could not be created
*/
define('XML_PARSER_ERROR_NO_RESOURCE', 200);
 
/**
* unsupported mode
*/
define('XML_PARSER_ERROR_UNSUPPORTED_MODE', 201);
 
/**
* invalid encoding was given
*/
define('XML_PARSER_ERROR_INVALID_ENCODING', 202);
 
/**
* specified file could not be read
*/
define('XML_PARSER_ERROR_FILE_NOT_READABLE', 203);
 
/**
* invalid input
*/
define('XML_PARSER_ERROR_INVALID_INPUT', 204);
 
/**
* remote file cannot be retrieved in safe mode
*/
define('XML_PARSER_ERROR_REMOTE', 205);
 
/**
* XML Parser class.
*
* This is an XML parser based on PHP's "xml" extension,
* based on the bundled expat library.
*
* Notes:
* - It requires PHP 4.0.4pl1 or greater
* - From revision 1.17, the function names used by the 'func' mode
* are in the format "xmltag_$elem", for example: use "xmltag_name"
* to handle the <name></name> tags of your xml file.
*
* @category XML
* @package XML_Parser
* @author Stig Bakken <ssb@fast.no>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Stephan Schmidt <schst@php-tools.net>
* @todo create XML_Parser_Namespace to parse documents with namespaces
* @todo create XML_Parser_Pull
* @todo Tests that need to be made:
* - mixing character encodings
* - a test using all expat handlers
* - options (folding, output charset)
* - different parsing modes
*/
class XML_Parser extends PEAR
{
// {{{ properties
 
/**
* XML parser handle
*
* @var resource
* @see xml_parser_create()
*/
var $parser;
 
/**
* File handle if parsing from a file
*
* @var resource
*/
var $fp;
 
/**
* Whether to do case folding
*
* If set to true, all tag and attribute names will
* be converted to UPPER CASE.
*
* @var boolean
*/
var $folding = true;
 
/**
* Mode of operation, one of "event" or "func"
*
* @var string
*/
var $mode;
 
/**
* Mapping from expat handler function to class method.
*
* @var array
*/
var $handler = array(
'character_data_handler' => 'cdataHandler',
'default_handler' => 'defaultHandler',
'processing_instruction_handler' => 'piHandler',
'unparsed_entity_decl_handler' => 'unparsedHandler',
'notation_decl_handler' => 'notationHandler',
'external_entity_ref_handler' => 'entityrefHandler'
);
 
/**
* source encoding
*
* @var string
*/
var $srcenc;
 
/**
* target encoding
*
* @var string
*/
var $tgtenc;
 
/**
* handler object
*
* @var object
*/
var $_handlerObj;
 
// }}}
// {{{ constructor
 
/**
* Creates an XML parser.
*
* This is needed for PHP4 compatibility, it will
* call the constructor, when a new instance is created.
*
* @param string $srcenc source charset encoding, use NULL (default) to use
* whatever the document specifies
* @param string $mode how this parser object should work, "event" for
* startelement/endelement-type events, "func"
* to have it call functions named after elements
* @param string $tgenc a valid target encoding
*/
function XML_Parser($srcenc = null, $mode = 'event', $tgtenc = null)
{
XML_Parser::__construct($srcenc, $mode, $tgtenc);
}
// }}}
 
/**
* PHP5 constructor
*
* @param string $srcenc source charset encoding, use NULL (default) to use
* whatever the document specifies
* @param string $mode how this parser object should work, "event" for
* startelement/endelement-type events, "func"
* to have it call functions named after elements
* @param string $tgenc a valid target encoding
*/
function __construct($srcenc = null, $mode = 'event', $tgtenc = null)
{
$this->PEAR('XML_Parser_Error');
 
$this->mode = $mode;
$this->srcenc = $srcenc;
$this->tgtenc = $tgtenc;
}
// }}}
 
/**
* Sets the mode of the parser.
*
* Possible modes are:
* - func
* - event
*
* You can set the mode using the second parameter
* in the constructor.
*
* This method is only needed, when switching to a new
* mode at a later point.
*
* @access public
* @param string mode, either 'func' or 'event'
* @return boolean|object true on success, PEAR_Error otherwise
*/
function setMode($mode)
{
if ($mode != 'func' && $mode != 'event') {
$this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE);
}
 
$this->mode = $mode;
return true;
}
 
/**
* Sets the object, that will handle the XML events
*
* This allows you to create a handler object independent of the
* parser object that you are using and easily switch the underlying
* parser.
*
* If no object will be set, XML_Parser assumes that you
* extend this class and handle the events in $this.
*
* @access public
* @param object object to handle the events
* @return boolean will always return true
* @since v1.2.0beta3
*/
function setHandlerObj(&$obj)
{
$this->_handlerObj = &$obj;
return true;
}
 
/**
* Init the element handlers
*
* @access private
*/
function _initHandlers()
{
if (!is_resource($this->parser)) {
return false;
}
 
if (!is_object($this->_handlerObj)) {
$this->_handlerObj = &$this;
}
switch ($this->mode) {
 
case 'func':
xml_set_object($this->parser, $this->_handlerObj);
xml_set_element_handler($this->parser, array(&$this, 'funcStartHandler'), array(&$this, 'funcEndHandler'));
break;
 
case 'event':
xml_set_object($this->parser, $this->_handlerObj);
xml_set_element_handler($this->parser, 'startHandler', 'endHandler');
break;
default:
return $this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE);
break;
}
 
 
/**
* set additional handlers for character data, entities, etc.
*/
foreach ($this->handler as $xml_func => $method) {
if (method_exists($this->_handlerObj, $method)) {
$xml_func = 'xml_set_' . $xml_func;
$xml_func($this->parser, $method);
}
}
}
 
// {{{ _create()
 
/**
* create the XML parser resource
*
* Has been moved from the constructor to avoid
* problems with object references.
*
* Furthermore it allows us returning an error
* if something fails.
*
* @access private
* @return boolean|object true on success, PEAR_Error otherwise
*
* @see xml_parser_create
*/
function _create()
{
if ($this->srcenc === null) {
$xp = @xml_parser_create();
} else {
$xp = @xml_parser_create($this->srcenc);
}
if (is_resource($xp)) {
if ($this->tgtenc !== null) {
if (!@xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING,
$this->tgtenc)) {
return $this->raiseError('invalid target encoding', XML_PARSER_ERROR_INVALID_ENCODING);
}
}
$this->parser = $xp;
$result = $this->_initHandlers($this->mode);
if ($this->isError($result)) {
return $result;
}
xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, $this->folding);
 
return true;
}
return $this->raiseError('Unable to create XML parser resource.', XML_PARSER_ERROR_NO_RESOURCE);
}
 
// }}}
// {{{ reset()
 
/**
* Reset the parser.
*
* This allows you to use one parser instance
* to parse multiple XML documents.
*
* @access public
* @return boolean|object true on success, PEAR_Error otherwise
*/
function reset()
{
$result = $this->_create();
if ($this->isError( $result )) {
return $result;
}
return true;
}
 
// }}}
// {{{ setInputFile()
 
/**
* Sets the input xml file to be parsed
*
* @param string Filename (full path)
* @return resource fopen handle of the given file
* @throws XML_Parser_Error
* @see setInput(), setInputString(), parse()
* @access public
*/
function setInputFile($file)
{
/**
* check, if file is a remote file
*/
if (eregi('^(http|ftp)://', substr($file, 0, 10))) {
if (!ini_get('allow_url_fopen')) {
return $this->raiseError('Remote files cannot be parsed, as safe mode is enabled.', XML_PARSER_ERROR_REMOTE);
}
}
$fp = @fopen($file, 'rb');
if (is_resource($fp)) {
$this->fp = $fp;
return $fp;
}
return $this->raiseError('File could not be opened.', XML_PARSER_ERROR_FILE_NOT_READABLE);
}
 
// }}}
// {{{ setInputString()
/**
* XML_Parser::setInputString()
*
* Sets the xml input from a string
*
* @param string $data a string containing the XML document
* @return null
**/
function setInputString($data)
{
$this->fp = $data;
return null;
}
// }}}
// {{{ setInput()
 
/**
* Sets the file handle to use with parse().
*
* You should use setInputFile() or setInputString() if you
* pass a string
*
* @param mixed $fp Can be either a resource returned from fopen(),
* a URL, a local filename or a string.
* @access public
* @see parse()
* @uses setInputString(), setInputFile()
*/
function setInput($fp)
{
if (is_resource($fp)) {
$this->fp = $fp;
return true;
}
// see if it's an absolute URL (has a scheme at the beginning)
elseif (eregi('^[a-z]+://', substr($fp, 0, 10))) {
return $this->setInputFile($fp);
}
// see if it's a local file
elseif (file_exists($fp)) {
return $this->setInputFile($fp);
}
// it must be a string
else {
$this->fp = $fp;
return true;
}
 
return $this->raiseError('Illegal input format', XML_PARSER_ERROR_INVALID_INPUT);
}
 
// }}}
// {{{ parse()
 
/**
* Central parsing function.
*
* @return true|object PEAR error returns true on success, or a PEAR_Error otherwise
* @access public
*/
function parse()
{
/**
* reset the parser
*/
$result = $this->reset();
if ($this->isError($result)) {
return $result;
}
// if $this->fp was fopened previously
if (is_resource($this->fp)) {
while ($data = fread($this->fp, 4096)) {
if (!$this->_parseString($data, feof($this->fp))) {
$error = &$this->raiseError();
$this->free();
return $error;
}
}
// otherwise, $this->fp must be a string
} else {
if (!$this->_parseString($this->fp, true)) {
$error = &$this->raiseError();
$this->free();
return $error;
}
}
$this->free();
 
return true;
}
 
/**
* XML_Parser::_parseString()
*
* @param string $data
* @param boolean $eof
* @return bool
* @access private
* @see parseString()
**/
function _parseString($data, $eof = false)
{
return xml_parse($this->parser, $data, $eof);
}
// }}}
// {{{ parseString()
 
/**
* XML_Parser::parseString()
*
* Parses a string.
*
* @param string $data XML data
* @param boolean $eof If set and TRUE, data is the last piece of data sent in this parser
* @throws XML_Parser_Error
* @return Pear Error|true true on success or a PEAR Error
* @see _parseString()
*/
function parseString($data, $eof = false)
{
if (!isset($this->parser) || !is_resource($this->parser)) {
$this->reset();
}
if (!$this->_parseString($data, $eof)) {
$error = &$this->raiseError();
$this->free();
return $error;
}
 
if ($eof === true) {
$this->free();
}
return true;
}
/**
* XML_Parser::free()
*
* Free the internal resources associated with the parser
*
* @return null
**/
function free()
{
if (isset($this->parser) && is_resource($this->parser)) {
xml_parser_free($this->parser);
unset( $this->parser );
}
if (isset($this->fp) && is_resource($this->fp)) {
fclose($this->fp);
}
unset($this->fp);
return null;
}
/**
* XML_Parser::raiseError()
*
* Throws a XML_Parser_Error
*
* @param string $msg the error message
* @param integer $ecode the error message code
* @return XML_Parser_Error
**/
function raiseError($msg = null, $ecode = 0)
{
$msg = !is_null($msg) ? $msg : $this->parser;
$err = &new XML_Parser_Error($msg, $ecode);
return parent::raiseError($err);
}
// }}}
// {{{ funcStartHandler()
 
function funcStartHandler($xp, $elem, $attribs)
{
$func = 'xmltag_' . $elem;
if (strchr($func, '.')) {
$func = str_replace('.', '_', $func);
}
if (method_exists($this->_handlerObj, $func)) {
call_user_func(array(&$this->_handlerObj, $func), $xp, $elem, $attribs);
} elseif (method_exists($this->_handlerObj, 'xmltag')) {
call_user_func(array(&$this->_handlerObj, 'xmltag'), $xp, $elem, $attribs);
}
}
 
// }}}
// {{{ funcEndHandler()
 
function funcEndHandler($xp, $elem)
{
$func = 'xmltag_' . $elem . '_';
if (strchr($func, '.')) {
$func = str_replace('.', '_', $func);
}
if (method_exists($this->_handlerObj, $func)) {
call_user_func(array(&$this->_handlerObj, $func), $xp, $elem);
} elseif (method_exists($this->_handlerObj, 'xmltag_')) {
call_user_func(array(&$this->_handlerObj, 'xmltag_'), $xp, $elem);
}
}
 
// }}}
// {{{ startHandler()
 
/**
*
* @abstract
*/
function startHandler($xp, $elem, &$attribs)
{
return NULL;
}
 
// }}}
// {{{ endHandler()
 
/**
*
* @abstract
*/
function endHandler($xp, $elem)
{
return NULL;
}
 
 
// }}}me
}
 
/**
* error class, replaces PEAR_Error
*
* An instance of this class will be returned
* if an error occurs inside XML_Parser.
*
* There are three advantages over using the standard PEAR_Error:
* - All messages will be prefixed
* - check for XML_Parser error, using is_a( $error, 'XML_Parser_Error' )
* - messages can be generated from the xml_parser resource
*
* @package XML_Parser
* @access public
* @see PEAR_Error
*/
class XML_Parser_Error extends PEAR_Error
{
// {{{ properties
 
/**
* prefix for all messages
*
* @var string
*/
var $error_message_prefix = 'XML_Parser: ';
 
// }}}
// {{{ constructor()
/**
* construct a new error instance
*
* You may either pass a message or an xml_parser resource as first
* parameter. If a resource has been passed, the last error that
* happened will be retrieved and returned.
*
* @access public
* @param string|resource message or parser resource
* @param integer error code
* @param integer error handling
* @param integer error level
*/
function XML_Parser_Error($msgorparser = 'unknown error', $code = 0, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE)
{
if (is_resource($msgorparser)) {
$code = xml_get_error_code($msgorparser);
$msgorparser = sprintf('%s at XML input line %d',
xml_error_string($code),
xml_get_current_line_number($msgorparser));
}
$this->PEAR_Error($msgorparser, $code, $mode, $level);
}
// }}}
}
?>
/branches/v1.0-menes/api/pear/XML/Tree.php
New file
0,0 → 1,370
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Bernd Römer <berndr@bonn.edu> |
// | Sebastian Bergmann <sb@sebastian-bergmann.de> |
// | Tomas V.V.Cox <cox@idecnet.com> (tree mapping from xml file)|
// +----------------------------------------------------------------------+
//
// $Id: Tree.php,v 1.1 2005-04-18 16:13:31 jpm Exp $
//
 
require_once 'XML/Parser.php';
require_once 'XML/Tree/Node.php';
 
/**
* PEAR::XML_Tree
*
* Purpose
*
* Allows for the building of XML data structures
* using a tree representation, without the need
* for an extension like DOMXML.
*
* Example
*
* $tree = new XML_Tree;
* $root =& $tree->addRoot('root');
* $foo =& $root->addChild('foo');
*
* header('Content-Type: text/xml');
* $tree->dump();
*
* @author Bernd Römer <berndr@bonn.edu>
* @package XML
* @version $Version$ - 1.0
*/
class XML_Tree extends XML_Parser
{
/**
* File Handle
*
* @var ressource
*/
var $file = NULL;
 
/**
* Filename
*
* @var string
*/
var $filename = '';
 
/**
* Namespace
*
* @var array
*/
var $namespace = array();
 
/**
* Root
*
* @var object XML_Tree_Node
*/
var $root = NULL;
 
/**
* XML Version
*
* @var string
*/
var $version = '1.0';
 
/**
* Constructor
*
* @param string Filename
* @param string XML Version
*/
function XML_Tree($filename = '', $version = '1.0') {
$this->filename = $filename;
$this->version = $version;
}
 
/**
* Add root node.
*
* @param string $name name of root element
* @return object XML_Tree_Node reference to root node
*
* @access public
*/
function &addRoot($name, $content = '', $attributes = array()) {
$this->root = new XML_Tree_Node($name, $content, $attributes);
return $this->root;
}
 
/**
* @deprecated
*/
function &add_root($name, $content = '', $attributes = array()) {
return $this->addRoot($name, $content, $attributes);
}
 
/**
* inserts a child/tree (child) into tree ($path,$pos) and
* maintains namespace integrity
*
* @param array $path path to parent of child to remove
* @param integer $pos position of child to be inserted in its parents children-list
* @param mixed $child child-node (by XML_Tree,XML_Node or Name)
* @param string $content content (text) for new node
* @param array $attributes attribute-hash for new node
*
* @return object XML_Tree_Node inserted child (node)
* @access public
*/
function &insertChild($path,$pos,$child, $content = '', $attributes = array()) {
// update namespace to maintain namespace integrity
$count=count($path);
foreach($this->namespace as $key => $val) {
if ((array_slice($val,0,$count)==$path) && ($val[$count]>=$pos))
$this->namespace[$key][$count]++;
}
 
$parent=&$this->get_node_by_path($path);
return($parent->insert_child($pos,$child,$content,$attributes));
}
 
/**
* @deprecated
*/
function &insert_child($path,$pos,$child, $content = '', $attributes = array()) {
return $this->insertChild($path, $child, $content, $attributes);
}
 
/*
* removes a child ($path,$pos) from tree ($path,$pos) and
* maintains namespace integrity
*
* @param array $path path to parent of child to remove
* @param integer $pos position of child in parents children-list
*
* @return object XML_Tree_Node parent whichs child was removed
* @access public
*/
function &removeChild($path,$pos) {
// update namespace to maintain namespace integrity
$count=count($path);
foreach($this->namespace as $key => $val) {
if (array_slice($val,0,$count)==$path) {
if ($val[$count]==$pos) { unset($this->namespace[$key]); break; }
if ($val[$count]>$pos)
$this->namespace[$key][$count]--;
}
}
 
$parent=&$this->get_node_by_path($path);
return($parent->remove_child($pos));
}
 
/**
* @deprecated
*/
function &remove_child($path, $pos) {
return $this->removeChild($path, $pos);
}
 
/*
* Maps a xml file to a objects tree
*
* @return mixed The objects tree (XML_tree or an Pear error)
* @access public
*/
function &getTreeFromFile ()
{
$this->folding = false;
$this->XML_Parser(null, 'event');
$err = $this->setInputFile($this->filename);
if (PEAR::isError($err)) {
return $err;
}
$this->cdata = null;
$err = $this->parse();
if (PEAR::isError($err)) {
return $err;
}
return $this->root;
}
 
function getTreeFromString($str)
{
$this->folding = false;
$this->XML_Parser(null, 'event');
$this->cdata = null;
$err = $this->parseString($str);
if (PEAR::isError($err)) {
return $err;
}
return $this->root;
}
 
/**
* Handler for the xml-data
*
* @param mixed $xp ignored
* @param string $elem name of the element
* @param array $attribs attributes for the generated node
*
* @access private
*/
function startHandler($xp, $elem, &$attribs)
{
// root elem
if (!isset($this->i)) {
$this->obj1 =& $this->add_root($elem, null, $attribs);
$this->i = 2;
} else {
// mixed contents
if (!empty($this->cdata)) {
$parent_id = 'obj' . ($this->i - 1);
$parent =& $this->$parent_id;
$parent->children[] = &new XML_Tree_Node(null, $this->cdata);
}
$obj_id = 'obj' . $this->i++;
$this->$obj_id = &new XML_Tree_Node($elem, null, $attribs);
}
$this->cdata = null;
return null;
}
 
/**
* Handler for the xml-data
*
* @param mixed $xp ignored
* @param string $elem name of the element
*
* @access private
*/
function endHandler($xp, $elem)
{
$this->i--;
if ($this->i > 1) {
$obj_id = 'obj' . $this->i;
// recover the node created in StartHandler
$node =& $this->$obj_id;
// mixed contents
if (count($node->children) > 0) {
if (trim($this->cdata)) {
$node->children[] = &new XML_Tree_Node(null, $this->cdata);
}
} else {
$node->set_content($this->cdata);
}
$parent_id = 'obj' . ($this->i - 1);
$parent =& $this->$parent_id;
// attach the node to its parent node children array
$parent->children[] = $node;
}
$this->cdata = null;
return null;
}
 
/*
* The xml character data handler
*
* @param mixed $xp ignored
* @param string $data PCDATA between tags
*
* @access private
*/
function cdataHandler($xp, $data)
{
if (trim($data)) {
$this->cdata .= $data;
}
}
 
/**
* Get a copy of this tree.
*
* @return object XML_Tree
* @access public
*/
function clone() {
$clone=new XML_Tree($this->filename,$this->version);
$clone->root=$this->root->clone();
 
// clone all other vars
$temp=get_object_vars($this);
foreach($temp as $varname => $value)
if (!in_array($varname,array('filename','version','root')))
$clone->$varname=$value;
 
return($clone);
}
 
/**
* Print text representation of XML tree.
*
* @access public
*/
function dump() {
echo $this->get();
}
 
/**
* Get text representation of XML tree.
*
* @return string XML
* @access public
*/
function &get() {
$out = '<?xml version="' . $this->version . "\"?>\n";
$out .= $this->root->get();
 
return $out;
}
 
/**
* Get current namespace.
*
* @param string $name namespace
* @return string
*
* @access public
*/
function &getName($name) {
return $this->root->get_element($this->namespace[$name]);
}
 
/**
* @deprecated
*/
function &get_name($name) {
return $this->getName($name);
}
 
/**
* Register a namespace.
*
* @param string $name namespace
* @param string $path path
*
* @access public
*/
function registerName($name, $path) {
$this->namespace[$name] = $path;
}
 
/**
* @deprecated
*/
function register_name($name, $path) {
return $this->registerName($name, $path);
}
}
?>
/branches/v1.0-menes/api/pear/XML/Parser/Simple.php
New file
0,0 → 1,297
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | 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 at through the world-wide-web at |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stephan Schmidt <schst@php-tools.net> |
// +----------------------------------------------------------------------+
//
// $Id: Simple.php,v 1.1 2005-04-18 16:13:31 jpm Exp $
 
/**
* Simple XML parser class.
*
* This class is a simplified version of XML_Parser.
* In most XML applications the real action is executed,
* when a closing tag is found.
*
* XML_Parser_Simple allows you to just implement one callback
* for each tag that will receive the tag with its attributes
* and CData
*
* @category XML
* @package XML_Parser
* @author Stephan Schmidt <schst@php-tools.net>
*/
 
/**
* built on XML_Parser
*/
require_once 'XML/Parser.php';
 
/**
* Simple XML parser class.
*
* This class is a simplified version of XML_Parser.
* In most XML applications the real action is executed,
* when a closing tag is found.
*
* XML_Parser_Simple allows you to just implement one callback
* for each tag that will receive the tag with its attributes
* and CData.
*
* <code>
* require_once '../Parser/Simple.php';
*
* class myParser extends XML_Parser_Simple
* {
* function myParser()
* {
* $this->XML_Parser_Simple();
* }
*
* function handleElement($name, $attribs, $data)
* {
* printf('handle %s<br>', $name);
* }
* }
*
* $p = &new myParser();
*
* $result = $p->setInputFile('myDoc.xml');
* $result = $p->parse();
* </code>
*
* @category XML
* @package XML_Parser
* @author Stephan Schmidt <schst@php-tools.net>
*/
class XML_Parser_Simple extends XML_Parser
{
/**
* element stack
*
* @access private
* @var array
*/
var $_elStack = array();
 
/**
* all character data
*
* @access private
* @var array
*/
var $_data = array();
 
/**
* element depth
*
* @access private
* @var integer
*/
var $_depth = 0;
 
/**
* Mapping from expat handler function to class method.
*
* @var array
*/
var $handler = array(
'default_handler' => 'defaultHandler',
'processing_instruction_handler' => 'piHandler',
'unparsed_entity_decl_handler' => 'unparsedHandler',
'notation_decl_handler' => 'notationHandler',
'external_entity_ref_handler' => 'entityrefHandler'
);
/**
* Creates an XML parser.
*
* This is needed for PHP4 compatibility, it will
* call the constructor, when a new instance is created.
*
* @param string $srcenc source charset encoding, use NULL (default) to use
* whatever the document specifies
* @param string $mode how this parser object should work, "event" for
* handleElement(), "func" to have it call functions
* named after elements (handleElement_$name())
* @param string $tgenc a valid target encoding
*/
function XML_Parser_Simple($srcenc = null, $mode = 'event', $tgtenc = null)
{
$this->XML_Parser($srcenc, $mode, $tgtenc);
}
 
/**
* inits the handlers
*
* @access private
*/
function _initHandlers()
{
if (!is_object($this->_handlerObj)) {
$this->_handlerObj = &$this;
}
 
if ($this->mode != 'func' && $this->mode != 'event') {
return $this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE);
}
xml_set_object($this->parser, $this->_handlerObj);
 
xml_set_element_handler($this->parser, array(&$this, 'startHandler'), array(&$this, 'endHandler'));
xml_set_character_data_handler($this->parser, array(&$this, 'cdataHandler'));
/**
* set additional handlers for character data, entities, etc.
*/
foreach ($this->handler as $xml_func => $method) {
if (method_exists($this->_handlerObj, $method)) {
$xml_func = 'xml_set_' . $xml_func;
$xml_func($this->parser, $method);
}
}
}
 
/**
* Reset the parser.
*
* This allows you to use one parser instance
* to parse multiple XML documents.
*
* @access public
* @return boolean|object true on success, PEAR_Error otherwise
*/
function reset()
{
$this->_elStack = array();
$this->_data = array();
$this->_depth = 0;
$result = $this->_create();
if ($this->isError( $result )) {
return $result;
}
return true;
}
 
/**
* start handler
*
* Pushes attributes and tagname onto a stack
*
* @access private
* @final
* @param resource xml parser resource
* @param string element name
* @param array attributes
*/
function startHandler($xp, $elem, &$attribs)
{
array_push($this->_elStack, array(
'name' => $elem,
'attribs' => $attribs
)
);
$this->_depth++;
$this->_data[$this->_depth] = '';
}
 
/**
* end handler
*
* Pulls attributes and tagname from a stack
*
* @access private
* @final
* @param resource xml parser resource
* @param string element name
*/
function endHandler($xp, $elem)
{
$el = array_pop($this->_elStack);
$data = $this->_data[$this->_depth];
$this->_depth--;
 
switch ($this->mode) {
case 'event':
$this->_handlerObj->handleElement($el['name'], $el['attribs'], $data);
break;
case 'func':
$func = 'handleElement_' . $elem;
if (strchr($func, '.')) {
$func = str_replace('.', '_', $func);
}
if (method_exists($this->_handlerObj, $func)) {
call_user_func(array(&$this->_handlerObj, $func), $el['name'], $el['attribs'], $data);
}
break;
}
}
 
/**
* handle character data
*
* @access private
* @final
* @param resource xml parser resource
* @param string data
*/
function cdataHandler($xp, $data)
{
$this->_data[$this->_depth] .= $data;
}
 
/**
* handle a tag
*
* Implement this in your parser
*
* @access public
* @abstract
* @param string element name
* @param array attributes
* @param string character data
*/
function handleElement($name, $attribs, $data)
{
}
 
/**
* get the current tag depth
*
* The root tag is in depth 0.
*
* @access public
* @return integer
*/
function getCurrentDepth()
{
return $this->_depth;
}
 
/**
* add some string to the current ddata.
*
* This is commonly needed, when a document is parsed recursively.
*
* @access public
* @param string data to add
* @return void
*/
function addToData( $data )
{
$this->_data[$this->_depth] .= $data;
}
}
?>
/branches/v1.0-menes/api/pear/XML/RSS.php
New file
0,0 → 1,359
<?php
// vim: set expandtab tabstop=4 shiftwidth=4 fdm=marker:
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Martin Jansen <mj@php.net> |
// | |
// +----------------------------------------------------------------------+
//
// $Id: RSS.php,v 1.1 2005-04-18 16:13:31 jpm Exp $
//
 
require_once 'XML/Parser.php';
 
/**
* RSS parser class.
*
* This class is a parser for Resource Description Framework (RDF) Site
* Summary (RSS) documents. For more information on RSS see the
* website of the RSS working group (http://www.purl.org/rss/).
*
* @author Martin Jansen <mj@php.net>
* @version $Revision: 1.1 $
* @access public
*/
class XML_RSS extends XML_Parser
{
// {{{ properties
 
/**
* @var string
*/
var $insideTag = '';
 
/**
* @var string
*/
var $activeTag = '';
 
/**
* @var array
*/
var $channel = array();
 
/**
* @var array
*/
var $items = array();
 
/**
* @var array
*/
var $item = array();
 
/**
* @var array
*/
var $image = array();
 
/**
* @var array
*/
var $textinput = array();
/**
* @var array
*/
var $textinputs = array();
 
/**
* @var array
*/
var $parentTags = array('CHANNEL', 'ITEM', 'IMAGE', 'TEXTINPUT');
 
/**
* @var array
*/
var $channelTags = array('TITLE', 'LINK', 'DESCRIPTION', 'IMAGE',
'ITEMS', 'TEXTINPUT');
 
/**
* @var array
*/
var $itemTags = array('TITLE', 'LINK', 'DESCRIPTION', 'PUBDATE');
 
/**
* @var array
*/
var $imageTags = array('TITLE', 'URL', 'LINK');
 
var $textinputTags = array('TITLE', 'DESCRIPTION', 'NAME', 'LINK');
 
/**
* List of allowed module tags
*
* Currently Dublin Core Metadata and the blogChannel RSS module
* are supported.
*
* @var array
*/
var $moduleTags = array('DC:TITLE', 'DC:CREATOR', 'DC:SUBJECT', 'DC:DESCRIPTION',
'DC:PUBLISHER', 'DC:CONTRIBUTOR', 'DC:DATE', 'DC:TYPE',
'DC:FORMAT', 'DC:IDENTIFIER', 'DC:SOURCE', 'DC:LANGUAGE',
'DC:RELATION', 'DC:COVERAGE', 'DC:RIGHTS',
'BLOGCHANNEL:BLOGROLL', 'BLOGCHANNEL:MYSUBSCRIPTIONS',
'BLOGCHANNEL:MYSUBSCRIPTIONS', 'BLOGCHANNEL:CHANGES');
 
// }}}
// {{{ Constructor
 
/**
* Constructor
*
* @access public
* @param mixed File pointer or name of the RDF file.
* @return void
*/
function XML_RSS($handle = '')
{
$this->XML_Parser();
 
if (@is_resource($handle)) {
$this->setInput($handle);
} elseif ($handle != '') {
$this->setInputFile($handle);
} else {
$this->raiseError('No filename passed.');
}
}
 
// }}}
// {{{ startHandler()
 
/**
* Start element handler for XML parser
*
* @access private
* @param object XML parser object
* @param string XML element
* @param array Attributes of XML tag
* @return void
*/
function startHandler($parser, $element, $attribs)
{
switch ($element) {
case 'CHANNEL':
case 'ITEM':
case 'IMAGE':
case 'TEXTINPUT':
$this->insideTag = $element;
break;
 
default:
$this->activeTag = $element;
}
}
 
// }}}
// {{{ endHandler()
 
/**
* End element handler for XML parser
*
* If the end of <item>, <channel>, <image> or <textinput>
* is reached, this function updates the structure array
* $this->struct[] and adds the field "type" to this array,
* that defines the type of the current field.
*
* @access private
* @param object XML parser object
* @param string
* @return void
*/
function endHandler($parser, $element)
{
if ($element == $this->insideTag) {
$this->insideTag = '';
$this->struct[] = array_merge(array('type' => strtolower($element)),
$this->last);
}
 
if ($element == 'ITEM') {
$this->items[] = $this->item;
$this->item = '';
}
 
if ($element == 'IMAGE') {
$this->images[] = $this->image;
$this->image = '';
}
 
if ($element == 'TEXTINPUT') {
$this->textinputs = $this->textinput;
$this->textinput = '';
}
 
$this->activeTag = '';
}
 
// }}}
// {{{ cdataHandler()
 
/**
* Handler for character data
*
* @access private
* @param object XML parser object
* @param string CDATA
* @return void
*/
function cdataHandler($parser, $cdata)
{
if (in_array($this->insideTag, $this->parentTags)) {
$tagName = strtolower($this->insideTag);
$var = $this->{$tagName . 'Tags'};
 
if (in_array($this->activeTag, $var) ||
in_array($this->activeTag, $this->moduleTags)) {
$this->_add($tagName, strtolower($this->activeTag),
$cdata);
}
}
}
 
// }}}
// {{{ defaultHandler()
 
/**
* Default handler for XML parser
*
* @access private
* @param object XML parser object
* @param string CDATA
* @return void
*/
function defaultHandler($parser, $cdata)
{
return;
}
 
// }}}
// {{{ _add()
 
/**
* Add element to internal result sets
*
* @access private
* @param string Name of the result set
* @param string Fieldname
* @param string Value
* @return void
* @see cdataHandler
*/
function _add($type, $field, $value)
{
if (empty($this->{$type}) || empty($this->{$type}[$field])) {
$this->{$type}[$field] = $value;
} else {
$this->{$type}[$field] .= $value;
}
 
$this->last = $this->{$type};
}
 
// }}}
// {{{ getStructure()
 
/**
* Get complete structure of RSS file
*
* @access public
* @return array
*/
function getStructure()
{
return (array)$this->struct;
}
 
// }}}
// {{{ getchannelInfo()
 
/**
* Get general information about current channel
*
* This function returns an array containing the information
* that has been extracted from the <channel>-tag while parsing
* the RSS file.
*
* @access public
* @return array
*/
function getChannelInfo()
{
return (array)$this->channel;
}
 
// }}}
// {{{ getItems()
 
/**
* Get items from RSS file
*
* This function returns an array containing the set of items
* that are provided by the RSS file.
*
* @access public
* @return array
*/
function getItems()
{
return (array)$this->items;
}
 
// }}}
// {{{ getImages()
 
/**
* Get images from RSS file
*
* This function returns an array containing the set of images
* that are provided by the RSS file.
*
* @access public
* @return array
*/
function getImages()
{
return (array)$this->images;
}
 
// }}}
// {{{ getTextinputs()
 
/**
* Get text input fields from RSS file
*
* @access public
* @return array
*/
function getTextinputs()
{
return (array)$this->textinputs;
}
 
// }}}
 
}
?>