/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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('ü', 'Ü', 'ö', |
'Ö', 'ä', 'Ä', |
'ß' |
), |
$xml |
); |
$xml = preg_replace(array("/\&([a-z\d\#]+)\;/i", |
"/\&/", |
"/\#\|\|([a-z\d\#]+)\|\|\#/i", |
"/([^a-zA-Z\d\s\<\>\&\;\.\:\=\"\-\/\%\?\!\'\(\)\[\]\{\}\$\#\+\,\@_])/e" |
), |
array("#||\\1||#", |
"&", |
"&\\1;", |
"'&#'.ord('\\1').';'" |
), |
$xml |
); |
return $xml; |
} |
/** |
* Print text representation of XML tree. |
*/ |
function dump() { |
echo $this->get(); |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/XML/Util.php |
---|
New file |
0,0 → 1,752 |
<?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.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Stephan Schmidt <schst@php-tools.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: Util.php,v 1.1 2007-03-28 08:51:22 neiluj Exp $ |
/** |
* error code for invalid chars in XML name |
*/ |
define("XML_UTIL_ERROR_INVALID_CHARS", 51); |
/** |
* error code for invalid chars in XML name |
*/ |
define("XML_UTIL_ERROR_INVALID_START", 52); |
/** |
* error code for non-scalar tag content |
*/ |
define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60); |
/** |
* error code for missing tag name |
*/ |
define("XML_UTIL_ERROR_NO_TAG_NAME", 61); |
/** |
* replace XML entities |
*/ |
define("XML_UTIL_REPLACE_ENTITIES", 1); |
/** |
* embedd content in a CData Section |
*/ |
define("XML_UTIL_CDATA_SECTION", 5); |
/** |
* do not replace entitites |
*/ |
define("XML_UTIL_ENTITIES_NONE", 0); |
/** |
* replace all XML entitites |
* This setting will replace <, >, ", ' and & |
*/ |
define("XML_UTIL_ENTITIES_XML", 1); |
/** |
* replace only required XML entitites |
* This setting will replace <, " and & |
*/ |
define("XML_UTIL_ENTITIES_XML_REQUIRED", 2); |
/** |
* replace HTML entitites |
* @link http://www.php.net/htmlentities |
*/ |
define("XML_UTIL_ENTITIES_HTML", 3); |
/** |
* Collapse all empty tags. |
*/ |
define("XML_UTIL_COLLAPSE_ALL", 1); |
/** |
* Collapse only empty XHTML tags that have no end tag. |
*/ |
define("XML_UTIL_COLLAPSE_XHTML_ONLY", 2); |
/** |
* utility class for working with XML documents |
* |
* @category XML |
* @package XML_Util |
* @version 1.1.0 |
* @author Stephan Schmidt <schst@php.net> |
*/ |
class XML_Util { |
/** |
* return API version |
* |
* @access public |
* @static |
* @return string $version API version |
*/ |
function apiVersion() |
{ |
return '1.1'; |
} |
/** |
* replace XML entities |
* |
* With the optional second parameter, you may select, which |
* entities should be replaced. |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // replace XML entites: |
* $string = XML_Util::replaceEntities("This string contains < & >."); |
* </code> |
* |
* @access public |
* @static |
* @param string string where XML special chars should be replaced |
* @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) |
* @return string string with replaced chars |
* @see reverseEntities() |
*/ |
function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML) |
{ |
switch ($replaceEntities) { |
case XML_UTIL_ENTITIES_XML: |
return strtr($string,array( |
'&' => '&', |
'>' => '>', |
'<' => '<', |
'"' => '"', |
'\'' => ''' )); |
break; |
case XML_UTIL_ENTITIES_XML_REQUIRED: |
return strtr($string,array( |
'&' => '&', |
'<' => '<', |
'"' => '"' )); |
break; |
case XML_UTIL_ENTITIES_HTML: |
return htmlentities($string); |
break; |
} |
return $string; |
} |
/** |
* reverse XML entities |
* |
* With the optional second parameter, you may select, which |
* entities should be reversed. |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // reverse XML entites: |
* $string = XML_Util::reverseEntities("This string contains < & >."); |
* </code> |
* |
* @access public |
* @static |
* @param string string where XML special chars should be replaced |
* @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) |
* @return string string with replaced chars |
* @see replaceEntities() |
*/ |
function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML) |
{ |
switch ($replaceEntities) { |
case XML_UTIL_ENTITIES_XML: |
return strtr($string,array( |
'&' => '&', |
'>' => '>', |
'<' => '<', |
'"' => '"', |
''' => '\'' )); |
break; |
case XML_UTIL_ENTITIES_XML_REQUIRED: |
return strtr($string,array( |
'&' => '&', |
'<' => '<', |
'"' => '"' )); |
break; |
case XML_UTIL_ENTITIES_HTML: |
$arr = array_flip(get_html_translation_table(HTML_ENTITIES)); |
return strtr($string, $arr); |
break; |
} |
return $string; |
} |
/** |
* build an xml declaration |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // get an XML declaration: |
* $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true); |
* </code> |
* |
* @access public |
* @static |
* @param string $version xml version |
* @param string $encoding character encoding |
* @param boolean $standAlone document is standalone (or not) |
* @return string $decl xml declaration |
* @uses XML_Util::attributesToString() to serialize the attributes of the XML declaration |
*/ |
function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null) |
{ |
$attributes = array( |
"version" => $version, |
); |
// add encoding |
if ($encoding !== null) { |
$attributes["encoding"] = $encoding; |
} |
// add standalone, if specified |
if ($standalone !== null) { |
$attributes["standalone"] = $standalone ? "yes" : "no"; |
} |
return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false)); |
} |
/** |
* build a document type declaration |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // get a doctype declaration: |
* $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd"); |
* </code> |
* |
* @access public |
* @static |
* @param string $root name of the root tag |
* @param string $uri uri of the doctype definition (or array with uri and public id) |
* @param string $internalDtd internal dtd entries |
* @return string $decl doctype declaration |
* @since 0.2 |
*/ |
function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) |
{ |
if (is_array($uri)) { |
$ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] ); |
} elseif (!empty($uri)) { |
$ref = sprintf( ' SYSTEM "%s"', $uri ); |
} else { |
$ref = ""; |
} |
if (empty($internalDtd)) { |
return sprintf("<!DOCTYPE %s%s>", $root, $ref); |
} else { |
return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd); |
} |
} |
/** |
* create string representation of an attribute list |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // build an attribute string |
* $att = array( |
* "foo" => "bar", |
* "argh" => "tomato" |
* ); |
* |
* $attList = XML_Util::attributesToString($att); |
* </code> |
* |
* @access public |
* @static |
* @param array $attributes attribute array |
* @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities' |
* @param boolean $multiline use linebreaks, if more than one attribute is given |
* @param string $indent string used for indentation of multiline attributes |
* @param string $linebreak string used for linebreaks of multiline attributes |
* @param integer $entities setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) |
* @return string string representation of the attributes |
* @uses XML_Util::replaceEntities() to replace XML entities in attribute values |
* @todo allow sort also to be an options array |
*/ |
function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML) |
{ |
/** |
* second parameter may be an array |
*/ |
if (is_array($sort)) { |
if (isset($sort['multiline'])) { |
$multiline = $sort['multiline']; |
} |
if (isset($sort['indent'])) { |
$indent = $sort['indent']; |
} |
if (isset($sort['linebreak'])) { |
$multiline = $sort['linebreak']; |
} |
if (isset($sort['entities'])) { |
$entities = $sort['entities']; |
} |
if (isset($sort['sort'])) { |
$sort = $sort['sort']; |
} else { |
$sort = true; |
} |
} |
$string = ''; |
if (is_array($attributes) && !empty($attributes)) { |
if ($sort) { |
ksort($attributes); |
} |
if( !$multiline || count($attributes) == 1) { |
foreach ($attributes as $key => $value) { |
if ($entities != XML_UTIL_ENTITIES_NONE) { |
if ($entities === XML_UTIL_CDATA_SECTION) { |
$entities = XML_UTIL_ENTITIES_XML; |
} |
$value = XML_Util::replaceEntities($value, $entities); |
} |
$string .= ' '.$key.'="'.$value.'"'; |
} |
} else { |
$first = true; |
foreach ($attributes as $key => $value) { |
if ($entities != XML_UTIL_ENTITIES_NONE) { |
$value = XML_Util::replaceEntities($value, $entities); |
} |
if ($first) { |
$string .= " ".$key.'="'.$value.'"'; |
$first = false; |
} else { |
$string .= $linebreak.$indent.$key.'="'.$value.'"'; |
} |
} |
} |
} |
return $string; |
} |
/** |
* Collapses empty tags. |
* |
* @access public |
* @static |
* @param string $xml XML |
* @param integer $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones. |
* @return string $xml XML |
*/ |
function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) { |
if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) { |
return preg_replace( |
'/<(area|base|br|col|hr|img|input|link|meta|param)([^>]*)><\/\\1>/s', |
'<\\1\\2 />', |
$xml |
); |
} else { |
return preg_replace( |
'/<(\w+)([^>]*)><\/\\1>/s', |
'<\\1\\2 />', |
$xml |
); |
} |
} |
/** |
* create a tag |
* |
* This method will call XML_Util::createTagFromArray(), which |
* is more flexible. |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // create an XML tag: |
* $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#"); |
* </code> |
* |
* @access public |
* @static |
* @param string $qname qualified tagname (including namespace) |
* @param array $attributes array containg attributes |
* @param mixed $content |
* @param string $namespaceUri URI of the namespace |
* @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both |
* @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line |
* @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) |
* @param string $linebreak string used for linebreaks |
* @param boolean $sortAttributes Whether to sort the attributes or not |
* @return string $string XML tag |
* @see XML_Util::createTagFromArray() |
* @uses XML_Util::createTagFromArray() to create the tag |
*/ |
function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $sortAttributes = true) |
{ |
$tag = array( |
"qname" => $qname, |
"attributes" => $attributes |
); |
// add tag content |
if ($content !== null) { |
$tag["content"] = $content; |
} |
// add namespace Uri |
if ($namespaceUri !== null) { |
$tag["namespaceUri"] = $namespaceUri; |
} |
return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak, $sortAttributes); |
} |
/** |
* create a tag from an array |
* this method awaits an array in the following format |
* <pre> |
* array( |
* "qname" => $qname // qualified name of the tag |
* "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace) |
* "localpart" => $localpart, // local part of the tagname (optional, if qname is specified) |
* "attributes" => array(), // array containing all attributes (optional) |
* "content" => $content, // tag content (optional) |
* "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional) |
* ) |
* </pre> |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* $tag = array( |
* "qname" => "foo:bar", |
* "namespaceUri" => "http://foo.com", |
* "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), |
* "content" => "I'm inside the tag", |
* ); |
* // creating a tag with qualified name and namespaceUri |
* $string = XML_Util::createTagFromArray($tag); |
* </code> |
* |
* @access public |
* @static |
* @param array $tag tag definition |
* @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both |
* @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line |
* @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) |
* @param string $linebreak string used for linebreaks |
* @param boolean $sortAttributes Whether to sort the attributes or not |
* @return string $string XML tag |
* @see XML_Util::createTag() |
* @uses XML_Util::attributesToString() to serialize the attributes of the tag |
* @uses XML_Util::splitQualifiedName() to get local part and namespace of a qualified name |
*/ |
function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $sortAttributes = true) |
{ |
if (isset($tag['content']) && !is_scalar($tag['content'])) { |
return XML_Util::raiseError( 'Supplied non-scalar value as tag content', XML_UTIL_ERROR_NON_SCALAR_CONTENT ); |
} |
if (!isset($tag['qname']) && !isset($tag['localPart'])) { |
return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME ); |
} |
// if no attributes hav been set, use empty attributes |
if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) { |
$tag["attributes"] = array(); |
} |
if (isset($tag['namespaces'])) { |
foreach ($tag['namespaces'] as $ns => $uri) { |
$tag['attributes']['xmlns:'.$ns] = $uri; |
} |
} |
// qualified name is not given |
if (!isset($tag["qname"])) { |
// check for namespace |
if (isset($tag["namespace"]) && !empty($tag["namespace"])) { |
$tag["qname"] = $tag["namespace"].":".$tag["localPart"]; |
} else { |
$tag["qname"] = $tag["localPart"]; |
} |
// namespace URI is set, but no namespace |
} elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) { |
$parts = XML_Util::splitQualifiedName($tag["qname"]); |
$tag["localPart"] = $parts["localPart"]; |
if (isset($parts["namespace"])) { |
$tag["namespace"] = $parts["namespace"]; |
} |
} |
if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) { |
// is a namespace given |
if (isset($tag["namespace"]) && !empty($tag["namespace"])) { |
$tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"]; |
} else { |
// define this Uri as the default namespace |
$tag["attributes"]["xmlns"] = $tag["namespaceUri"]; |
} |
} |
// check for multiline attributes |
if ($multiline === true) { |
if ($indent === "_auto") { |
$indent = str_repeat(" ", (strlen($tag["qname"])+2)); |
} |
} |
// create attribute list |
$attList = XML_Util::attributesToString($tag['attributes'], $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities ); |
if (!isset($tag['content']) || (string)$tag['content'] == '') { |
$tag = sprintf('<%s%s />', $tag['qname'], $attList); |
} else { |
switch ($replaceEntities) { |
case XML_UTIL_ENTITIES_NONE: |
break; |
case XML_UTIL_CDATA_SECTION: |
$tag['content'] = XML_Util::createCDataSection($tag['content']); |
break; |
default: |
$tag['content'] = XML_Util::replaceEntities($tag['content'], $replaceEntities); |
break; |
} |
$tag = sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'], $tag['qname'] ); |
} |
return $tag; |
} |
/** |
* create a start element |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // create an XML start element: |
* $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#"); |
* </code> |
* |
* @access public |
* @static |
* @param string $qname qualified tagname (including namespace) |
* @param array $attributes array containg attributes |
* @param string $namespaceUri URI of the namespace |
* @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line |
* @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) |
* @param string $linebreak string used for linebreaks |
* @param boolean $sortAttributes Whether to sort the attributes or not |
* @return string $string XML start element |
* @see XML_Util::createEndElement(), XML_Util::createTag() |
*/ |
function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n", $sortAttributes = true) |
{ |
// if no attributes hav been set, use empty attributes |
if (!isset($attributes) || !is_array($attributes)) { |
$attributes = array(); |
} |
if ($namespaceUri != null) { |
$parts = XML_Util::splitQualifiedName($qname); |
} |
// check for multiline attributes |
if ($multiline === true) { |
if ($indent === "_auto") { |
$indent = str_repeat(" ", (strlen($qname)+2)); |
} |
} |
if ($namespaceUri != null) { |
// is a namespace given |
if (isset($parts["namespace"]) && !empty($parts["namespace"])) { |
$attributes["xmlns:".$parts["namespace"]] = $namespaceUri; |
} else { |
// define this Uri as the default namespace |
$attributes["xmlns"] = $namespaceUri; |
} |
} |
// create attribute list |
$attList = XML_Util::attributesToString($attributes, $sortAttributes, $multiline, $indent, $linebreak); |
$element = sprintf("<%s%s>", $qname, $attList); |
return $element; |
} |
/** |
* create an end element |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // create an XML start element: |
* $tag = XML_Util::createEndElement("myNs:myTag"); |
* </code> |
* |
* @access public |
* @static |
* @param string $qname qualified tagname (including namespace) |
* @return string $string XML end element |
* @see XML_Util::createStartElement(), XML_Util::createTag() |
*/ |
function createEndElement($qname) |
{ |
$element = sprintf("</%s>", $qname); |
return $element; |
} |
/** |
* create an XML comment |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // create an XML start element: |
* $tag = XML_Util::createComment("I am a comment"); |
* </code> |
* |
* @access public |
* @static |
* @param string $content content of the comment |
* @return string $comment XML comment |
*/ |
function createComment($content) |
{ |
$comment = sprintf("<!-- %s -->", $content); |
return $comment; |
} |
/** |
* create a CData section |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // create a CData section |
* $tag = XML_Util::createCDataSection("I am content."); |
* </code> |
* |
* @access public |
* @static |
* @param string $data data of the CData section |
* @return string $string CData section with content |
*/ |
function createCDataSection($data) |
{ |
return sprintf("<![CDATA[%s]]>", $data); |
} |
/** |
* split qualified name and return namespace and local part |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // split qualified tag |
* $parts = XML_Util::splitQualifiedName("xslt:stylesheet"); |
* </code> |
* the returned array will contain two elements: |
* <pre> |
* array( |
* "namespace" => "xslt", |
* "localPart" => "stylesheet" |
* ); |
* </pre> |
* |
* @access public |
* @static |
* @param string $qname qualified tag name |
* @param string $defaultNs default namespace (optional) |
* @return array $parts array containing namespace and local part |
*/ |
function splitQualifiedName($qname, $defaultNs = null) |
{ |
if (strstr($qname, ':')) { |
$tmp = explode(":", $qname); |
return array( |
"namespace" => $tmp[0], |
"localPart" => $tmp[1] |
); |
} |
return array( |
"namespace" => $defaultNs, |
"localPart" => $qname |
); |
} |
/** |
* check, whether string is valid XML name |
* |
* <p>XML names are used for tagname, attribute names and various |
* other, lesser known entities.</p> |
* <p>An XML name may only consist of alphanumeric characters, |
* dashes, undescores and periods, and has to start with a letter |
* or an underscore. |
* </p> |
* |
* <code> |
* require_once 'XML/Util.php'; |
* |
* // verify tag name |
* $result = XML_Util::isValidName("invalidTag?"); |
* if (XML_Util::isError($result)) { |
* print "Invalid XML name: " . $result->getMessage(); |
* } |
* </code> |
* |
* @access public |
* @static |
* @param string $string string that should be checked |
* @return mixed $valid true, if string is a valid XML name, PEAR error otherwise |
* @todo support for other charsets |
*/ |
function isValidName($string) |
{ |
// check for invalid chars |
if (!preg_match('/^[[:alpha:]_]$/', $string{0})) { |
return XML_Util::raiseError('XML names may only start with letter or underscore', XML_UTIL_ERROR_INVALID_START); |
} |
// check for invalid chars |
if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/', $string)) { |
return XML_Util::raiseError('XML names may only contain alphanumeric chars, period, hyphen, colon and underscores', XML_UTIL_ERROR_INVALID_CHARS); |
} |
// XML name is valid |
return true; |
} |
/** |
* replacement for XML_Util::raiseError |
* |
* Avoids the necessity to always require |
* PEAR.php |
* |
* @access public |
* @param string error message |
* @param integer error code |
* @return object PEAR_Error |
*/ |
function raiseError($msg, $code) |
{ |
require_once 'PEAR.php'; |
return PEAR::raiseError($msg, $code); |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/Array.php |
---|
New file |
0,0 → 1,159 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a PHP Array |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author georg_1 at have2 dot com |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Array.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @since File available since Release 1.4.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching authentication data from a PHP Array |
* |
* This container takes two options when configuring: |
* |
* cryptType: The crypt used to store the password. Currently recognised |
* are: none, md5 and crypt. default: none |
* users: A named array of usernames and passwords. |
* Ex: |
* array( |
* 'guest' => '084e0343a0486ff05530df6c705c8bb4', // password guest |
* 'georg' => 'fc77dba827fcc88e0243404572c51325' // password georg |
* ) |
* |
* Usage Example: |
* <?php |
* $AuthOptions = array( |
* 'users' => array( |
* 'guest' => '084e0343a0486ff05530df6c705c8bb4', // password guest |
* 'georg' => 'fc77dba827fcc88e0243404572c51325' // password georg |
* ), |
* 'cryptType'=>'md5', |
* ); |
* |
* $auth = new Auth("Array", $AuthOptions); |
* ?> |
* |
* @category Authentication |
* @package Auth |
* @author georg_1 at have2 dot com |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @since File available since Release 1.4.0 |
*/ |
class Auth_Container_Array extends Auth_Container { |
// {{{ properties |
/** |
* The users and their password to authenticate against |
* |
* @var array $users |
*/ |
var $users; |
/** |
* The cryptType used on the passwords |
* |
* @var string $cryptType |
*/ |
var $cryptType = 'none'; |
// }}} |
// {{{ Auth_Container_Array() |
/** |
* Constructor for Array Container |
* |
* @param array $data Options for the container |
* @return void |
*/ |
function Auth_Container_Array($data) |
{ |
if (!is_array($data)) { |
PEAR::raiseError('The options for Auth_Container_Array must be an array'); |
} |
if (isset($data['users']) && is_array($data['users'])) { |
$this->users = $data['users']; |
} else { |
$this->users = array(); |
PEAR::raiseError('Auth_Container_Array: no user data found inoptions array'); |
} |
if (isset($data['cryptType'])) { |
$this->cryptType = $data['cryptType']; |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from array |
* |
* This function uses the given username to fetch the corresponding |
* login data from the array. 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 boolean|PEAR_Error Error object or boolean |
*/ |
function fetchData($user, $pass) |
{ |
if ( isset($this->users[$user]) |
&& $this->verifyPassword($pass, $this->users[$user], $this->cryptType)) { |
return true; |
} |
return false; |
} |
// }}} |
// {{{ listUsers() |
/** |
* Returns a list of users available within the container |
* |
* @return array |
*/ |
function listUsers() |
{ |
$ret = array(); |
foreach ($this->users as $username => $password) { |
$ret[]['username'] = $username; |
} |
return $ret; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/File.php |
---|
New file |
0,0 → 1,305 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a generic password file |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Stefan Ekman <stekman@sedata.org> |
* @author Martin Jansen <mj@php.net> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Michael Wallner <mike@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: File.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
*/ |
/** |
* Include PEAR File_Passwd package |
*/ |
require_once "File/Passwd.php"; |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
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. |
* |
* @category Authentication |
* @package Auth |
* @author Stefan Ekman <stekman@sedata.org> |
* @author Martin Jansen <mj@php.net> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Michael Wallner <mike@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
*/ |
class Auth_Container_File extends Auth_Container |
{ |
// {{{ properties |
/** |
* Path to passwd file |
* |
* @var string |
*/ |
var $pwfile = ''; |
/** |
* Options for container |
* |
* @var array |
*/ |
var $options = array(); |
// }}} |
// {{{ Auth_Container_File() [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->_setDefaults(); |
// Only file is a valid option here |
if(is_array($filename)) { |
$this->pwfile = $filename['file']; |
$this->_parseOptions($filename); |
} else { |
$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($this->options['type'], $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 Additional parameters to File_Password_*::addUser() |
* |
* @return boolean |
*/ |
function addUser($user, $pass, $additional='') |
{ |
$params = array($user, $pass); |
if (is_array($additional)) { |
foreach ($additional as $item) { |
$params[] = $item; |
} |
} else { |
$params[] = $additional; |
} |
$pw_obj = &$this->_load(); |
if (PEAR::isError($pw_obj)) { |
return false; |
} |
$res = call_user_func_array(array(&$pw_obj, 'addUser'), $params); |
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; |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password |
*/ |
function changePassword($username, $password) |
{ |
$pw_obj = &$this->_load(); |
if (PEAR::isError($pw_obj)) { |
return false; |
} |
$res = $pw_obj->changePasswd($username, $password); |
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($this->options['type']); |
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; |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
* @return void |
*/ |
function _setDefaults() |
{ |
$this->options['type'] = 'Cvs'; |
} |
// }}} |
// {{{ _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; |
} |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/LDAP.php |
---|
New file |
0,0 → 1,773 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against an LDAP server |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Jan Wagner <wagner@netsols.de> |
* @author Adam Ashley <aashley@php.net> |
* @author Hugues Peeters <hugues.peeters@claroline.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: LDAP.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
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 |
* version: LDAP version to use, ususally 2 (default) or 3, |
* must be an integer! |
* referrals: If set, determines whether the LDAP library automatically |
* follows referrals returned by LDAP servers or not. Possible |
* values are true (default) or false. |
* 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 |
* basedn: the base dn of your server |
* userdn: gets prepended to basedn when searching for user |
* userscope: Scope for user searching: one, sub (default), or base |
* userattr: the user attribute to search for (default: uid) |
* userfilter: filter that will be added to the search filter |
* this way: (&(userattr=username)(userfilter)) |
* default: (objectClass=posixAccount) |
* attributes: array of additional attributes to fetch from entry. |
* these will added to auth data and can be retrieved via |
* Auth::getAuthData(). An empty array will fetch all attributes, |
* array('') will fetch no attributes at all (default) |
* If you add 'dn' as a value to this array, the users DN that was |
* used for binding will be added to auth data as well. |
* attrformat: The returned format of the additional data defined in the |
* 'attributes' option. Two formats are available. |
* LDAP returns data formatted in a |
* multidimensional array where each array starts with a |
* 'count' element providing the number of attributes in the |
* entry, or the number of values for attributes. When set |
* to this format, the only way to retrieve data from the |
* Auth object is by calling getAuthData('attributes'). |
* AUTH returns data formatted in a |
* structure more compliant with other Auth Containers, |
* where each attribute element can be directly called by |
* getAuthData() method from Auth. |
* For compatibily with previous LDAP container versions, |
* the default format is LDAP. |
* groupdn: gets prepended to basedn when searching for group |
* groupattr: the group attribute to search for (default: cn) |
* groupfilter: filter that will be added to the search filter when |
* searching for a group: |
* (&(groupattr=group)(memberattr=username)(groupfilter)) |
* default: (objectClass=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 |
* groupscope: Scope for group searching: one, sub (default), or base |
* start_tls: enable/disable the use of START_TLS encrypted connection |
* (default: false) |
* debug: Enable/Disable debugging output (default: false) |
* try_all: Whether to try all user accounts returned from the search |
* or just the first one. (default: false) |
* |
* To use this storage container, you have to use the following syntax: |
* |
* <?php |
* ... |
* |
* $a1 = new Auth("LDAP", array( |
* 'host' => 'localhost', |
* 'port' => '389', |
* 'version' => 3, |
* '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', |
* 'userscope' => 'one', |
* 'userdn' => 'ou=People', |
* 'groupdn' => 'ou=Groups', |
* 'groupfilter' => '(objectClass=posixGroup)', |
* 'memberattr' => 'memberUid', |
* 'memberisdn' => false, |
* 'group' => 'admin' |
* )); |
* |
* $a3 = new Auth('LDAP', array( |
* 'host' => 'ldap.netsols.de', |
* 'port' => 389, |
* 'version' => 3, |
* 'referrals' => false, |
* 'basedn' => 'dc=netsols,dc=de', |
* 'binddn' => 'cn=Jan Wagner,cn=Users,dc=netsols,dc=de', |
* 'bindpw' => 'password', |
* 'userattr' => 'samAccountName', |
* 'userfilter' => '(objectClass=user)', |
* 'attributes' => array(''), |
* 'group' => 'testing', |
* 'groupattr' => 'samAccountName', |
* 'groupfilter' => '(objectClass=group)', |
* 'memberattr' => 'member', |
* 'memberisdn' => true, |
* 'groupdn' => 'cn=Users', |
* 'groupscope' => 'one', |
* '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. |
* |
* LDAP Referrals need to be set to false for AD to work sometimes. |
* |
* Example a3 shows a full blown and tested example for connection to |
* Windows 2000 Active Directory with group mebership checking |
* |
* Note also that if you want an encrypted connection to an MS LDAP |
* server, then, on your webserver, you must specify |
* TLS_REQCERT never |
* in /etc/ldap/ldap.conf or in the webserver user's ~/.ldaprc (which |
* may or may not be read depending on your configuration). |
* |
* |
* @category Authentication |
* @package Auth |
* @author Jan Wagner <wagner@netsols.de> |
* @author Adam Ashley <aashley@php.net> |
* @author Hugues Peeters <hugues.peeters@claroline.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
*/ |
class Auth_Container_LDAP extends Auth_Container |
{ |
// {{{ properties |
/** |
* Options for the class |
* @var array |
*/ |
var $options = array(); |
/** |
* Connection ID of LDAP Link |
* @var string |
*/ |
var $conn_id = false; |
// }}} |
// {{{ Auth_Container_LDAP() [constructor] |
/** |
* 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) |
{ |
if (false === extension_loaded('ldap')) { |
return PEAR::raiseError('Auth_Container_LDAP: LDAP Extension not loaded', |
41, PEAR_ERROR_DIE); |
} |
$this->_setDefaults(); |
if (is_array($params)) { |
$this->_parseOptions($params); |
} |
} |
// }}} |
// {{{ _prepare() |
/** |
* Prepare LDAP connection |
* |
* This function checks if we have already opened a connection to |
* the LDAP server. If that's not the case, a new connection is opened. |
* |
* @access private |
* @return mixed True or a PEAR error object. |
*/ |
function _prepare() |
{ |
if (!$this->_isValidLink()) { |
$res = $this->_connect(); |
if (PEAR::isError($res)) { |
return $res; |
} |
} |
return true; |
} |
// }}} |
// {{{ _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); |
} |
$this->_debug('Successfully connected to server', __LINE__); |
// switch LDAP version |
if (is_numeric($this->options['version']) && $this->options['version'] > 2) { |
$this->_debug("Switching to LDAP version {$this->options['version']}", __LINE__); |
@ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $this->options['version']); |
// start TLS if available |
if (isset($this->options['start_tls']) && $this->options['start_tls']) { |
$this->_debug("Starting TLS session", __LINE__); |
if (@ldap_start_tls($this->conn_id) === false) { |
return PEAR::raiseError('Auth_Container_LDAP: Could not start tls.', 41); |
} |
} |
} |
// switch LDAP referrals |
if (is_bool($this->options['referrals'])) { |
$this->_debug("Switching LDAP referrals to " . (($this->options['referrals']) ? 'true' : 'false'), __LINE__); |
@ldap_set_option($this->conn_id, LDAP_OPT_REFERRALS, $this->options['referrals']); |
} |
// bind with credentials or anonymously |
if (strlen($this->options['binddn']) && strlen($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); |
} |
$this->_debug('Binding was successful', __LINE__); |
return true; |
} |
// }}} |
// {{{ _disconnect() |
/** |
* Disconnects (unbinds) from ldap server |
* |
* @access private |
*/ |
function _disconnect() |
{ |
if ($this->_isValidLink()) { |
$this->_debug('disconnecting from server'); |
@ldap_unbind($this->conn_id); |
} |
} |
// }}} |
// {{{ _getBaseDN() |
/** |
* Tries to find Basedn via namingContext Attribute |
* |
* @access private |
*/ |
function _getBaseDN() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
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); |
} |
return true; |
} |
// }}} |
// {{{ _isValidLink() |
/** |
* 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; |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
*/ |
function _setDefaults() |
{ |
$this->options['url'] = ''; |
$this->options['host'] = 'localhost'; |
$this->options['port'] = '389'; |
$this->options['version'] = 2; |
$this->options['referrals'] = true; |
$this->options['binddn'] = ''; |
$this->options['bindpw'] = ''; |
$this->options['basedn'] = ''; |
$this->options['userdn'] = ''; |
$this->options['userscope'] = 'sub'; |
$this->options['userattr'] = 'uid'; |
$this->options['userfilter'] = '(objectClass=posixAccount)'; |
$this->options['attributes'] = array(''); // no attributes |
// $this->options['attrformat'] = 'LDAP'; // returns attribute array as PHP LDAP functions return it |
$this->options['attrformat'] = 'AUTH'; // returns attribute like other Auth containers |
$this->options['group'] = ''; |
$this->options['groupdn'] = ''; |
$this->options['groupscope'] = 'sub'; |
$this->options['groupattr'] = 'cn'; |
$this->options['groupfilter'] = '(objectClass=groupOfUniqueNames)'; |
$this->options['memberattr'] = 'uniqueMember'; |
$this->options['memberisdn'] = true; |
$this->options['start_tls'] = false; |
$this->options['debug'] = false; |
$this->options['try_all'] = false; // Try all user ids returned not just the first one |
} |
// }}} |
// {{{ _parseOptions() |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
$array = $this->_setV12OptionsToV13($array); |
foreach ($array as $key => $value) { |
if (array_key_exists($key, $this->options)) { |
if ($key == 'attributes') { |
if (is_array($value)) { |
$this->options[$key] = $value; |
} else { |
$this->options[$key] = explode(',', $value); |
} |
} else { |
$this->options[$key] = $value; |
} |
} |
} |
} |
// }}} |
// {{{ _setV12OptionsToV13() |
/** |
* Adapt deprecated options from Auth 1.2 LDAP to Auth 1.3 LDAP |
* |
* @author Hugues Peeters <hugues.peeters@claroline.net> |
* @access private |
* @param array |
* @return array |
*/ |
function _setV12OptionsToV13($array) |
{ |
if (isset($array['useroc'])) |
$array['userfilter'] = "(objectClass=".$array['useroc'].")"; |
if (isset($array['groupoc'])) |
$array['groupfilter'] = "(objectClass=".$array['groupoc'].")"; |
if (isset($array['scope'])) |
$array['userscope'] = $array['scope']; |
return $array; |
} |
// }}} |
// {{{ _scope2function() |
/** |
* Get search function for scope |
* |
* @param string scope |
* @return string ldap search function |
*/ |
function _scope2function($scope) |
{ |
switch($scope) { |
case 'one': |
$function = 'ldap_list'; |
break; |
case 'base': |
$function = 'ldap_read'; |
break; |
default: |
$function = 'ldap_search'; |
break; |
} |
return $function; |
} |
// }}} |
// {{{ fetchData() |
/** |
* Fetch data from LDAP server |
* |
* Searches the LDAP server for the given username/password |
* combination. Escapes all LDAP meta characters in username |
* before performing the query. |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$err = $this->_getBaseDN(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
// UTF8 Encode username for LDAPv3 |
if (@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver == 3) { |
$this->_debug('UTF8 encoding username for LDAPv3', __LINE__); |
$username = utf8_encode($username); |
} |
// make search filter |
$filter = sprintf('(&(%s=%s)%s)', |
$this->options['userattr'], |
$this->_quoteFilterString($username), |
$this->options['userfilter']); |
// make search base dn |
$search_basedn = $this->options['userdn']; |
if ($search_basedn != '' && substr($search_basedn, -1) != ',') { |
$search_basedn .= ','; |
} |
$search_basedn .= $this->options['basedn']; |
// attributes |
$attributes = $this->options['attributes']; |
// make functions params array |
$func_params = array($this->conn_id, $search_basedn, $filter, $attributes); |
// search function to use |
$func_name = $this->_scope2function($this->options['userscope']); |
$this->_debug("Searching with $func_name and filter $filter in $search_basedn", __LINE__); |
// search |
if (($result_id = @call_user_func_array($func_name, $func_params)) === false) { |
$this->_debug('User not found', __LINE__); |
} elseif (@ldap_count_entries($this->conn_id, $result_id) >= 1) { // did we get some possible results? |
$this->_debug('User(s) found', __LINE__); |
$first = true; |
$entry_id = null; |
do { |
// then get the user dn |
if ($first) { |
$entry_id = @ldap_first_entry($this->conn_id, $result_id); |
$first = false; |
} else { |
$entry_id = @ldap_next_entry($this->conn_id, $entry_id); |
if ($entry_id === false) |
break; |
} |
$user_dn = @ldap_get_dn($this->conn_id, $entry_id); |
// as the dn is not fetched as an attribute, we save it anyway |
if (is_array($attributes) && in_array('dn', $attributes)) { |
$this->_debug('Saving DN to AuthData', __LINE__); |
$this->_auth_obj->setAuthData('dn', $user_dn); |
} |
// fetch attributes |
if ($attributes = @ldap_get_attributes($this->conn_id, $entry_id)) { |
if (is_array($attributes) && isset($attributes['count']) && |
$attributes['count'] > 0) { |
// ldap_get_attributes() returns a specific multi dimensional array |
// format containing all the attributes and where each array starts |
// with a 'count' element providing the number of attributes in the |
// entry, or the number of values for attribute. For compatibility |
// reasons, it remains the default format returned by LDAP container |
// setAuthData(). |
// The code below optionally returns attributes in another format, |
// more compliant with other Auth containers, where each attribute |
// element are directly set in the 'authData' list. This option is |
// enabled by setting 'attrformat' to |
// 'AUTH' in the 'options' array. |
// eg. $this->options['attrformat'] = 'AUTH' |
if ( strtoupper($this->options['attrformat']) == 'AUTH' ) { |
$this->_debug('Saving attributes to Auth data in AUTH format', __LINE__); |
unset ($attributes['count']); |
foreach ($attributes as $attributeName => $attributeValue ) { |
if (is_int($attributeName)) continue; |
if (is_array($attributeValue) && isset($attributeValue['count'])) { |
unset ($attributeValue['count']); |
} |
if (count($attributeValue)<=1) $attributeValue = $attributeValue[0]; |
$this->_auth_obj->setAuthData($attributeName, $attributeValue); |
} |
} |
else |
{ |
$this->_debug('Saving attributes to Auth data in LDAP format', __LINE__); |
$this->_auth_obj->setAuthData('attributes', $attributes); |
} |
} |
} |
@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 (strlen($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); |
$this->_disconnect(); |
return $return; |
} else { |
$this->_debug('Authenticated', __LINE__); |
$this->_disconnect(); |
return true; // user authenticated |
} // checkGroup |
} // bind |
} // non-empty password |
} while ($this->options['try_all'] == true); // interate through entries |
} // get results |
// default |
$this->_debug('NOT authenticated!', __LINE__); |
$this->_disconnect(); |
return false; |
} |
// }}} |
// {{{ checkGroup() |
/** |
* Validate group membership |
* |
* Searches the LDAP server for group membership of the |
* supplied username. Quotes all LDAP filter meta characters in |
* the user name before querying the LDAP server. |
* |
* @param string Distinguished Name of the authenticated User |
* @return boolean |
*/ |
function checkGroup($user) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
// make filter |
$filter = sprintf('(&(%s=%s)(%s=%s)%s)', |
$this->options['groupattr'], |
$this->options['group'], |
$this->options['memberattr'], |
$this->_quoteFilterString($user), |
$this->options['groupfilter']); |
// 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'])); |
$func_name = $this->_scope2function($this->options['groupscope']); |
$this->_debug("Searching with $func_name and filter $filter in $search_basedn", __LINE__); |
// search |
if (($result_id = @call_user_func_array($func_name, $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__); |
return true; |
} |
} |
// default |
$this->_debug('User is NOT member of group', __LINE__); |
return false; |
} |
// }}} |
// {{{ _debug() |
/** |
* 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 />"); |
} |
} |
// }}} |
// {{{ _quoteFilterString() |
/** |
* Escapes LDAP filter special characters as defined in RFC 2254. |
* |
* @access private |
* @param string Filter String |
*/ |
function _quoteFilterString($filter_str) |
{ |
$metas = array( '\\', '*', '(', ')', "\x00"); |
$quoted_metas = array('\\\\', '\*', '\(', '\)', "\\\x00"); |
return str_replace($metas, $quoted_metas, $filter_str); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/POP3.php |
---|
New file |
0,0 → 1,143 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a POP3 server |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Stefan Ekman <stekman@sedata.org> |
* @author Martin Jansen <mj@php.net> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: POP3.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR package for error handling |
*/ |
require_once 'PEAR.php'; |
/** |
* Include PEAR Net_POP3 package |
*/ |
require_once 'Net/POP3.php'; |
/** |
* Storage driver for Authentication on a POP3 server. |
* |
* @category Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.0 |
*/ |
class Auth_Container_POP3 extends Auth_Container |
{ |
// {{{ properties |
/** |
* POP3 Server |
* @var string |
*/ |
var $server='localhost'; |
/** |
* POP3 Server port |
* @var string |
*/ |
var $port='110'; |
/** |
* POP3 Authentication method |
* |
* Prefered POP3 authentication method. Acceptable values: |
* Boolean TRUE - Use Net_POP3's autodetection |
* String 'DIGEST-MD5','CRAM-MD5','LOGIN','PLAIN','APOP','USER' |
* - Attempt this authentication style first |
* then fallback to autodetection. |
* @var mixed |
*/ |
var $method=true; |
// }}} |
// {{{ Auth_Container_POP3() [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) && !is_null($server)) { |
if (is_array($server)) { |
if (isset($server['host'])) { |
$this->server = $server['host']; |
} |
if (isset($server['port'])) { |
$this->port = $server['port']; |
} |
if (isset($server['method'])) { |
$this->method = $server['method']; |
} |
} 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, $this->method); |
if (!$res) { |
return $res; |
} |
$result = $pop3->login($username, $password); |
$pop3->disconnect(); |
return $result; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/SAP.php |
---|
New file |
0,0 → 1,177 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a SAP system using the SAPRFC PHP extension. |
* |
* Requires the SAPRFC ext available at http://saprfc.sourceforge.net/ |
* |
* PHP version 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Stoyan Stefanov <ssttoo@gmail.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: SAP.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.4.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR for error handling |
*/ |
require_once 'PEAR.php'; |
/** |
* Performs authentication against a SAP system using the SAPRFC PHP extension. |
* |
* When the option GETSSO2 is TRUE (default) |
* the Single Sign-On (SSO) ticket is retrieved |
* and stored as an Auth attribute called 'sap' |
* in order to be reused for consecutive connections. |
* |
* @category Authentication |
* @package Auth |
* @author Stoyan Stefanov <ssttoo@gmail.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @since Class available since Release 1.4.0 |
*/ |
class Auth_Container_SAP extends Auth_Container { |
// {{{ properties |
/** |
* @var array Default options |
*/ |
var $options = array( |
'CLIENT' => '000', |
'LANG' => 'EN', |
'GETSSO2' => true, |
); |
// }}} |
// {{{ Auth_Container_SAP() |
/** |
* Class constructor. Checks that required options |
* are present and that the SAPRFC extension is loaded |
* |
* Options that can be passed and their defaults: |
* <pre> |
* array( |
* 'ASHOST' => "", |
* 'SYSNR' => "", |
* 'CLIENT' => "000", |
* 'GWHOST' =>"", |
* 'GWSERV' =>"", |
* 'MSHOST' =>"", |
* 'R3NAME' =>"", |
* 'GROUP' =>"", |
* 'LANG' =>"EN", |
* 'TRACE' =>"", |
* 'GETSSO2'=> true |
* ) |
* </pre> |
* |
* @param array array of options. |
* @return void |
*/ |
function Auth_Container_SAP($options) |
{ |
$saprfc_loaded = PEAR::loadExtension('saprfc'); |
if (!$saprfc_loaded) { |
return PEAR::raiseError('Cannot use SAP authentication, ' |
.'SAPRFC extension not loaded!'); |
} |
if (empty($options['R3NAME']) && empty($options['ASHOST'])) { |
return PEAR::raiseError('R3NAME or ASHOST required for authentication'); |
} |
$this->options = array_merge($this->options, $options); |
} |
// }}} |
// {{{ fetchData() |
/** |
* Performs username and password check |
* |
* @param string Username |
* @param string Password |
* @return boolean TRUE on success (valid user), FALSE otherwise |
*/ |
function fetchData($username, $password) |
{ |
$connection_options = $this->options; |
$connection_options['USER'] = $username; |
$connection_options['PASSWD'] = $password; |
$rfc = saprfc_open($connection_options); |
if (!$rfc) { |
$message = "Couldn't connect to the SAP system."; |
$error = $this->getError(); |
if ($error['message']) { |
$message .= ': ' . $error['message']; |
} |
PEAR::raiseError($message, null, null, null, @$erorr['all']); |
return false; |
} else { |
if (!empty($this->options['GETSSO2'])) { |
if ($ticket = @saprfc_get_ticket($rfc)) { |
$this->options['MYSAPSSO2'] = $ticket; |
unset($this->options['GETSSO2']); |
$this->_auth_obj->setAuthData('sap', $this->options); |
} else { |
PEAR::raiseError("SSO ticket retrieval failed"); |
} |
} |
@saprfc_close($rfc); |
return true; |
} |
} |
// }}} |
// {{{ getError() |
/** |
* Retrieves the last error from the SAP connection |
* and returns it as an array. |
* |
* @return array Array of error information |
*/ |
function getError() |
{ |
$error = array(); |
$sap_error = saprfc_error(); |
if (empty($err)) { |
return $error; |
} |
$err = explode("n", $sap_error); |
foreach ($err AS $line) { |
$item = split(':', $line); |
$error[strtolower(trim($item[0]))] = trim($item[1]); |
} |
$error['all'] = $sap_error; |
return $error; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/MDB2.php |
---|
New file |
0,0 → 1,571 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against PEAR MDB2 |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Lorenzo Alberton <l.alberton@quipo.it> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: MDB2.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR MDB2 package |
*/ |
require_once 'MDB2.php'; |
/** |
* Storage driver for fetching login data from a database |
* |
* This storage driver can use all databases which are supported |
* by the PEAR MDB2 abstraction layer to fetch login data. |
* |
* @category Authentication |
* @package Auth |
* @author Lorenzo Alberton <l.alberton@quipo.it> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Container_MDB2 extends Auth_Container |
{ |
// {{{ properties |
/** |
* Additional options for the storage container |
* @var array |
*/ |
var $options = array(); |
/** |
* MDB object |
* @var object |
*/ |
var $db = null; |
var $dsn = ''; |
/** |
* User that is currently selected from the DB. |
* @var string |
*/ |
var $activeUser = ''; |
// }}} |
// {{{ Auth_Container_MDB2() [constructor] |
/** |
* Constructor of the container class |
* |
* Initate connection to the database via PEAR::MDB2 |
* |
* @param string Connection data or MDB2 object |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_MDB2($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 mixed DSN string | array | mdb object |
* @return mixed Object on error, otherwise bool |
*/ |
function _connect($dsn) |
{ |
if (is_string($dsn) || is_array($dsn)) { |
$this->db =& MDB2::connect($dsn, $this->options['db_options']); |
} elseif (is_subclass_of($dsn, 'MDB2_Driver_Common')) { |
$this->db = $dsn; |
} elseif (is_object($dsn) && MDB2::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 (MDB2::isError($this->db) || PEAR::isError($this->db)) { |
return PEAR::raiseError($this->db->getMessage(), $this->db->code); |
} |
if ($this->options['auto_quote']) { |
$this->options['final_table'] = $this->db->quoteIdentifier($this->options['table'], true); |
$this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol'], true); |
$this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol'], true); |
} else { |
$this->options['final_table'] = $this->options['table']; |
$this->options['final_usernamecol'] = $this->options['usernamecol']; |
$this->options['final_passwordcol'] = $this->options['passwordcol']; |
} |
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 MDB error object. |
*/ |
function _prepare() |
{ |
if (is_subclass_of($this->db, 'MDB2_Driver_Common')) { |
return true; |
} |
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->exec($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'; |
$this->options['db_options'] = array(); |
$this->options['auto_quote'] = true; |
} |
// }}} |
// {{{ _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; |
} |
} |
} |
// }}} |
// {{{ _quoteDBFields() |
/** |
* Quote the db_fields option to avoid the possibility of SQL injection. |
* |
* @access private |
* @return string A properly quoted string that can be concatenated into a |
* SELECT clause. |
*/ |
function _quoteDBFields() |
{ |
if (isset($this->options['db_fields'])) { |
if (is_array($this->options['db_fields'])) { |
if ($this->options['auto_quote']) { |
$fields = array(); |
foreach ($this->options['db_fields'] as $field) { |
$fields[] = $this->db->quoteIdentifier($field, true); |
} |
return implode(', ', $fields); |
} else { |
return implode(', ', $this->options['db_fields']); |
} |
} else { |
if (strlen($this->options['db_fields']) > 0) { |
if ($this->options['auto_quote']) { |
return $this->db->quoteIdentifier($this->options['db_fields'], true); |
} else { |
return $this->options['db_fields']; |
} |
} |
} |
} |
return ''; |
} |
// }}} |
// {{{ 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 |
* @param boolean If true password is secured using a md5 hash |
* the frontend and auth are responsible for making sure the container supports |
* challenge response password authentication |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password, $isChallengeResponse=false) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
//Check if db_fields contains a *, if so assume all columns are selected |
if (is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = sprintf("SELECT %s FROM %s WHERE %s = %s", |
$sql_from, |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->db->quote($username, 'text') |
); |
$res = $this->db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); |
if (MDB2::isError($res) || PEAR::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} |
if (!is_array($res)) { |
$this->activeUser = ''; |
return false; |
} |
// Perform trimming here before the hashing |
$password = trim($password, "\r\n"); |
$res[$this->options['passwordcol']] = trim($res[$this->options['passwordcol']], "\r\n"); |
// If using Challenge Response md5 the pass with the secret |
if ($isChallengeResponse) { |
$res[$this->options['passwordcol']] = |
md5($res[$this->options['passwordcol']].$this->_auth_obj->session['loginchallenege']); |
// UGLY cannot avoid without modifying verifyPassword |
if ($this->options['cryptType'] == 'md5') { |
$res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']]); |
} |
} |
if ($this->verifyPassword($password, |
$res[$this->options['passwordcol']], |
$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 sense |
$this->_auth_obj->setAuthData($key, $value); |
} |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
// {{{ listUsers() |
/** |
* Returns a list of users from the container |
* |
* @return mixed array|PEAR_Error |
* @access public |
*/ |
function listUsers() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$retVal = array(); |
//Check if db_fields contains a *, if so assume all columns are selected |
if ( is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = sprintf('SELECT %s FROM %s', |
$sql_from, |
$this->options['final_table'] |
); |
$res = $this->db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); |
if (MDB2::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 = "") |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$additional_key = ''; |
$additional_value = ''; |
if (is_array($additional)) { |
foreach ($additional as $key => $value) { |
if ($this->options['auto_quote']) { |
$additional_key .= ', ' . $this->db->quoteIdentifier($key, true); |
} else { |
$additional_key .= ', ' . $key; |
} |
$additional_value .= ', ' . $this->db->quote($value, 'text'); |
} |
} |
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->options['final_passwordcol'], |
$additional_key, |
$this->db->quote($username, 'text'), |
$this->db->quote($password, 'text'), |
$additional_value |
); |
$res = $this->query($query); |
if (MDB2::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
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) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$query = sprintf("DELETE FROM %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->db->quote($username, 'text') |
); |
$res = $this->query($query); |
if (MDB2::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
return true; |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password (plain text) |
*/ |
function changePassword($username, $password) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$query = sprintf("UPDATE %s SET %s = %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_passwordcol'], |
$this->db->quote($password, 'text'), |
$this->options['final_usernamecol'], |
$this->db->quote($username, 'text') |
); |
$res = $this->query($query); |
if (MDB2::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
return true; |
} |
// }}} |
// {{{ supportsChallengeResponse() |
/** |
* Determine if this container supports |
* password authentication with challenge response |
* |
* @return bool |
* @access public |
*/ |
function supportsChallengeResponse() |
{ |
return in_array($this->options['cryptType'], array('md5', 'none', '')); |
} |
// }}} |
// {{{ getCryptType() |
/** |
* Returns the selected crypt type for this container |
* |
* @return string Function used to crypt the password |
*/ |
function getCryptType() |
{ |
return $this->options['cryptType']; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/DB.php |
---|
New file |
0,0 → 1,578 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against PEAR DB |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: DB.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR DB |
*/ |
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. |
* |
* @category Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
*/ |
class Auth_Container_DB extends Auth_Container |
{ |
// {{{ properties |
/** |
* 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 = ''; |
// }}} |
// {{{ Auth_Container_DB [constructor] |
/** |
* Constructor of the container class |
* |
* Save the initial options passed to the container. Initiation of the DB |
* connection is no longer performed here and is only done when needed. |
* |
* @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, $this->options['db_options']); |
} elseif (is_subclass_of($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; |
} |
} |
if ($this->options['auto_quote'] && $this->db->dsn['phptype'] != 'sqlite') { |
$this->options['final_table'] = $this->db->quoteIdentifier($this->options['table']); |
$this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol']); |
$this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol']); |
} else { |
$this->options['final_table'] = $this->options['table']; |
$this->options['final_usernamecol'] = $this->options['usernamecol']; |
$this->options['final_passwordcol'] = $this->options['passwordcol']; |
} |
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'; |
$this->options['db_options'] = array(); |
$this->options['auto_quote'] = true; |
} |
// }}} |
// {{{ _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; |
} |
} |
} |
// }}} |
// {{{ _quoteDBFields() |
/** |
* Quote the db_fields option to avoid the possibility of SQL injection. |
* |
* @access private |
* @return string A properly quoted string that can be concatenated into a |
* SELECT clause. |
*/ |
function _quoteDBFields() |
{ |
if (isset($this->options['db_fields'])) { |
if (is_array($this->options['db_fields'])) { |
if ($this->options['auto_quote']) { |
$fields = array(); |
foreach ($this->options['db_fields'] as $field) { |
$fields[] = $this->db->quoteIdentifier($field); |
} |
return implode(', ', $fields); |
} else { |
return implode(', ', $this->options['db_fields']); |
} |
} else { |
if (strlen($this->options['db_fields']) > 0) { |
if ($this->options['auto_quote']) { |
return $this->db->quoteIdentifier($this->options['db_fields']); |
} else { |
return $this->options['db_fields']; |
} |
} |
} |
} |
return ''; |
} |
// }}} |
// {{{ 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 |
* @param boolean If true password is secured using a md5 hash |
* the frontend and auth are responsible for making sure the container supports |
* challenge response password authentication |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password, $isChallengeResponse=false) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
// Find if db_fields contains a *, if so assume all columns are selected |
if (is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = "*"; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = "SELECT ".$sql_from. |
" FROM ".$this->options['final_table']. |
" WHERE ".$this->options['final_usernamecol']." = ".$this->db->quoteSmart($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; |
} |
// Perform trimming here before the hashihg |
$password = trim($password, "\r\n"); |
$res[$this->options['passwordcol']] = trim($res[$this->options['passwordcol']], "\r\n"); |
// If using Challenge Response md5 the pass with the secret |
if ($isChallengeResponse) { |
$res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']] |
.$this->_auth_obj->session['loginchallenege']); |
// UGLY cannot avoid without modifying verifyPassword |
if ($this->options['cryptType'] == 'md5') { |
$res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']]); |
} |
//print " Hashed Password [{$res[$this->options['passwordcol']]}]<br/>\n"; |
} |
if ($this->verifyPassword($password, |
$res[$this->options['passwordcol']], |
$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 |
$this->_auth_obj->setAuthData($key, $value); |
} |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
// {{{ listUsers() |
/** |
* Returns a list of users from the container |
* |
* @return mixed |
* @access public |
*/ |
function listUsers() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$retVal = array(); |
// Find if db_fields contains a *, if so assume all col are selected |
if ( is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = "*"; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = sprintf("SELECT %s FROM %s", |
$sql_from, |
$this->options['final_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 = "") |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if ( isset($this->options['cryptType']) |
&& $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif ( isset($this->options['cryptType']) |
&& function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$additional_key = ''; |
$additional_value = ''; |
if (is_array($additional)) { |
foreach ($additional as $key => $value) { |
if ($this->options['auto_quote']) { |
$additional_key .= ', ' . $this->db->quoteIdentifier($key); |
} else { |
$additional_key .= ', ' . $key; |
} |
$additional_value .= ", " . $this->db->quoteSmart($value); |
} |
} |
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->options['final_passwordcol'], |
$additional_key, |
$this->db->quoteSmart($username), |
$this->db->quoteSmart($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) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$query = sprintf("DELETE FROM %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->db->quoteSmart($username) |
); |
$res = $this->query($query); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password (plain text) |
*/ |
function changePassword($username, $password) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if ( isset($this->options['cryptType']) |
&& $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif ( isset($this->options['cryptType']) |
&& function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$query = sprintf("UPDATE %s SET %s = %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_passwordcol'], |
$this->db->quoteSmart($password), |
$this->options['final_usernamecol'], |
$this->db->quoteSmart($username) |
); |
$res = $this->query($query); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ supportsChallengeResponse() |
/** |
* Determine if this container supports |
* password authentication with challenge response |
* |
* @return bool |
* @access public |
*/ |
function supportsChallengeResponse() |
{ |
return in_array($this->options['cryptType'], array('md5', 'none', '')); |
} |
// }}} |
// {{{ getCryptType() |
/** |
* Returns the selected crypt type for this container |
*/ |
function getCryptType() |
{ |
return($this->options['cryptType']); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/IMAP.php |
---|
New file |
0,0 → 1,206 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against IMAP servers |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Jeroen Houben <jeroen@terena.nl> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: IMAP.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR class for error handling |
*/ |
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 |
* |
* @category Authentication |
* @package Auth |
* @author Jeroen Houben <jeroen@terena.nl> |
* @author Cipriano Groenendal <cipri@campai.nl> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.0 |
*/ |
class Auth_Container_IMAP extends Auth_Container |
{ |
// {{{ properties |
/** |
* Options for the class |
* @var array |
*/ |
var $options = array(); |
// }}} |
// {{{ Auth_Container_IMAP() [constructor] |
/** |
* Constructor of the container class |
* |
* @param $params associative array with host, port, baseDSN, checkServer |
* and userattr key |
* @return object Returns an error object if something went wrong |
* @todo Use PEAR Net_IMAP if IMAP extension not loaded |
*/ |
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; |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* 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; |
} |
// }}} |
// {{{ _checkServer() |
/** |
* Check if the given server and port are reachable |
* |
* @access private |
*/ |
function _checkServer() { |
$fp = @fsockopen ($this->options['host'], $this->options['port'], |
$errno, $errstr, $this->options['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); |
} |
} |
// }}} |
// {{{ _parseOptions() |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
foreach ($array as $key => $value) { |
$this->options[$key] = $value; |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* 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; |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/PEAR.php |
---|
New file |
0,0 → 1,103 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against PEAR website |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: PEAR.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR XML_RPC |
*/ |
require_once 'XML/RPC.php'; |
/** |
* Storage driver for authenticating against PEAR website |
* |
* This driver provides a method for authenticating against the pear.php.net |
* authentication system. |
* |
* @category Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Container_Pear extends Auth_Container |
{ |
// {{{ Auth_Container_Pear() [constructor] |
/** |
* Constructor |
* |
* Currently does nothing |
* |
* @return void |
*/ |
function Auth_Container_Pear() |
{ |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from pear.php.net |
* |
* This function uses the given username and password to authenticate |
* against the pear.php.net website |
* |
* @param string Username |
* @param string Password |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password) |
{ |
$rpc = new XML_RPC_Client('/xmlrpc.php', 'pear.php.net'); |
$rpc_message = new XML_RPC_Message("user.info", array(new XML_RPC_Value($username, "string")) ); |
// Error Checking howto ??? |
$result = $rpc->send($rpc_message); |
$value = $result->value(); |
$userinfo = xml_rpc_decode($value); |
if ($userinfo['password'] == md5($password)) { |
$this->activeUser = $userinfo['handle']; |
foreach ($userinfo as $uk=>$uv) { |
$this->_auth_obj->setAuthData($uk, $uv); |
} |
return true; |
} |
return false; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/RADIUS.php |
---|
New file |
0,0 → 1,180 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against RADIUS servers |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: RADIUS.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR Auth_RADIUS package |
*/ |
require_once "Auth/RADIUS.php"; |
/** |
* Storage driver for authenticating users against RADIUS servers. |
* |
* @category Authentication |
* @package Auth |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.0 |
*/ |
class Auth_Container_RADIUS extends Auth_Container |
{ |
// {{{ properties |
/** |
* Contains a RADIUS object |
* @var object |
*/ |
var $radius; |
/** |
* Contains the authentication type |
* @var string |
*/ |
var $authtype; |
// }}} |
// {{{ Auth_Container_RADIUS() [constructor] |
/** |
* 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 one 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); |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* 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)) { |
$this->radius->challenge = $challenge; |
$this->radius->chapid = 1; |
$this->radius->response = pack('H*', $password); |
} else { |
require_once 'Crypt/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.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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/SOAP5.php |
---|
New file |
0,0 → 1,267 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a SOAP service using PHP5 SoapClient |
* |
* PHP version 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Based upon Auth_Container_SOAP by Bruno Pedro <bpedro@co.sapo.pt> |
* @author Marcel Oelke <puRe@rednoize.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: SOAP5.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @since File available since Release 1.4.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from SOAP using the PHP5 Builtin SOAP |
* functions. This is a modification of the SOAP Storage driver from Bruno Pedro |
* thats using the PEAR SOAP Package. |
* |
* This class takes one parameter (options), where |
* you specify the following fields: |
* * location and uri, or wsdl file |
* * method to call on the SOAP service |
* * usernamefield, the name of the parameter where the username is supplied |
* * passwordfield, the name of the parameter where the password is supplied |
* * matchpassword, whether to look for the password in the response from |
* the function call or assume that no errors means user |
* authenticated. |
* |
* See http://www.php.net/manual/en/ref.soap.php for further details |
* on options for the PHP5 SoapClient which are passed through. |
* |
* Example usage without WSDL: |
* |
* <?php |
* |
* $options = array ( |
* 'wsdl' => NULL, |
* 'location' => 'http://your.soap.service/endpoint', |
* 'uri' => 'urn:/Your/Namespace', |
* 'method' => 'checkAuth', |
* 'usernamefield' => 'username', |
* 'passwordfield' => 'password', |
* 'matchpasswords' => false, |
* '_features' => array ( |
* 'extra_parameter' => 'example_value', |
* 'another_parameter' => 'foobar' |
* ) |
* ); |
* |
* $auth = new Auth('SOAP5', $options); |
* $auth->start(); |
* |
* ?> |
* |
* Example usage with WSDL: |
* |
* <?php |
* |
* $options = array ( |
* 'wsdl' => 'http://your.soap.service/wsdl', |
* 'method' => 'checkAuth', |
* 'usernamefield' => 'username', |
* 'passwordfield' => 'password', |
* 'matchpasswords' => false, |
* '_features' => array ( |
* 'extra_parameter' => 'example_value', |
* 'another_parameter' => 'foobar' |
* ) |
* ); |
* |
* $auth = new Auth('SOAP5', $options); |
* $auth->start(); |
* |
* ?> |
* |
* @category Authentication |
* @package Auth |
* @author Based upon Auth_Container_SOAP by Bruno Pedro <bpedro@co.sapo.pt> |
* @author Marcel Oelke <puRe@rednoize.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @since Class available since Release 1.4.0 |
*/ |
class Auth_Container_SOAP5 extends Auth_Container |
{ |
// {{{ properties |
/** |
* Required options for the class |
* @var array |
* @access private |
*/ |
var $_requiredOptions = array( |
'location', |
'uri', |
'method', |
'usernamefield', |
'passwordfield', |
'wsdl', |
); |
/** |
* 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(); |
// }}} |
// {{{ Auth_Container_SOAP5() |
/** |
* Constructor of the container class |
* |
* @param $options, associative array with endpoint, namespace, method, |
* usernamefield, passwordfield and optional features |
*/ |
function Auth_Container_SOAP5($options) |
{ |
$this->_setDefaults(); |
foreach ($options as $name => $value) { |
$this->_options[$name] = $value; |
} |
if (!empty($this->_options['_features'])) { |
$this->_features = $this->_options['_features']; |
unset($this->_options['_features']); |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* 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) |
{ |
$result = $this->_validateOptions(); |
if (PEAR::isError($result)) |
return $result; |
// create a SOAP client |
$soapClient = new SoapClient($this->_options["wsdl"], $this->_options); |
$params = array(); |
// first, assign the optional features |
foreach ($this->_features as $fieldName => $fieldValue) { |
$params[$fieldName] = $fieldValue; |
} |
// assign username and password ... |
$params[$this->_options['usernamefield']] = $username; |
$params[$this->_options['passwordfield']] = $password; |
try { |
$this->soapResponse = $soapClient->__soapCall($this->_options['method'], $params); |
if ($this->_options['matchpasswords']) { |
// check if passwords match |
if ($password == $this->soapResponse[$this->_options['passwordfield']]) { |
return true; |
} else { |
return false; |
} |
} else { |
return true; |
} |
} catch (SoapFault $e) { |
return PEAR::raiseError("Error retrieving authentication data. Received SOAP Fault: ".$e->faultstring, $e->faultcode); |
} |
} |
// }}} |
// {{{ _validateOptions() |
/** |
* Validate that the options passed to the container class are enough for us to proceed |
* |
* @access private |
* @param array |
*/ |
function _validateOptions($array) |
{ |
if ( ( is_null($this->options['wsdl']) |
&& is_null($this->options['location']) |
&& is_null($this->options['uri'])) |
|| ( is_null($this->options['wsdl']) |
&& ( is_null($this->options['location']) |
|| is_null($this->options['uri'])))) { |
return PEAR::raiseError('Either a WSDL file or a location/uri pair must be specified.'); |
} |
if (is_null($this->options['method'])) { |
return PEAR::raiseError('A method to call on the soap service must be specified.'); |
} |
return true; |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
* @return void |
*/ |
function _setDefaults() |
{ |
$this->options['wsdl'] = null; |
$this->options['location'] = null; |
$this->options['uri'] = null; |
$this->options['method'] = null; |
$this->options['usernamefield'] = 'username'; |
$this->options['passwordfield'] = 'password'; |
$this->options['matchpasswords'] = true; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/vpopmail.php |
---|
New file |
0,0 → 1,87 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against vpopmail setups |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Stanislav Grozev <tacho@orbitel.bg> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: vpopmail.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from vpopmail |
* |
* @category Authentication |
* @package Auth |
* @author Stanislav Grozev <tacho@orbitel.bg> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.0 |
*/ |
class Auth_Container_vpopmail extends Auth_Container { |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* @return void |
*/ |
function Auth_Container_vpopmail() |
{ |
if (!extension_loaded('vpopmail')) { |
return PEAR::raiseError('Cannot use VPOPMail authentication, ' |
.'VPOPMail extension not loaded!', 41, PEAR_ERROR_DIE); |
} |
} |
// }}} |
// {{{ 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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/KADM5.php |
---|
New file |
0,0 → 1,170 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for Authentication on a Kerberos V server. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Andrew Teixeira <ateixeira@gmail.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: KADM5.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.4.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR for error handling |
*/ |
require_once 'PEAR.php'; |
/** |
* Storage driver for Authentication on a Kerberos V server. |
* |
* Available options: |
* hostname: The hostname of the kerberos server |
* realm: The Kerberos V realm |
* timeout: The timeout for checking the server |
* checkServer: Set to true to check if the server is running when |
* constructing the object |
* |
* @category Authentication |
* @package Auth |
* @author Andrew Teixeira <ateixeira@gmail.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.4.0 |
*/ |
class Auth_Container_KADM5 extends Auth_Container { |
// {{{ properties |
/** |
* Options for the class |
* @var string |
*/ |
var $options = array(); |
// }}} |
// {{{ Auth_Container_KADM5() |
/** |
* Constructor of the container class |
* |
* $options can have these keys: |
* 'hostname' The hostname of the kerberos server |
* 'realm' The Kerberos V realm |
* 'timeout' The timeout for checking the server |
* 'checkServer' Set to true to check if the server is running when |
* constructing the object |
* |
* @param $options associative array |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_KADM5($options) { |
if (!extension_loaded('kadm5')) { |
return PEAR::raiseError("Cannot use Kerberos V authentication, KADM5 extension not loaded!", 41, PEAR_ERROR_DIE); |
} |
$this->_setDefaults(); |
if (isset($options['hostname'])) { |
$this->options['hostname'] = $options['hostname']; |
} |
if (isset($options['realm'])) { |
$this->options['realm'] = $options['realm']; |
} |
if (isset($options['timeout'])) { |
$this->options['timeout'] = $options['timeout']; |
} |
if (isset($options['checkServer'])) { |
$this->options['checkServer'] = $options['checkServer']; |
} |
if ($this->options['checkServer']) { |
$this->_checkServer(); |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Try to login to the KADM5 server |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) { |
if ( ($username == NULL) || ($password == NULL) ) { |
return false; |
} |
$server = $this->options['hostname']; |
$realm = $this->options['realm']; |
$check = @kadm5_init_with_password($server, $realm, $username, $password); |
if ($check == false) { |
return false; |
} else { |
return true; |
} |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
*/ |
function _setDefaults() { |
$this->options['hostname'] = 'localhost'; |
$this->options['realm'] = NULL; |
$this->options['timeout'] = 10; |
$this->options['checkServer'] = false; |
} |
// }}} |
// {{{ _checkServer() |
/** |
* Check if the given server and port are reachable |
* |
* @access private |
*/ |
function _checkServer() { |
$fp = @fsockopen ($this->options['hostname'], 88, $errno, $errstr, $this->options['timeout']); |
if (is_resource($fp)) { |
@fclose($fp); |
} else { |
$message = "Error connecting to Kerberos V server " |
.$this->options['hostname'].":".$this->options['port']; |
return PEAR::raiseError($message, 41, PEAR_ERROR_DIE); |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/MDB.php |
---|
New file |
0,0 → 1,573 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against PEAR MDB |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Lorenzo Alberton <l.alberton@quipo.it> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: MDB.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.3 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR MDB package |
*/ |
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. |
* |
* @category Authentication |
* @package Auth |
* @author Lorenzo Alberton <l.alberton@quipo.it> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.3 |
*/ |
class Auth_Container_MDB extends Auth_Container |
{ |
// {{{ properties |
/** |
* Additional options for the storage container |
* @var array |
*/ |
var $options = array(); |
/** |
* MDB object |
* @var object |
*/ |
var $db = null; |
var $dsn = ''; |
/** |
* User that is currently selected from the DB. |
* @var string |
*/ |
var $activeUser = ''; |
// }}} |
// {{{ Auth_Container_MDB() [constructor] |
/** |
* Constructor of the container class |
* |
* Initate connection to the database via PEAR::MDB |
* |
* @param string Connection data or MDB 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 mixed DSN string | array | mdb object |
* @return mixed Object on error, otherwise bool |
*/ |
function _connect($dsn) |
{ |
if (is_string($dsn) || is_array($dsn)) { |
$this->db =& MDB::connect($dsn, $this->options['db_options']); |
} elseif (is_subclass_of($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); |
} |
if ($this->options['auto_quote']) { |
$this->options['final_table'] = $this->db->quoteIdentifier($this->options['table']); |
$this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol']); |
$this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol']); |
} else { |
$this->options['final_table'] = $this->options['table']; |
$this->options['final_usernamecol'] = $this->options['usernamecol']; |
$this->options['final_passwordcol'] = $this->options['passwordcol']; |
} |
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 MDB error object. |
*/ |
function _prepare() |
{ |
if (is_subclass_of($this->db, 'mdb_common')) { |
return true; |
} |
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'; |
$this->options['db_options'] = array(); |
$this->options['auto_quote'] = true; |
} |
// }}} |
// {{{ _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; |
} |
} |
} |
// }}} |
// {{{ _quoteDBFields() |
/** |
* Quote the db_fields option to avoid the possibility of SQL injection. |
* |
* @access private |
* @return string A properly quoted string that can be concatenated into a |
* SELECT clause. |
*/ |
function _quoteDBFields() |
{ |
if (isset($this->options['db_fields'])) { |
if (is_array($this->options['db_fields'])) { |
if ($this->options['auto_quote']) { |
$fields = array(); |
foreach ($this->options['db_fields'] as $field) { |
$fields[] = $this->db->quoteIdentifier($field); |
} |
return implode(', ', $fields); |
} else { |
return implode(', ', $this->options['db_fields']); |
} |
} else { |
if (strlen($this->options['db_fields']) > 0) { |
if ($this->options['auto_quote']) { |
return $this->db->quoteIdentifier($this->options['db_fields']); |
} else { |
return $this->options['db_fields']; |
} |
} |
} |
} |
return ''; |
} |
// }}} |
// {{{ 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 |
* @param boolean If true password is secured using a md5 hash |
* the frontend and auth are responsible for making sure the container supports |
* challenge response password authentication |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password, $isChallengeResponse=false) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
//Check if db_fields contains a *, if so assume all columns are selected |
if (is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = sprintf("SELECT %s FROM %s WHERE %s = %s", |
$sql_from, |
$this->options['final_table'], |
$this->options['final_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; |
} |
// Perform trimming here before the hashing |
$password = trim($password, "\r\n"); |
$res[$this->options['passwordcol']] = trim($res[$this->options['passwordcol']], "\r\n"); |
// If using Challenge Response md5 the pass with the secret |
if ($isChallengeResponse) { |
$res[$this->options['passwordcol']] = |
md5($res[$this->options['passwordcol']].$this->_auth_obj->session['loginchallenege']); |
// UGLY cannot avoid without modifying verifyPassword |
if ($this->options['cryptType'] == 'md5') { |
$res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']]); |
} |
} |
if ($this->verifyPassword($password, |
$res[$this->options['passwordcol']], |
$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 sense |
$this->_auth_obj->setAuthData($key, $value); |
} |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
// {{{ listUsers() |
/** |
* Returns a list of users from the container |
* |
* @return mixed array|PEAR_Error |
* @access public |
*/ |
function listUsers() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$retVal = array(); |
//Check if db_fields contains a *, if so assume all columns are selected |
if ( is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else { |
$sql_from = $this->options['final_usernamecol'] |
.', '.$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = sprintf('SELECT %s FROM %s', |
$sql_from, |
$this->options['final_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 = "") |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$additional_key = ''; |
$additional_value = ''; |
if (is_array($additional)) { |
foreach ($additional as $key => $value) { |
if ($this->options['auto_quote']) { |
$additional_key .= ', ' . $this->db->quoteIdentifier($key); |
} else { |
$additional_key .= ', ' . $key; |
} |
$additional_value .= ', ' . $this->db->getTextValue($value); |
} |
} |
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->options['final_passwordcol'], |
$additional_key, |
$this->db->getTextValue($username), |
$this->db->getTextValue($password), |
$additional_value |
); |
$res = $this->query($query); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
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) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$query = sprintf("DELETE FROM %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_usernamecol'], |
$this->db->getTextValue($username) |
); |
$res = $this->query($query); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
return true; |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password (plain text) |
*/ |
function changePassword($username, $password) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') { |
$cryptFunction = 'strval'; |
} elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$password = $cryptFunction($password); |
$query = sprintf("UPDATE %s SET %s = %s WHERE %s = %s", |
$this->options['final_table'], |
$this->options['final_passwordcol'], |
$this->db->getTextValue($password), |
$this->options['final_usernamecol'], |
$this->db->getTextValue($username) |
); |
$res = $this->query($query); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} |
return true; |
} |
// }}} |
// {{{ supportsChallengeResponse() |
/** |
* Determine if this container supports |
* password authentication with challenge response |
* |
* @return bool |
* @access public |
*/ |
function supportsChallengeResponse() |
{ |
return in_array($this->options['cryptType'], array('md5', 'none', '')); |
} |
// }}} |
// {{{ getCryptType() |
/** |
* Returns the selected crypt type for this container |
* |
* @return string Function used to crypt the password |
*/ |
function getCryptType() |
{ |
return $this->options['cryptType']; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/SOAP.php |
---|
New file |
0,0 → 1,228 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against a SOAP service |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Bruno Pedro <bpedro@co.sapo.pt> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: SOAP.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR package for error handling |
*/ |
require_once "PEAR.php"; |
/** |
* Include PEAR SOAP_Client |
*/ |
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(); |
* |
* ... |
* |
* ?> |
* |
* @category Authentication |
* @package Auth |
* @author Bruno Pedro <bpedro@co.sapo.pt> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.0 |
*/ |
class Auth_Container_SOAP extends Auth_Container |
{ |
// {{{ properties |
/** |
* 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(); |
/** |
* The SOAP client |
* @var mixed |
* @access public |
*/ |
var $soapClient = null; |
// }}} |
// {{{ Auth_Container_SOAP() [constructor] |
/** |
* 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']); |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* 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 |
$this->soapClient = new SOAP_Client($this->_options['endpoint']); |
$this->soapClient->setEncoding($this->_options['encoding']); |
} |
// set the trace option if requested |
if (isset($this->_options['trace'])) { |
$this->soapClient->__options['trace'] = true; |
} |
// set the timeout option if requested |
if (isset($this->_options['timeout'])) { |
$this->soapClient->__options['timeout'] = $this->_options['timeout']; |
} |
// 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 = $this->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; |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/DBLite.php |
---|
New file |
0,0 → 1,298 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Reduced storage driver for use against PEAR DB |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: DBLite.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Include Auth_Container base class |
*/ |
require_once 'Auth/Container.php'; |
/** |
* Include PEAR DB package |
*/ |
require_once 'DB.php'; |
/** |
* A lighter storage driver for fetching login data from a database |
* |
* This driver is derived from the DB storage container but |
* with the user manipulation function removed for smaller file size |
* by the PEAR DB abstraction layer to fetch login data. |
* |
* @category Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Container_DBLite extends Auth_Container |
{ |
// {{{ properties |
/** |
* 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 = ''; |
// }}} |
// {{{ Auth_Container_DBLite() [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_DBLite($dsn) |
{ |
$this->options['table'] = 'auth'; |
$this->options['usernamecol'] = 'username'; |
$this->options['passwordcol'] = 'password'; |
$this->options['dsn'] = ''; |
$this->options['db_fields'] = ''; |
$this->options['cryptType'] = 'md5'; |
$this->options['db_options'] = array(); |
$this->options['auto_quote'] = true; |
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, $this->options['db_options']); |
} elseif (is_subclass_of($dsn, "db_common")) { |
$this->db =& $dsn; |
} else { |
return PEAR::raiseError("Invalid dsn or db object given"); |
} |
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; |
} |
} |
if ($this->options['auto_quote'] && $this->db->dsn['phptype'] != 'sqlite') { |
$this->options['final_table'] = $this->db->quoteIdentifier($this->options['table']); |
$this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol']); |
$this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol']); |
} else { |
$this->options['final_table'] = $this->options['table']; |
$this->options['final_usernamecol'] = $this->options['usernamecol']; |
$this->options['final_passwordcol'] = $this->options['passwordcol']; |
} |
return true; |
} |
// }}} |
// {{{ _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; |
} |
} |
} |
// }}} |
// {{{ _quoteDBFields() |
/** |
* Quote the db_fields option to avoid the possibility of SQL injection. |
* |
* @access private |
* @return string A properly quoted string that can be concatenated into a |
* SELECT clause. |
*/ |
function _quoteDBFields() |
{ |
if (isset($this->options['db_fields'])) { |
if (is_array($this->options['db_fields'])) { |
if ($this->options['auto_quote']) { |
$fields = array(); |
foreach ($this->options['db_fields'] as $field) { |
$fields[] = $this->db->quoteIdentifier($field); |
} |
return implode(', ', $fields); |
} else { |
return implode(', ', $this->options['db_fields']); |
} |
} else { |
if (strlen($this->options['db_fields']) > 0) { |
if ($this->options['auto_quote']) { |
return $this->db->quoteIdentifier($this->options['db_fields']); |
} else { |
$this->options['db_fields']; |
} |
} |
} |
} |
return ''; |
} |
// }}} |
// {{{ 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_fields contains a *, if so assume all col are selected |
if (is_string($this->options['db_fields']) |
&& strstr($this->options['db_fields'], '*')) { |
$sql_from = "*"; |
} else { |
$sql_from = $this->options['final_usernamecol']. |
", ".$this->options['final_passwordcol']; |
if (strlen($fields = $this->_quoteDBFields()) > 0) { |
$sql_from .= ', '.$fields; |
} |
} |
$query = "SELECT ".$sql_from. |
" FROM ".$this->options['final_table']. |
" WHERE ".$this->options['final_usernamecol']." = ".$this->db->quoteSmart($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); |
} |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container/SMBPasswd.php |
---|
New file |
0,0 → 1,177 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Storage driver for use against Samba password files |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: SMBPasswd.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.2.3 |
*/ |
/** |
* Include PEAR File_SMBPasswd |
*/ |
require_once "File/SMBPasswd.php"; |
/** |
* Include Auth_Container Base file |
*/ |
require_once "Auth/Container.php"; |
/** |
* Include PEAR class for error handling |
*/ |
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(); |
* } |
* |
* @category Authentication |
* @package Auth |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @author Adam Ashley <aashley@php.net> |
* @package Auth |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.2.3 |
*/ |
class Auth_Container_SMBPasswd extends Auth_Container |
{ |
// {{{ properties |
/** |
* File_SMBPasswd object |
* @var object |
*/ |
var $pwfile; |
// }}} |
// {{{ Auth_Container_SMBPasswd() [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; |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password |
*/ |
function changePassword($username, $password) |
{ |
$res = $this->pwfile->modUser($username, '', $password); |
if ($res === true) { |
return $this->pwfile->save(); |
} |
return $res; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/Plain.php |
---|
New file |
0,0 → 1,63 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: Plain.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* Implmentation of PLAIN SASL mechanism |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('Auth/SASL/Common.php'); |
class Auth_SASL_Plain extends Auth_SASL_Common |
{ |
/** |
* Returns PLAIN response |
* |
* @param string $authcid Authentication id (username) |
* @param string $pass Password |
* @param string $authzid Autorization id |
* @return string PLAIN Response |
*/ |
function getResponse($authcid, $pass, $authzid = '') |
{ |
return $authzid . chr(0) . $authcid . chr(0) . $pass; |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/DigestMD5.php |
---|
New file |
0,0 → 1,194 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: DigestMD5.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* Implmentation of DIGEST-MD5 SASL mechanism |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('Auth/SASL/Common.php'); |
class Auth_SASL_DigestMD5 extends Auth_SASL_Common |
{ |
/** |
* Provides the (main) client response for DIGEST-MD5 |
* requires a few extra parameters than the other |
* mechanisms, which are unavoidable. |
* |
* @param string $authcid Authentication id (username) |
* @param string $pass Password |
* @param string $challenge The digest challenge sent by the server |
* @param string $hostname The hostname of the machine you're connecting to |
* @param string $service The servicename (eg. imap, pop, acap etc) |
* @param string $authzid Authorization id (username to proxy as) |
* @return string The digest response (NOT base64 encoded) |
* @access public |
*/ |
function getResponse($authcid, $pass, $challenge, $hostname, $service, $authzid = '') |
{ |
$challenge = $this->_parseChallenge($challenge); |
$authzid_string = ''; |
if ($authzid != '') { |
$authzid_string = ',authzid="' . $authzid . '"'; |
} |
if (!empty($challenge)) { |
$cnonce = $this->_getCnonce(); |
$digest_uri = sprintf('%s/%s', $service, $hostname); |
$response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid); |
return sprintf('username="%s",realm="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']); |
} else { |
return PEAR::raiseError('Invalid digest challenge'); |
} |
} |
/** |
* Parses and verifies the digest challenge* |
* |
* @param string $challenge The digest challenge |
* @return array The parsed challenge as an assoc |
* array in the form "directive => value". |
* @access private |
*/ |
function _parseChallenge($challenge) |
{ |
$tokens = array(); |
while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) { |
// Ignore these as per rfc2831 |
if ($matches[1] == 'opaque' OR $matches[1] == 'domain') { |
$challenge = substr($challenge, strlen($matches[0]) + 1); |
continue; |
} |
// Allowed multiple "realm" and "auth-param" |
if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) { |
if (is_array($tokens[$matches[1]])) { |
$tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]); |
} else { |
$tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2])); |
} |
// Any other multiple instance = failure |
} elseif (!empty($tokens[$matches[1]])) { |
$tokens = array(); |
break; |
} else { |
$tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]); |
} |
// Remove the just parsed directive from the challenge |
$challenge = substr($challenge, strlen($matches[0]) + 1); |
} |
/** |
* Defaults and required directives |
*/ |
// Realm |
if (empty($tokens['realm'])) { |
$uname = posix_uname(); |
$tokens['realm'] = $uname['nodename']; |
} |
// Maxbuf |
if (empty($tokens['maxbuf'])) { |
$tokens['maxbuf'] = 65536; |
} |
// Required: nonce, algorithm |
if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) { |
return array(); |
} |
return $tokens; |
} |
/** |
* Creates the response= part of the digest response |
* |
* @param string $authcid Authentication id (username) |
* @param string $pass Password |
* @param string $realm Realm as provided by the server |
* @param string $nonce Nonce as provided by the server |
* @param string $cnonce Client nonce |
* @param string $digest_uri The digest-uri= value part of the response |
* @param string $authzid Authorization id |
* @return string The response= part of the digest response |
* @access private |
*/ |
function _getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '') |
{ |
if ($authzid == '') { |
$A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce); |
} else { |
$A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid); |
} |
$A2 = 'AUTHENTICATE:' . $digest_uri; |
return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2))); |
} |
/** |
* Creates the client nonce for the response |
* |
* @return string The cnonce value |
* @access private |
*/ |
function _getCnonce() |
{ |
if (file_exists('/dev/urandom')) { |
return base64_encode(fread(fopen('/dev/urandom', 'r'), 32)); |
} elseif (file_exists('/dev/random')) { |
return base64_encode(fread(fopen('/dev/random', 'r'), 32)); |
} else { |
$str = ''; |
mt_srand((double)microtime()*10000000); |
for ($i=0; $i<32; $i++) { |
$str .= chr(mt_rand(0, 255)); |
} |
return base64_encode($str); |
} |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/Anonymous.php |
---|
New file |
0,0 → 1,71 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: Anonymous.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* Implmentation of ANONYMOUS SASL mechanism |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('Auth/SASL/Common.php'); |
class Auth_SASL_Anonymous extends Auth_SASL_Common |
{ |
/** |
* Not much to do here except return the token supplied. |
* No encoding, hashing or encryption takes place for this |
* mechanism, simply one of: |
* o An email address |
* o An opaque string not containing "@" that can be interpreted |
* by the sysadmin |
* o Nothing |
* |
* We could have some logic here for the second option, but this |
* would by no means create something interpretable. |
* |
* @param string $token Optional email address or string to provide |
* as trace information. |
* @return string The unaltered input token |
*/ |
function getResponse($token = '') |
{ |
return $token; |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/Common.php |
---|
New file |
0,0 → 1,74 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: Common.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* Common functionality to SASL mechanisms |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
class Auth_SASL_Common |
{ |
/** |
* Function which implements HMAC MD5 digest |
* |
* @param string $key The secret key |
* @param string $data The data to protect |
* @return string The HMAC MD5 digest |
*/ |
function _HMAC_MD5($key, $data) |
{ |
if (strlen($key) > 64) { |
$key = pack('H32', md5($key)); |
} |
if (strlen($key) < 64) { |
$key = str_pad($key, 64, chr(0)); |
} |
$k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64); |
$k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64); |
$inner = pack('H32', md5($k_ipad . $data)); |
$digest = md5($k_opad . $inner); |
return $digest; |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/CramMD5.php |
---|
New file |
0,0 → 1,68 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: CramMD5.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* Implmentation of CRAM-MD5 SASL mechanism |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('Auth/SASL/Common.php'); |
class Auth_SASL_CramMD5 extends Auth_SASL_Common |
{ |
/** |
* Implements the CRAM-MD5 SASL mechanism |
* This DOES NOT base64 encode the return value, |
* you will need to do that yourself. |
* |
* @param string $user Username |
* @param string $pass Password |
* @param string $challenge The challenge supplied by the server. |
* this should be already base64_decoded. |
* |
* @return string The string to pass back to the server, of the form |
* "<user> <digest>". This is NOT base64_encoded. |
*/ |
function getResponse($user, $pass, $challenge) |
{ |
return $user . ' ' . $this->_HMAC_MD5($pass, $challenge); |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL/Login.php |
---|
New file |
0,0 → 1,65 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: Login.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
/** |
* This is technically not a SASL mechanism, however |
* it's used by Net_Sieve, Net_Cyrus and potentially |
* other protocols , so here is a good place to abstract |
* it. |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('Auth/SASL/Common.php'); |
class Auth_SASL_Login extends Auth_SASL_Common |
{ |
/** |
* Pseudo SASL LOGIN mechanism |
* |
* @param string $user Username |
* @param string $pass Password |
* @return string LOGIN string |
*/ |
function getResponse($user, $pass) |
{ |
return sprintf('LOGIN %s %s', $user, $pass); |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/HTTP.php |
---|
New file |
0,0 → 1,795 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2004 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> | |
// | Rui Hirokawa <hirokawa@php.net> | |
// | David Costa <gurugeek@php.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: HTTP.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
// |
require_once "Auth/Auth.php"; |
define('AUTH_HTTP_NONCE_TIME_LEN', 16); |
define('AUTH_HTTP_NONCE_HASH_LEN', 32); |
// {{{ class Auth_HTTP |
/** |
* PEAR::Auth_HTTP |
* |
* The PEAR::Auth_HTTP class provides methods for creating an |
* HTTP authentication system based on RFC-2617 using PHP. |
* |
* Instead of generating an HTML driven form like PEAR::Auth |
* does, this class sends header commands to the clients which |
* cause them to present a login box like they are e.g. used |
* in Apache's .htaccess mechanism. |
* |
* This class requires the PEAR::Auth package. |
* |
* @notes The HTTP Digest Authentication part is based on |
* authentication class written by Tom Pike <tom.pike@xiven.com> |
* |
* @author Martin Jansen <mj@php.net> |
* @author Rui Hirokawa <hirokawa@php.net> |
* @author David Costa <gurugeek@php.net> |
* @package Auth_HTTP |
* @extends Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_HTTP extends Auth |
{ |
// {{{ properties |
/** |
* Authorization method: 'basic' or 'digest' |
* |
* @access public |
* @var string |
*/ |
var $authType = 'basic'; |
/** |
* Name of the realm for Basic Authentication |
* |
* @access public |
* @var string |
* @see drawLogin() |
*/ |
var $realm = "protected area"; |
/** |
* Text to send if user hits cancel button |
* |
* @access public |
* @var string |
* @see drawLogin() |
*/ |
var $CancelText = "Error 401 - Access denied"; |
/** |
* option array |
* |
* @access public |
* @var array |
*/ |
var $options = array(); |
/** |
* flag to indicate the nonce was stale. |
* |
* @access public |
* @var bool |
*/ |
var $stale = false; |
/** |
* opaque string for digest authentication |
* |
* @access public |
* @var string |
*/ |
var $opaque = 'dummy'; |
/** |
* digest URI |
* |
* @access public |
* @var string |
*/ |
var $uri = ''; |
/** |
* authorization info returned by the client |
* |
* @access public |
* @var array |
*/ |
var $auth = array(); |
/** |
* next nonce value |
* |
* @access public |
* @var string |
*/ |
var $nextNonce = ''; |
/** |
* nonce value |
* |
* @access public |
* @var string |
*/ |
var $nonce = ''; |
/** |
* Holds a reference to the global server variable |
* @var array |
*/ |
var $server; |
/** |
* Holds a reference to the global post variable |
* @var array |
*/ |
var $post; |
/** |
* Holds a reference to the global cookie variable |
* @var array |
*/ |
var $cookie; |
// }}} |
// {{{ Constructor |
/** |
* Constructor |
* |
* @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) |
* |
* @return void |
*/ |
function Auth_HTTP($storageDriver, $options = '') |
{ |
/* set default values for options */ |
$this->options = array('cryptType' => 'md5', |
'algorithm' => 'MD5', |
'qop' => 'auth-int,auth', |
'opaquekey' => 'moo', |
'noncekey' => 'moo', |
'digestRealm' => 'protected area', |
'forceDigestOnly' => false, |
'nonceLife' => 300, |
'sessionSharing' => true, |
); |
if (!empty($options['authType'])) { |
$this->authType = strtolower($options['authType']); |
} |
if (is_array($options)) { |
foreach($options as $key => $value) { |
if (array_key_exists( $key, $this->options)) { |
$this->options[$key] = $value; |
} |
} |
if (!empty($this->options['opaquekey'])) { |
$this->opaque = md5($this->options['opaquekey']); |
} |
} |
$this->Auth($storageDriver, $options); |
} |
// }}} |
// {{{ assignData() |
/** |
* Assign values from $PHP_AUTH_USER and $PHP_AUTH_PW or 'Authorization' header |
* to internal variables and sets the session id based |
* on them |
* |
* @access public |
* @return void |
*/ |
function assignData() |
{ |
if (method_exists($this, '_importGlobalVariable')) { |
$this->server = &$this->_importGlobalVariable('server'); |
} |
if ($this->authType == 'basic') { |
if (!empty($this->server['PHP_AUTH_USER'])) { |
$this->username = $this->server['PHP_AUTH_USER']; |
} |
if (!empty($this->server['PHP_AUTH_PW'])) { |
$this->password = $this->server['PHP_AUTH_PW']; |
} |
/** |
* Try to get authentication information from IIS |
*/ |
if (empty($this->username) && empty($this->password)) { |
if (!empty($this->server['HTTP_AUTHORIZATION'])) { |
list($this->username, $this->password) = |
explode(':', base64_decode(substr($this->server['HTTP_AUTHORIZATION'], 6))); |
} |
} |
} elseif ($this->authType == 'digest') { |
$this->username = ''; |
$this->password = ''; |
$this->digest_header = null; |
if (!empty($this->server['PHP_AUTH_DIGEST'])) { |
$this->digest_header = substr($this->server['PHP_AUTH_DIGEST'], |
strpos($this->server['PHP_AUTH_DIGEST'],' ')+1); |
} else { |
$headers = getallheaders(); |
if(isset($headers['Authorization']) && !empty($headers['Authorization'])) { |
$this->digest_header = substr($headers['Authorization'], |
strpos($headers['Authorization'],' ')+1); |
} |
} |
if($this->digest_header) { |
$authtemp = explode(',', $this->digest_header); |
$auth = array(); |
foreach($authtemp as $key => $value) { |
$value = trim($value); |
if(strpos($value,'=') !== false) { |
$lhs = substr($value,0,strpos($value,'=')); |
$rhs = substr($value,strpos($value,'=')+1); |
if(substr($rhs,0,1) == '"' && substr($rhs,-1,1) == '"') { |
$rhs = substr($rhs,1,-1); |
} |
$auth[$lhs] = $rhs; |
} |
} |
} |
if (!isset($auth['uri']) || !isset($auth['realm'])) { |
return; |
} |
if ($this->selfURI() == $auth['uri']) { |
$this->uri = $auth['uri']; |
if (substr($headers['Authorization'],0,7) == 'Digest ') { |
$this->authType = 'digest'; |
if (!isset($auth['nonce']) || !isset($auth['username']) || |
!isset($auth['response']) || !isset($auth['qop']) || |
!isset($auth['nc']) || !isset($auth['cnonce'])){ |
return; |
} |
if ($auth['qop'] != 'auth' && $auth['qop'] != 'auth-int') { |
return; |
} |
$this->stale = $this->_judgeStale($auth['nonce']); |
if ($this->nextNonce == false) { |
return; |
} |
$this->username = $auth['username']; |
$this->password = $auth['response']; |
$this->auth['nonce'] = $auth['nonce']; |
$this->auth['qop'] = $auth['qop']; |
$this->auth['nc'] = $auth['nc']; |
$this->auth['cnonce'] = $auth['cnonce']; |
if (isset($auth['opaque'])) { |
$this->auth['opaque'] = $auth['opaque']; |
} |
} elseif (substr($headers['Authorization'],0,6) == 'Basic ') { |
if ($this->options['forceDigestOnly']) { |
return; // Basic authentication is not allowed. |
} |
$this->authType = 'basic'; |
list($username, $password) = |
explode(':',base64_decode(substr($headers['Authorization'],6))); |
$this->username = $username; |
$this->password = $password; |
} |
} |
} else { |
return PEAR::raiseError('authType is invalid.'); |
} |
if ($this->options['sessionSharing'] && |
isset($this->username) && isset($this->password)) { |
session_id(md5('Auth_HTTP' . $this->username . $this->password)); |
} |
/** |
* set sessionName for AUTH, so that the sessionName is different |
* for distinct realms |
*/ |
$this->_sessionName = "_authhttp".md5($this->realm); |
} |
// }}} |
// {{{ login() |
/** |
* Login function |
* |
* @access private |
* @return void |
*/ |
function login() |
{ |
$login_ok = false; |
if (method_exists($this, '_loadStorage')) { |
$this->_loadStorage(); |
} |
$this->storage->_auth_obj->_sessionName =& $this->_sessionName; |
/** |
* When the user has already entered a username, |
* we have to validate it. |
*/ |
if (!empty($this->username) && !empty($this->password)) { |
if ($this->authType == 'basic' && !$this->options['forceDigestOnly']) { |
if (true === $this->storage->fetchData($this->username, $this->password)) { |
$login_ok = true; |
} |
} else { /* digest authentication */ |
if (!$this->getAuth() || $this->getAuthData('a1') == null) { |
/* |
* note: |
* - only PEAR::DB is supported as container. |
* - password should be stored in container as plain-text |
* (if $options['cryptType'] == 'none') or |
* A1 hashed form (md5('username:realm:password')) |
* (if $options['cryptType'] == 'md5') |
*/ |
$dbs = $this->storage; |
if (!DB::isConnection($dbs->db)) { |
$dbs->_connect($dbs->options['dsn']); |
} |
$query = 'SELECT '.$dbs->options['passwordcol']." FROM ".$dbs->options['table']. |
' WHERE '.$dbs->options['usernamecol']." = '". |
$dbs->db->quoteString($this->username)."' "; |
$pwd = $dbs->db->getOne($query); // password stored in container. |
if (DB::isError($pwd)) { |
return PEAR::raiseError($pwd->getMessage(), $pwd->getCode()); |
} |
if ($this->options['cryptType'] == 'none') { |
$a1 = md5($this->username.':'.$this->options['digestRealm'].':'.$pwd); |
} else { |
$a1 = $pwd; |
} |
$this->setAuthData('a1', $a1, true); |
} else { |
$a1 = $this->getAuthData('a1'); |
} |
$login_ok = $this->validateDigest($this->password, $a1); |
if ($this->nextNonce == false) { |
$login_ok = false; |
} |
} |
if (!$login_ok && 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; |
} |
if (!empty($this->username) && $login_ok && $this->authType == 'digest' |
&& $this->auth['qop'] == 'auth') { |
$this->authenticationInfo(); |
} |
} |
// }}} |
// {{{ drawLogin() |
/** |
* Launch the login box |
* |
* @param string $username Username |
* @return void |
* @access private |
*/ |
function drawLogin($username = "") |
{ |
/** |
* Send the header commands |
*/ |
if ($this->authType == 'basic') { |
header("WWW-Authenticate: Basic realm=\"".$this->realm."\""); |
header('HTTP/1.0 401 Unauthorized'); |
} else if ($this->authType == 'digest') { |
$this->nonce = $this->_getNonce(); |
$wwwauth = 'WWW-Authenticate: Digest '; |
$wwwauth .= 'qop="'.$this->options['qop'].'", '; |
$wwwauth .= 'algorithm='.$this->options['algorithm'].', '; |
$wwwauth .= 'realm="'.$this->options['digestRealm'].'", '; |
$wwwauth .= 'nonce="'.$this->nonce.'", '; |
if ($this->stale) { |
$wwwauth .= 'stale=true, '; |
} |
if (!empty($this->opaque)) { |
$wwwauth .= 'opaque="'.$this->opaque.'"' ; |
} |
$wwwauth .= "\r\n"; |
if (!$this->options['forceDigestOnly']) { |
$wwwauth .= 'WWW-Authenticate: Basic realm="'.$this->realm.'"'; |
} |
header($wwwauth); |
header('HTTP/1.0 401 Unauthorized'); |
} |
/** |
* This code is only executed if the user hits the cancel |
* button or if he enters wrong data 3 times. |
*/ |
if ($this->stale) { |
echo 'Stale nonce value, please re-authenticate.'; |
} else { |
echo $this->CancelText; |
} |
exit; |
} |
// }}} |
// {{{ setRealm() |
/** |
* Set name of the current realm |
* |
* @access public |
* @param string $realm Name of the realm |
* @param string $digestRealm Name of the realm for digest authentication |
* @return void |
*/ |
function setRealm($realm, $digestRealm = '') |
{ |
$this->realm = $realm; |
if (!empty($digestRealm)) { |
$this->options['digestRealm'] = $digestRealm; |
} |
} |
// }}} |
// {{{ setCancelText() |
/** |
* Set the text to send if user hits the cancel button |
* |
* @access public |
* @param string $text Text to send |
* @return void |
*/ |
function setCancelText($text) |
{ |
$this->CancelText = $text; |
} |
// }}} |
// {{{ validateDigest() |
/** |
* judge if the client response is valid. |
* |
* @access private |
* @param string $response client response |
* @param string $a1 password or hashed password stored in container |
* @return bool true if success, false otherwise |
*/ |
function validateDigest($response, $a1) |
{ |
if (method_exists($this, '_importGlobalVariable')) { |
$this->server = &$this->_importGlobalVariable('server'); |
} |
$a2unhashed = $this->server['REQUEST_METHOD'].":".$this->selfURI(); |
if($this->auth['qop'] == 'auth-int') { |
if(isset($GLOBALS["HTTP_RAW_POST_DATA"])) { |
// In PHP < 4.3 get raw POST data from this variable |
$body = $GLOBALS["HTTP_RAW_POST_DATA"]; |
} else if($lines = @file('php://input')) { |
// In PHP >= 4.3 get raw POST data from this file |
$body = implode("\n", $lines); |
} else { |
if (method_exists($this, '_importGlobalVariable')) { |
$this->post = &$this->_importGlobalVariable('post'); |
} |
$body = ''; |
foreach($this->post as $key => $value) { |
if($body != '') $body .= '&'; |
$body .= rawurlencode($key) . '=' . rawurlencode($value); |
} |
} |
$a2unhashed .= ':'.md5($body); |
} |
$a2 = md5($a2unhashed); |
$combined = $a1.':'. |
$this->auth['nonce'].':'. |
$this->auth['nc'].':'. |
$this->auth['cnonce'].':'. |
$this->auth['qop'].':'. |
$a2; |
$expectedResponse = md5($combined); |
if(!isset($this->auth['opaque']) || $this->auth['opaque'] == $this->opaque) { |
if($response == $expectedResponse) { // password is valid |
if(!$this->stale) { |
return true; |
} else { |
$this->drawLogin(); |
} |
} |
} |
return false; |
} |
// }}} |
// {{{ _judgeStale() |
/** |
* judge if nonce from client is stale. |
* |
* @access private |
* @param string $nonce nonce value from client |
* @return bool stale |
*/ |
function _judgeStale($nonce) |
{ |
$stale = false; |
if(!$this->_decodeNonce($nonce, $time, $hash_cli)) { |
$this->nextNonce = false; |
$stale = true; |
return $stale; |
} |
if ($time < time() - $this->options['nonceLife']) { |
$this->nextNonce = $this->_getNonce(); |
$stale = true; |
} else { |
$this->nextNonce = $nonce; |
} |
return $stale; |
} |
// }}} |
// {{{ _nonceDecode() |
/** |
* decode nonce string |
* |
* @access private |
* @param string $nonce nonce value from client |
* @param string $time decoded time |
* @param string $hash decoded hash |
* @return bool false if nonce is invalid |
*/ |
function _decodeNonce($nonce, &$time, &$hash) |
{ |
if (method_exists($this, '_importGlobalVariable')) { |
$this->server = &$this->_importGlobalVariable('server'); |
} |
if (strlen($nonce) != AUTH_HTTP_NONCE_TIME_LEN + AUTH_HTTP_NONCE_HASH_LEN) { |
return false; |
} |
$time = base64_decode(substr($nonce, 0, AUTH_HTTP_NONCE_TIME_LEN)); |
$hash_cli = substr($nonce, AUTH_HTTP_NONCE_TIME_LEN, AUTH_HTTP_NONCE_HASH_LEN); |
$hash = md5($time . $this->server['HTTP_USER_AGENT'] . $this->options['noncekey']); |
if ($hash_cli != $hash) { |
return false; |
} |
return true; |
} |
// }}} |
// {{{ _getNonce() |
/** |
* return nonce to detect timeout |
* |
* @access private |
* @return string nonce value |
*/ |
function _getNonce() |
{ |
if (method_exists($this, '_importGlobalVariable')) { |
$this->server = &$this->_importGlobalVariable('server'); |
} |
$time = time(); |
$hash = md5($time . $this->server['HTTP_USER_AGENT'] . $this->options['noncekey']); |
return base64_encode($time) . $hash; |
} |
// }}} |
// {{{ authenticationInfo() |
/** |
* output HTTP Authentication-Info header |
* |
* @notes md5 hash of contents is required if 'qop' is 'auth-int' |
* |
* @access private |
* @param string MD5 hash of content |
*/ |
function authenticationInfo($contentMD5 = '') { |
if($this->getAuth() && ($this->getAuthData('a1') != null)) { |
$a1 = $this->getAuthData('a1'); |
// Work out authorisation response |
$a2unhashed = ":".$this->selfURI(); |
if($this->auth['qop'] == 'auth-int') { |
$a2unhashed .= ':'.$contentMD5; |
} |
$a2 = md5($a2unhashed); |
$combined = $a1.':'. |
$this->nonce.':'. |
$this->auth['nc'].':'. |
$this->auth['cnonce'].':'. |
$this->auth['qop'].':'. |
$a2; |
// Send authentication info |
$wwwauth = 'Authentication-Info: '; |
if($this->nonce != $this->nextNonce) { |
$wwwauth .= 'nextnonce="'.$this->nextNonce.'", '; |
} |
$wwwauth .= 'qop='.$this->auth['qop'].', '; |
$wwwauth .= 'rspauth="'.md5($combined).'", '; |
$wwwauth .= 'cnonce="'.$this->auth['cnonce'].'", '; |
$wwwauth .= 'nc='.$this->auth['nc'].''; |
header($wwwauth); |
} |
} |
// }}} |
// {{{ setOption() |
/** |
* set authentication option |
* |
* @access public |
* @param mixed $name key of option |
* @param mixed $value value of option |
* @return void |
*/ |
function setOption($name, $value = null) |
{ |
if (is_array($name)) { |
foreach($name as $key => $value) { |
if (array_key_exists( $key, $this->options)) { |
$this->options[$key] = $value; |
} |
} |
} else { |
if (array_key_exists( $name, $this->options)) { |
$this->options[$name] = $value; |
} |
} |
} |
// }}} |
// {{{ getOption() |
/** |
* get authentication option |
* |
* @access public |
* @param string $name key of option |
* @return mixed option value |
*/ |
function getOption($name) |
{ |
if (array_key_exists( $name, $this->options)) { |
return $this->options[$name]; |
} |
if ($name == 'CancelText') { |
return $this->CancelText; |
} |
if ($name == 'Realm') { |
return $this->realm; |
} |
return false; |
} |
// }}} |
// {{{ selfURI() |
/** |
* get self URI |
* |
* @access public |
* @return string self URI |
*/ |
function selfURI() |
{ |
if (method_exists($this, '_importGlobalVariable')) { |
$this->server = &$this->_importGlobalVariable('server'); |
} |
if (preg_match("/MSIE/",$this->server['HTTP_USER_AGENT'])) { |
// query string should be removed for MSIE |
$uri = preg_replace("/^(.*)\?/","\\1",$this->server['REQUEST_URI']); |
} else { |
$uri = $this->server['REQUEST_URI']; |
} |
return $uri; |
} |
// }}} |
} |
// }}} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/Auth/Auth.php |
---|
New file |
0,0 → 1,30 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Provide compatibility with previous Auth include location. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Auth.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @deprecated File deprecated since Release 1.2.0 |
*/ |
/** |
* Include Auth package |
*/ |
require_once 'Auth.php'; |
?> |
/tags/v2.0-narmer/api/pear/Auth/Container.php |
---|
New file |
0,0 → 1,224 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Auth_Container Base Class |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Container.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
*/ |
/** |
* Storage class for fetching login data |
* |
* @category Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
*/ |
class Auth_Container |
{ |
// {{{ properties |
/** |
* User that is currently selected from the storage container. |
* |
* @access public |
*/ |
var $activeUser = ""; |
// }}} |
// {{{ Auth_Container() [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($username, $password, $isChallengeResponse=false) |
{ |
} |
// }}} |
// {{{ 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 ((string)crypt($password1, $password2) === (string)$password2); |
break; |
case "none" : |
case "" : |
return ((string)$password1 === (string)$password2); |
break; |
case "md5" : |
return ((string)md5($password1) === (string)$password2); |
break; |
default : |
if (function_exists($cryptType)) { |
return ((string)$cryptType($password1) === (string)$password2); |
} elseif (method_exists($this,$cryptType)) { |
return ((string)$this->$cryptType($password1) === (string)$password2); |
} else { |
return false; |
} |
break; |
} |
} |
// }}} |
// {{{ supportsChallengeResponse() |
/** |
* Returns true if the container supports Challenge Response |
* password authentication |
*/ |
function supportsChallengeResponse() |
{ |
return(false); |
} |
// }}} |
// {{{ getCryptType() |
/** |
* Returns the crypt current crypt type of the container |
* |
* @return string |
*/ |
function getCryptType() |
{ |
return(''); |
} |
// }}} |
// {{{ listUsers() |
/** |
* List all users that are available from the storage container |
*/ |
function listUsers() |
{ |
return AUTH_METHOD_NOT_SUPPORTED; |
} |
// }}} |
// {{{ getUser() |
/** |
* 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; |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @param string Username |
* @param string The new password |
*/ |
function changePassword($username, $password) |
{ |
return AUTH_METHOD_NOT_SUPPORTED; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/SASL.php |
---|
New file |
0,0 → 1,98 |
<?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@php.net> | |
// +-----------------------------------------------------------------------+ |
// |
// $Id: SASL.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
/** |
* Client implementation of various SASL mechanisms |
* |
* @author Richard Heyes <richard@php.net> |
* @access public |
* @version 1.0 |
* @package Auth_SASL |
*/ |
require_once('PEAR.php'); |
class Auth_SASL |
{ |
/** |
* Factory class. Returns an object of the request |
* type. |
* |
* @param string $type One of: Anonymous |
* Plain |
* CramMD5 |
* DigestMD5 |
* Types are not case sensitive |
*/ |
function &factory($type) |
{ |
switch (strtolower($type)) { |
case 'anonymous': |
$filename = 'Auth/SASL/Anonymous.php'; |
$classname = 'Auth_SASL_Anonymous'; |
break; |
case 'login': |
$filename = 'Auth/SASL/Login.php'; |
$classname = 'Auth_SASL_Login'; |
break; |
case 'plain': |
$filename = 'Auth/SASL/Plain.php'; |
$classname = 'Auth_SASL_Plain'; |
break; |
case 'crammd5': |
$filename = 'Auth/SASL/CramMD5.php'; |
$classname = 'Auth_SASL_CramMD5'; |
break; |
case 'digestmd5': |
$filename = 'Auth/SASL/DigestMD5.php'; |
$classname = 'Auth_SASL_DigestMD5'; |
break; |
default: |
return PEAR::raiseError('Invalid SASL mechanism type'); |
break; |
} |
require_once($filename); |
return new $classname(); |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Controller.php |
---|
New file |
0,0 → 1,302 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Auth Controller |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Controller.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Controlls access to a group of php access |
* and redirects to a predefined login page as |
* needed |
* |
* In all pages |
* <code> |
* include_once('Auth.php'); |
* include_once('Auth/Controller.php'); |
* $_auth = new Auth('File', 'passwd'); |
* $authController = new Auth_Controller($_auth, 'login.php', 'index.php'); |
* $authController->start(); |
* </code> |
* |
* In login.php |
* <code> |
* include_once('Auth.php'); |
* include_once('Auth/Controller.php'); |
* $_auth = new Auth('File', 'passwd'); |
* $authController = new Auth_Controller($_auth, 'login.php', 'index.php'); |
* $authController->start(); |
* if( $authController->isAuthorised() ){ |
* $authController->redirectBack(); |
* } |
* </code> |
* |
* @category Authentication |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Controller |
{ |
// {{{ properties |
/** |
* The Auth instance this controller is managing |
* |
* @var object Auth |
*/ |
var $auth = null; |
/** |
* The login URL |
* @var string |
* */ |
var $login = null; |
/** |
* The default index page to use when the caller page is not set |
* |
* @var string |
*/ |
var $default = null; |
/** |
* If this is set to true after a succesfull login the |
* Auth_Controller::redirectBack() is invoked automatically |
* |
* @var boolean |
*/ |
var $autoRedirectBack = false; |
// }}} |
// {{{ Auth_Controller() [constructor] |
/** |
* Constructor |
* |
* @param Auth An auth instance |
* @param string The login page |
* @param string The default page to go to if return page is not set |
* @param array Some rules about which urls need to be sent to the login page |
* @return void |
* @todo Add a list of urls which need redirection |
*/ |
function Auth_Controller(&$auth_obj, $login='login.php', $default='index.php', $accessList=array()) |
{ |
$this->auth =& $auth_obj; |
$this->_loginPage = $login; |
$this->_defaultPage = $default; |
@session_start(); |
if (!empty($_GET['return']) && $_GET['return'] && !strstr($_GET['return'], $this->_loginPage)) { |
$this->auth->setAuthData('returnUrl', $_GET['return']); |
} |
if(!empty($_GET['authstatus']) && $this->auth->status == '') { |
$this->auth->status = $_GET['authstatus']; |
} |
} |
// }}} |
// {{{ setAutoRedirectBack() |
/** |
* Enables auto redirection when login is done |
* |
* @param bool Sets the autoRedirectBack flag to this |
* @see Auth_Controller::autoRedirectBack |
* @return void |
*/ |
function setAutoRedirectBack($flag = true) |
{ |
$this->autoRedirectBack = $flag; |
} |
// }}} |
// {{{ redirectBack() |
/** |
* Redirects Back to the calling page |
* |
* @return void |
*/ |
function redirectBack() |
{ |
// If redirectback go there |
// else go to the default page |
$returnUrl = $this->auth->getAuthData('returnUrl'); |
if(!$returnUrl) { |
$returnUrl = $this->_defaultPage; |
} |
// Add some entropy to the return to make it unique |
// avoind problems with cached pages and proxies |
if(strpos($returnUrl, '?') === false) { |
$returnUrl .= '?'; |
} |
$returnUrl .= uniqid(''); |
// Track the auth status |
if($this->auth->status != '') { |
$url .= '&authstatus='.$this->auth->status; |
} |
header('Location:'.$returnUrl); |
print("You could not be redirected to <a href=\"$returnUrl\">$returnUrl</a>"); |
} |
// }}} |
// {{{ redirectLogin() |
/** |
* Redirects to the login Page if not authorised |
* |
* put return page on the query or in auth |
* |
* @return void |
*/ |
function redirectLogin() |
{ |
// Go to the login Page |
// For Auth, put some check to avoid infinite redirects, this should at least exclude |
// the login page |
$url = $this->_loginPage; |
if(strpos($url, '?') === false) { |
$url .= '?'; |
} |
if(!strstr($_SERVER['PHP_SELF'], $this->_loginPage)) { |
$url .= 'return='.urlencode($_SERVER['PHP_SELF']); |
} |
// Track the auth status |
if($this->auth->status != '') { |
$url .= '&authstatus='.$this->auth->status; |
} |
header('Location:'.$url); |
print("You could not be redirected to <a href=\"$url\">$url</a>"); |
} |
// }}} |
// {{{ start() |
/** |
* Starts the Auth Procedure |
* |
* If the page requires login the user is redirected to the login page |
* otherwise the Auth::start is called to initialize Auth |
* |
* @return void |
* @todo Implement an access list which specifies which urls/pages need login and which do not |
*/ |
function start() |
{ |
// Check the accessList here |
// ACL should be a list of urls with allow/deny |
// If allow set allowLogin to false |
// Some wild card matching should be implemented ?,* |
if(!strstr($_SERVER['PHP_SELF'], $this->_loginPage) && !$this->auth->checkAuth()) { |
$this->redirectLogin(); |
} else { |
$this->auth->start(); |
// Logged on and on login page |
if(strstr($_SERVER['PHP_SELF'], $this->_loginPage) && $this->auth->checkAuth()){ |
$this->autoRedirectBack ? |
$this->redirectBack() : |
null ; |
} |
} |
} |
// }}} |
// {{{ isAuthorised() |
/** |
* Checks is the user is logged on |
* @see Auth::checkAuth() |
*/ |
function isAuthorised() |
{ |
return($this->auth->checkAuth()); |
} |
// }}} |
// {{{ checkAuth() |
/** |
* Proxy call to auth |
* @see Auth::checkAuth() |
*/ |
function checkAuth() |
{ |
return($this->auth->checkAuth()); |
} |
// }}} |
// {{{ logout() |
/** |
* Proxy call to auth |
* @see Auth::logout() |
*/ |
function logout() |
{ |
return($this->auth->logout()); |
} |
// }}} |
// {{{ getUsername() |
/** |
* Proxy call to auth |
* @see Auth::getUsername() |
*/ |
function getUsername() |
{ |
return($this->auth->getUsername()); |
} |
// }}} |
// {{{ getStatus() |
/** |
* Proxy call to auth |
* @see Auth::getStatus() |
*/ |
function getStatus() |
{ |
return($this->auth->getStatus()); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/PrefManager.php |
---|
New file |
0,0 → 1,426 |
<?php |
require_once("DB.php"); |
/** |
* A simple preference manager, takes userid, preference name pairs and returns the value |
* of that preference. |
* |
* CREATE TABLE `preferences` ( |
* `user_id` varchar( 255 ) NOT NULL default '', |
* `pref_id` varchar( 32 ) NOT NULL default '', |
* `pref_value` longtext NOT NULL , |
* PRIMARY KEY ( `user_id` , `pref_id` ) |
* ) |
* |
* @author Jon Wood <jon@jellybob.co.uk> |
* @package Auth_PrefManager |
* @category Authentication |
*/ |
class Auth_PrefManager |
{ |
/** |
* The database object. |
* @var object |
* @access private |
*/ |
var $_db; |
/** |
* The user name to get preferences from if the user specified doesn't |
* have that preference set. |
* @var string |
* @access private |
*/ |
var $_defaultUser = "__default__"; |
/** |
* Should we search for default values, or just fail when we find out that |
* the specified user didn't have it set. |
* |
* @var bool |
* @access private |
*/ |
var $_returnDefaults = true; |
/** |
* The table containing the preferences. |
* @var string |
* @access private |
*/ |
var $_table = "preferences"; |
/** |
* The column containing user ids. |
* @var string |
* @access private |
*/ |
var $_userColumn = "user_id"; |
/** |
* The column containing preference names. |
* @var string |
* @access private |
*/ |
var $_nameColumn = "pref_id"; |
/** |
* The column containing preference values. |
* @var string |
* @access private |
*/ |
var $_valueColumn = "pref_value"; |
/** |
* The quoted value column. |
* @var string |
* @access private |
*/ |
var $_valueColumnQuoted = "pref_value"; |
/** |
* The session variable that the cache array is stored in. |
* @var string |
* @access private |
*/ |
var $_cacheName = "prefCache"; |
/** |
* The last error given. |
* @var string |
* @access private |
*/ |
var $_lastError; |
/** |
* Defines whether the cache should be used or not. |
* @var bool |
* @access private |
*/ |
var $_useCache = true; |
/** |
* Defines whether values should be serialized before saving. |
* @var bool |
* @access private |
*/ |
var $_serialize = false; |
/** |
* Constructor |
* |
* Options: |
* table: The table to get prefs from. [preferences] |
* userColumn: The field name to search for userid's [user_id] |
* nameColumn: The field name to search for preference names [pref_name] |
* valueColumn: The field name to search for preference values [pref_value] |
* defaultUser: The userid assigned to default values [__default__] |
* cacheName: The name of cache in the session variable ($_SESSION[cacheName]) [prefsCache] |
* useCache: Whether or not values should be cached. |
* serialize: Should preference values be serialzed before saving? |
* |
* @param string $dsn The DSN of the database connection to make, or a DB object. |
* @param array $properties An array of properties to set. |
* @param string $defaultUser The default user to manage for. |
* @return bool Success or failure. |
* @access public |
*/ |
function Auth_PrefManager($dsn, $properties = NULL) |
{ |
// Connect to the database. |
if (isset($dsn)) { |
if (is_string($dsn)) { |
$this->_db = DB::Connect($dsn); |
if (DB::isError($this->_db)) { |
$this->_lastError = "DB Error: ".$this->_db->getMessage(); |
} |
} else if (is_subclass_of($dsn, 'db_common')) { |
$this->_db = &$dsn; |
} else { |
$this->_lastError = "Invalid DSN specified."; |
return false; |
} |
} else { |
$this->_lastError = "No DSN specified."; |
return false; |
} |
if (is_array($properties)) { |
if (isset($properties["table"])) { $this->_table = $this->_db->quoteIdentifier($properties["table"]); } |
if (isset($properties["userColumn"])) { $this->_userColumn = $this->_db->quoteIdentifier($properties["userColumn"]); } |
if (isset($properties["nameColumn"])) { $this->_nameColumn = $this->_db->quoteIdentifier($properties["nameColumn"]); } |
if (isset($properties["valueColumn"])) { $this->_valueColumn = $properties["valueColumn"]; } |
if (isset($properties["valueColumn"])) { $this->_valueColumnQuoted = $this->_db->quoteIdentifier($properties["valueColumn"]); } |
if (isset($properties["defaultUser"])) { $this->_defaultUser = $properties["defaultUser"]; } |
if (isset($properties["cacheName"])) { $this->_cacheName = $properties["cacheName"]; } |
if (isset($properties["useCache"])) { $this->_useCache = $properties["useCache"]; } |
if (isset($properties["serialize"])) { $this->_serialize = $properties["serialize"]; } |
} |
return true; |
} |
function setReturnDefaults($returnDefaults = true) |
{ |
if (is_bool($returnDefaults)) { |
$this->_returnDefaults = $returnDefaults; |
} |
} |
/** |
* Sets whether the cache should be used. |
* |
* @param bool $use Should the cache be used. |
* @access public |
*/ |
function useCache($use = true) |
{ |
$this->_useCache = $use; |
} |
/** |
* Cleans out the cache. |
* |
* @access public |
*/ |
function clearCache() |
{ |
unset($_SESSION[$this->_cacheName]); |
} |
/** |
* Get a preference for the specified user, or, if returning default values |
* is enabled, the default. |
* |
* @param string $user_id The user to get the preference for. |
* @param string $pref_id The preference to get. |
* @param bool $showDefaults Should default values be searched (overrides the global setting). |
* @return mixed The value if it's found, or NULL if it isn't. |
* @access public |
*/ |
function getPref($user_id, $pref_id, $showDefaults = true) |
{ |
if (isset($_SESSION[$this->_cacheName][$user_id][$pref_id]) && $this->_useCache) { |
// Value is cached for the specified user, so give them the cached copy. |
return $_SESSION[$this->_cacheName][$user_id][$pref_id]; |
} else { |
// Not cached, search the database for this user's preference. |
$query = sprintf("SELECT * FROM %s WHERE %s=%s AND %s=%s", $this->_table, |
$this->_userColumn, |
$this->_db->quote($user_id), |
$this->_nameColumn, |
$this->_db->quote($pref_id)); |
$result = $this->_db->query($query); |
if (DB::isError($result)) { |
// Ouch! The query failed! |
$this->_lastError = "DB Error: ".$result->getMessage(); |
return NULL; |
} else if ($result->numRows()) { |
// The query found a value, so we can cache that, and then return it. |
$row = $result->fetchRow(DB_FETCHMODE_ASSOC); |
$_SESSION[$this->_cacheName][$user_id][$pref_id] = $this->_unpack($row[$this->_valueColumn]); |
return $_SESSION[$this->_cacheName][$user_id][$pref_id]; |
} else if ($this->_returnDefaults && $showDefaults) { |
// I was doing this with a call to getPref again, but it threw things into an |
// infinite loop if the default value didn't exist. If you can fix that, it would |
// be great ;) |
if (isset($_SESSION[$this->_cacheName][$this->_defaultUser][$pref_id]) && $this->_useCache) { |
$_SESSION[$this->_cacheName][$user_id][$pref_id] = $_SESSION[$this->_cacheName][$this->_defaultUser][$pref_id]; |
return $_SESSION[$this->_cacheName][$this->_defaultUser][$pref_id]; |
} else { |
$query = sprintf("SELECT * FROM %s WHERE %s=%s AND %s=%s", $this->_table, |
$this->_userColumn, |
$this->_db->quote($this->_defaultUser), |
$this->_nameColumn, |
$this->_db->quote($pref_id)); |
$result = $this->_db->query($query); |
if (DB::isError($result)) { |
$this->_lastError = "DB Error: ".$result->getMessage(); |
return NULL; |
} else { |
if ($result->numRows()) { |
$row = $result->fetchRow(DB_FETCHMODE_ASSOC); |
$_SESSION[$this->_cacheName][$this->_defaultUser][$pref_id] = $this->_unpack($row[$this->_valueColumn]); |
$_SESSION[$this->_cacheName][$user_id][$pref_id] = $_SESSION[$this->_cacheName][$this->_defaultUser][$pref_id]; |
return $_SESSION[$this->_cacheName][$user_id][$pref_id]; |
} else { |
return NULL; |
} |
} |
} |
} else { |
// We've used up all the resources we're allowed to search, so return a NULL. |
return NULL; |
} |
} |
} |
/** |
* A shortcut function for getPref($this->_defaultUser, $pref_id, $value), |
* useful if you have a logged in user, but want to get defaults anyway. |
* |
* @param string $pref_id The name of the preference to get. |
* @return mixed The value if it's found, or NULL if it isn't. |
* @access public |
*/ |
function getDefaultPref($pref_id) |
{ |
return $this->getPref($this->_defaultUser, $pref_id); |
} |
/** |
* Set a preference for the specified user. |
* |
* @param string $user_id The user to set for. |
* @param string $pref_id The preference to set. |
* @param mixed $value The value it should be set to. |
* @return bool Sucess or failure. |
* @access public |
*/ |
function setPref($user_id, $pref_id, $value) |
{ |
// Start off by checking if the preference is already set (if it is we need to do |
// an UPDATE, if not, it's an INSERT. |
if ($this->_exists($user_id, $pref_id, false)) { |
$query = sprintf("UPDATE %s SET %s=%s WHERE %s=%s AND %s=%s", $this->_table, |
$this->_valueColumnQuoted, |
$this->_db->quote($this->_pack($value)), |
$this->_userColumn, |
$this->_db->quote($user_id), |
$this->_nameColumn, |
$this->_db->quote($pref_id)); |
} else { |
$query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES(%s, %s, %s)", $this->_table, |
$this->_userColumn, |
$this->_nameColumn, |
$this->_valueColumnQuoted, |
$this->_db->quote($user_id), |
$this->_db->quote($pref_id), |
$this->_db->quote($this->_pack($value))); |
} |
$result = $this->_db->query($query); |
if (DB::isError($result)) { |
$this->_lastError = "DB Error: ".$result->getMessage(); |
return false; |
} else { |
if ($this->_useCache) { |
$_SESSION[$this->_cacheName][$user_id][$pref_id] = $value; |
} |
return true; |
} |
} |
/** |
* A shortcut function for setPref($this->_defaultUser, $pref_id, $value) |
* |
* @param string $pref_id The name of the preference to set. |
* @param mixed $value The value to set it to. |
* @return bool Sucess or failure. |
* @access public |
*/ |
function setDefaultPref($pref_id, $value) |
{ |
return $this->setPref($this->_defaultUser, $pref_id, $value); |
} |
/** |
* Deletes a preference for the specified user. |
* |
* @param string $user_id The userid of the user to delete from. |
* @param string $pref_id The preference to delete. |
* @return bool Success/Failure |
* @access public |
*/ |
function deletePref($user_id, $pref_id) |
{ |
if ($this->getPref($user_id, $pref_id) == NULL) { |
// The user doesn't have this variable anyway ;) |
return true; |
} else { |
$query = sprintf("DELETE FROM %s WHERE %s=%s AND %s=%s", $this->_table, |
$this->_userColumn, |
$this->_db->quote($user_id), |
$this->_nameColumn, |
$this->_db->quote($pref_id)); |
$result = $this->_db->query($query); |
if (DB::isError($result)) { |
$this->_lastError = "DB Error: ".$result->getMessage(); |
return false; |
} else { |
if ($this->_useCache) { |
unset($_SESSION[$this->_cacheName][$user_id][$pref_id]); |
} |
return true; |
} |
} |
} |
/** |
* Deletes a preference for the default user. |
* |
* @param string $pref_id The preference to delete. |
* @return bool Success/Failure |
* @access public |
*/ |
function deleteDefaultPref($pref_id) |
{ |
return $this->deletePref($this->_defaultUser, $pref_id); |
} |
/** |
* Checks if a preference exists in the database. |
* |
* @param string $user_id The userid of the preference owner. |
* @param string $pref_id The preference to check for. |
* @return bool True if the preference exists. |
* @access private |
*/ |
function _exists($user_id, $pref_id) |
{ |
$query = sprintf("SELECT COUNT(%s) FROM %s WHERE %s=%s AND %s=%s", $this->_nameColumn, |
$this->_table, |
$this->_userColumn, |
$this->_db->quoteSmart($user_id), |
$this->_nameColumn, |
$this->_db->quote($pref_id)); |
$result = $this->_db->getOne($query); |
if (DB::isError($result)) { |
$this->_lastError = "DB Error: ".$result->getMessage(); |
return false; |
} else { |
return (bool)$result; |
} |
} |
/** |
* Does anything needed to prepare a value for saving in the database. |
* |
* @param mixed $value The value to be saved. |
* @return string The value in a format valid for saving to the database. |
* @access private |
*/ |
function _pack($value) |
{ |
if ($this->_serialize) { |
return serialize($value); |
} else { |
return $value; |
} |
} |
/** |
* Does anything needed to create a value of the preference, such as unserializing. |
* |
* @param string $value The value of the preference. |
* @return mixed The unpacked version of the preference. |
* @access private |
*/ |
function _unpack($value) |
{ |
if ($this->_serialize) { |
return unserialize($value); |
} else { |
return $value; |
} |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/RADIUS.php |
---|
New file |
0,0 → 1,964 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
/* |
Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.com> |
All rights reserved. |
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 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. |
This code cannot simply be copied and put under the GNU Public License or |
any other GPL-like (LGPL, GPL2) License. |
$Id: RADIUS.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
*/ |
require_once 'PEAR.php'; |
/** |
* Client implementation of RADIUS. This are wrapper classes for |
* the RADIUS PECL. |
* Provides RADIUS Authentication (RFC2865) and RADIUS Accounting (RFC2866). |
* |
* @package Auth_RADIUS |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @access public |
* @version $Revision: 1.1 $ |
*/ |
/** |
* class Auth_RADIUS |
* |
* Abstract base class for RADIUS |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS extends PEAR { |
/** |
* List of RADIUS servers. |
* @var array |
* @see addServer(), putServer() |
*/ |
var $_servers = array(); |
/** |
* Path to the configuration-file. |
* @var string |
* @see setConfigFile() |
*/ |
var $_configfile = null; |
/** |
* Resource. |
* @var resource |
* @see open(), close() |
*/ |
var $res = null; |
/** |
* Username for authentication and accounting requests. |
* @var string |
*/ |
var $username = null; |
/** |
* Password for plaintext-authentication (PAP). |
* @var string |
*/ |
var $password = null; |
/** |
* List of known attributes. |
* @var array |
* @see dumpAttributes(), getAttributes() |
*/ |
var $attributes = array(); |
/** |
* List of raw attributes. |
* @var array |
* @see dumpAttributes(), getAttributes() |
*/ |
var $rawAttributes = array(); |
/** |
* List of raw vendor specific attributes. |
* @var array |
* @see dumpAttributes(), getAttributes() |
*/ |
var $rawVendorAttributes = array(); |
/** |
* Constructor |
* |
* Loads the RADIUS PECL/extension |
* |
* @return void |
*/ |
function Auth_RADIUS() |
{ |
$this->PEAR(); |
$this->loadExtension('radius'); |
} |
/** |
* Adds a RADIUS server to the list of servers for requests. |
* |
* At most 10 servers may be specified. When multiple servers |
* are given, they are tried in round-robin fashion until a |
* valid response is received |
* |
* @access public |
* @param string $servername Servername or IP-Address |
* @param integer $port Portnumber |
* @param string $sharedSecret Shared secret |
* @param integer $timeout Timeout for each request |
* @param integer $maxtries Max. retries for each request |
* @return void |
*/ |
function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 3, $maxtries = 3) |
{ |
$this->_servers[] = array($servername, $port, $sharedSecret, $timeout, $maxtries); |
} |
/** |
* Returns an error message, if an error occurred. |
* |
* @access public |
* @return string |
*/ |
function getError() |
{ |
return radius_strerror($this->res); |
} |
/** |
* Sets the configuration-file. |
* |
* @access public |
* @param string $file Path to the configuration file |
* @return void |
*/ |
function setConfigfile($file) |
{ |
$this->_configfile = $file; |
} |
/** |
* Puts an attribute. |
* |
* @access public |
* @param integer $attrib Attribute-number |
* @param mixed $port Attribute-value |
* @param type $type Attribute-type |
* @return bool true on success, false on error |
*/ |
function putAttribute($attrib, $value, $type = null) |
{ |
if ($type == null) { |
$type = gettype($value); |
} |
switch ($type) { |
case 'integer': |
return radius_put_int($this->res, $attrib, $value); |
case 'addr': |
return radius_put_addr($this->res, $attrib, $value); |
case 'string': |
default: |
return radius_put_attr($this->res, $attrib, $value); |
} |
} |
/** |
* Puts a vendor-specific attribute. |
* |
* @access public |
* @param integer $vendor Vendor (MSoft, Cisco, ...) |
* @param integer $attrib Attribute-number |
* @param mixed $port Attribute-value |
* @param type $type Attribute-type |
* @return bool true on success, false on error |
*/ |
function putVendorAttribute($vendor, $attrib, $value, $type = null) |
{ |
if ($type == null) { |
$type = gettype($value); |
} |
switch ($type) { |
case 'integer': |
return radius_put_vendor_int($this->res, $vendor, $attrib, $value); |
case 'addr': |
return radius_put_vendor_addr($this->res, $vendor,$attrib, $value); |
case 'string': |
default: |
return radius_put_vendor_attr($this->res, $vendor, $attrib, $value); |
} |
} |
/** |
* Prints known attributes received from the server. |
* |
* @access public |
*/ |
function dumpAttributes() |
{ |
foreach ($this->attributes as $name => $data) { |
echo "$name:$data<br>\n"; |
} |
} |
/** |
* Overwrite this. |
* |
* @access public |
*/ |
function open() |
{ |
} |
/** |
* Overwrite this. |
* |
* @access public |
*/ |
function createRequest() |
{ |
} |
/** |
* Puts standard attributes. |
* |
* @access public |
*/ |
function putStandardAttributes() |
{ |
if (isset($_SERVER)) { |
$var = &$_SERVER; |
} else { |
$var = &$GLOBALS['HTTP_SERVER_VARS']; |
} |
$this->putAttribute(RADIUS_NAS_IDENTIFIER, isset($var['HTTP_HOST']) ? $var['HTTP_HOST'] : 'localhost'); |
$this->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_VIRTUAL); |
$this->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_FRAMED); |
$this->putAttribute(RADIUS_FRAMED_PROTOCOL, RADIUS_PPP); |
$this->putAttribute(RADIUS_CALLING_STATION_ID, isset($var['REMOTE_HOST']) ? $var['REMOTE_HOST'] : '127.0.0.1'); |
} |
/** |
* Puts custom attributes. |
* |
* @access public |
*/ |
function putAuthAttributes() |
{ |
if (isset($this->username)) { |
$this->putAttribute(RADIUS_USER_NAME, $this->username); |
} |
} |
/** |
* Configures the radius library. |
* |
* @access public |
* @param string $servername Servername or IP-Address |
* @param integer $port Portnumber |
* @param string $sharedSecret Shared secret |
* @param integer $timeout Timeout for each request |
* @param integer $maxtries Max. retries for each request |
* @return bool true on success, false on error |
* @see addServer() |
*/ |
function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3) |
{ |
if (!radius_add_server($this->res, $servername, $port, $sharedsecret, $timeout, $maxtries)) { |
return false; |
} |
return true; |
} |
/** |
* Configures the radius library via external configurationfile |
* |
* @access public |
* @param string $servername Servername or IP-Address |
* @return bool true on success, false on error |
*/ |
function putConfigfile($file) |
{ |
if (!radius_config($this->res, $file)) { |
return false; |
} |
return true; |
} |
/** |
* Initiates a RADIUS request. |
* |
* @access public |
* @return bool true on success, false on errors |
*/ |
function start() |
{ |
if (!$this->open()) { |
return false; |
} |
foreach ($this->_servers as $s) { |
// Servername, port, sharedsecret, timeout, retries |
if (!$this->putServer($s[0], $s[1], $s[2], $s[3], $s[4])) { |
return false; |
} |
} |
if (!empty($this->_configfile)) { |
if (!$this->putConfigfile($this->_configfile)) { |
return false; |
} |
} |
$this->createRequest(); |
$this->putStandardAttributes(); |
$this->putAuthAttributes(); |
return true; |
} |
/** |
* Sends a prepared RADIUS request and waits for a response |
* |
* @access public |
* @return mixed true on success, false on reject, PEAR_Error on error |
*/ |
function send() |
{ |
$req = radius_send_request($this->res); |
if (!$req) { |
return $this->raiseError('Error sending request: ' . $this->getError()); |
} |
switch($req) { |
case RADIUS_ACCESS_ACCEPT: |
if (is_subclass_of($this, 'auth_radius_acct')) { |
return $this->raiseError('RADIUS_ACCESS_ACCEPT is unexpected for accounting'); |
} |
return true; |
case RADIUS_ACCESS_REJECT: |
return false; |
case RADIUS_ACCOUNTING_RESPONSE: |
if (is_subclass_of($this, 'auth_radius_pap')) { |
return $this->raiseError('RADIUS_ACCOUNTING_RESPONSE is unexpected for authentication'); |
} |
return true; |
default: |
return $this->raiseError("Unexpected return value: $req"); |
} |
} |
/** |
* Reads all received attributes after sending the request. |
* |
* This methos stores know attributes in the property attributes, |
* all attributes (including known attibutes) are stored in rawAttributes |
* or rawVendorAttributes. |
* NOTE: call this functio also even if the request was rejected, because the |
* Server returns usualy an errormessage |
* |
* @access public |
* @return bool true on success, false on error |
*/ |
function getAttributes() |
{ |
while ($attrib = radius_get_attr($this->res)) { |
if (!is_array($attrib)) { |
return false; |
} |
$attr = $attrib['attr']; |
$data = $attrib['data']; |
$this->rawAttributes[$attr] = $data; |
switch ($attr) { |
case RADIUS_FRAMED_IP_ADDRESS: |
$this->attributes['framed_ip'] = radius_cvt_addr($data); |
break; |
case RADIUS_FRAMED_IP_NETMASK: |
$this->attributes['framed_mask'] = radius_cvt_addr($data); |
break; |
case RADIUS_FRAMED_MTU: |
$this->attributes['framed_mtu'] = radius_cvt_int($data); |
break; |
case RADIUS_FRAMED_COMPRESSION: |
$this->attributes['framed_compression'] = radius_cvt_int($data); |
break; |
case RADIUS_SESSION_TIMEOUT: |
$this->attributes['session_timeout'] = radius_cvt_int($data); |
break; |
case RADIUS_IDLE_TIMEOUT: |
$this->attributes['idle_timeout'] = radius_cvt_int($data); |
break; |
case RADIUS_SERVICE_TYPE: |
$this->attributes['service_type'] = radius_cvt_int($data); |
break; |
case RADIUS_CLASS: |
$this->attributes['class'] = radius_cvt_int($data); |
break; |
case RADIUS_FRAMED_PROTOCOL: |
$this->attributes['framed_protocol'] = radius_cvt_int($data); |
break; |
case RADIUS_FRAMED_ROUTING: |
$this->attributes['framed_routing'] = radius_cvt_int($data); |
break; |
case RADIUS_FILTER_ID: |
$this->attributes['filter_id'] = radius_cvt_string($data); |
break; |
case RADIUS_VENDOR_SPECIFIC: |
$attribv = radius_get_vendor_attr($data); |
if (!is_array($attribv)) { |
return false; |
} |
$vendor = $attribv['vendor']; |
$attrv = $attribv['attr']; |
$datav = $attribv['data']; |
$this->rawVendorAttributes[$vendor][$attrv] = $datav; |
if ($vendor == RADIUS_VENDOR_MICROSOFT) { |
switch ($attrv) { |
case RADIUS_MICROSOFT_MS_CHAP2_SUCCESS: |
$this->attributes['ms_chap2_success'] = radius_cvt_string($datav); |
break; |
case RADIUS_MICROSOFT_MS_CHAP_ERROR: |
$this->attributes['ms_chap_error'] = radius_cvt_string(substr($datav,1)); |
break; |
case RADIUS_MICROSOFT_MS_CHAP_DOMAIN: |
$this->attributes['ms_chap_domain'] = radius_cvt_string($datav); |
break; |
case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: |
$this->attributes['ms_mppe_encryption_policy'] = radius_cvt_int($datav); |
break; |
case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: |
$this->attributes['ms_mppe_encryption_types'] = radius_cvt_int($datav); |
break; |
case RADIUS_MICROSOFT_MS_CHAP_MPPE_KEYS: |
$demangled = radius_demangle($this->res, $datav); |
$this->attributes['ms_chap_mppe_lm_key'] = substr($demangled, 0, 8); |
$this->attributes['ms_chap_mppe_nt_key'] = substr($demangled, 8, RADIUS_MPPE_KEY_LEN); |
break; |
case RADIUS_MICROSOFT_MS_MPPE_SEND_KEY: |
$this->attributes['ms_chap_mppe_send_key'] = radius_demangle_mppe_key($this->res, $datav); |
break; |
case RADIUS_MICROSOFT_MS_MPPE_RECV_KEY: |
$this->attributes['ms_chap_mppe_recv_key'] = radius_demangle_mppe_key($this->res, $datav); |
break; |
case RADIUS_MICROSOFT_MS_PRIMARY_DNS_SERVER: |
$this->attributes['ms_primary_dns_server'] = radius_cvt_string($datav); |
break; |
} |
} |
break; |
} |
} |
return true; |
} |
/** |
* Frees resources. |
* |
* Calling this method is always a good idea, because all security relevant |
* attributes are filled with Nullbytes to leave nothing in the mem. |
* |
* @access public |
*/ |
function close() |
{ |
if ($this->res != null) { |
radius_close($this->res); |
$this->res = null; |
} |
$this->username = str_repeat("\0", strlen($this->username)); |
$this->password = str_repeat("\0", strlen($this->password)); |
} |
} |
/** |
* class Auth_RADIUS_PAP |
* |
* Class for authenticating using PAP (Plaintext) |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_PAP extends Auth_RADIUS |
{ |
/** |
* Constructor |
* |
* @param string $username Username |
* @param string $password Password |
* @return void |
*/ |
function Auth_RADIUS_PAP($username = null, $password = null) |
{ |
$this->Auth_RADIUS(); |
$this->username = $username; |
$this->password = $password; |
} |
/** |
* Creates a RADIUS resource |
* |
* Creates a RADIUS resource for authentication. This should be the first |
* call before you make any other things with the library. |
* |
* @return bool true on success, false on error |
*/ |
function open() |
{ |
$this->res = radius_auth_open(); |
if (!$this->res) { |
return false; |
} |
return true; |
} |
/** |
* Creates an authentication request |
* |
* Creates an authentication request. |
* You MUST call this method before you can put any attribute |
* |
* @return bool true on success, false on error |
*/ |
function createRequest() |
{ |
if (!radius_create_request($this->res, RADIUS_ACCESS_REQUEST)) { |
return false; |
} |
return true; |
} |
/** |
* Put authentication specific attributes |
* |
* @return void |
*/ |
function putAuthAttributes() |
{ |
if (isset($this->username)) { |
$this->putAttribute(RADIUS_USER_NAME, $this->username); |
} |
if (isset($this->password)) { |
$this->putAttribute(RADIUS_USER_PASSWORD, $this->password); |
} |
} |
} |
/** |
* class Auth_RADIUS_CHAP_MD5 |
* |
* Class for authenticating using CHAP-MD5 see RFC1994. |
* Instead og the plaintext password the challenge and |
* the response are needed. |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP |
{ |
/** |
* 8 Bytes binary challenge |
* @var string |
*/ |
var $challenge = null; |
/** |
* 16 Bytes MD5 response binary |
* @var string |
*/ |
var $response = null; |
/** |
* Id of the authentication request. Should incremented after every request. |
* @var integer |
*/ |
var $chapid = 1; |
/** |
* Constructor |
* |
* @param string $username Username |
* @param string $challenge 8 Bytes Challenge (binary) |
* @param integer $chapid Requestnumber |
* @return void |
*/ |
function Auth_RADIUS_CHAP_MD5($username = null, $challenge = null, $chapid = 1) |
{ |
$this->Auth_RADIUS_PAP(); |
$this->username = $username; |
$this->challenge = $challenge; |
$this->chapid = $chapid; |
} |
/** |
* Put CHAP-MD5 specific attributes |
* |
* For authenticating using CHAP-MD5 via RADIUS you have to put the challenge |
* and the response. The chapid is inserted in the first byte of the response. |
* |
* @return void |
*/ |
function putAuthAttributes() |
{ |
if (isset($this->username)) { |
$this->putAttribute(RADIUS_USER_NAME, $this->username); |
} |
if (isset($this->response)) { |
$response = pack('C', $this->chapid) . $this->response; |
$this->putAttribute(RADIUS_CHAP_PASSWORD, $response); |
} |
if (isset($this->challenge)) { |
$this->putAttribute(RADIUS_CHAP_CHALLENGE, $this->challenge); |
} |
} |
/** |
* Frees resources. |
* |
* Calling this method is always a good idea, because all security relevant |
* attributes are filled with Nullbytes to leave nothing in the mem. |
* |
* @access public |
*/ |
function close() |
{ |
Auth_RADIUS_PAP::close(); |
$this->challenge = str_repeat("\0", strlen($this->challenge)); |
$this->response = str_repeat("\0", strlen($this->response)); |
} |
} |
/** |
* class Auth_RADIUS_MSCHAPv1 |
* |
* Class for authenticating using MS-CHAPv1 see RFC2433 |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5 |
{ |
/** |
* LAN-Manager-Response |
* @var string |
*/ |
var $lmResponse = null; |
/** |
* Wether using deprecated LM-Responses or not. |
* 0 = use LM-Response, 1 = use NT-Response |
* @var bool |
*/ |
var $flags = 1; |
/** |
* Put MS-CHAPv1 specific attributes |
* |
* For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge |
* and the response. The response has this structure: |
* struct rad_mschapvalue { |
* u_char ident; |
* u_char flags; |
* u_char lm_response[24]; |
* u_char response[24]; |
* }; |
* |
* @return void |
*/ |
function putAuthAttributes() |
{ |
if (isset($this->username)) { |
$this->putAttribute(RADIUS_USER_NAME, $this->username); |
} |
if (isset($this->response) || isset($this->lmResponse)) { |
$lmResp = isset($this->lmResponse) ? $this->lmResponse : str_repeat ("\0", 24); |
$ntResp = isset($this->response) ? $this->response : str_repeat ("\0", 24); |
$resp = pack('CC', $this->chapid, $this->flags) . $lmResp . $ntResp; |
$this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_RESPONSE, $resp); |
} |
if (isset($this->challenge)) { |
$this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge); |
} |
} |
} |
/** |
* class Auth_RADIUS_MSCHAPv2 |
* |
* Class for authenticating using MS-CHAPv2 see RFC2759 |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1 |
{ |
/** |
* 16 Bytes binary challenge |
* @var string |
*/ |
var $challenge = null; |
/** |
* 16 Bytes binary Peer Challenge |
* @var string |
*/ |
var $peerChallenge = null; |
/** |
* Put MS-CHAPv2 specific attributes |
* |
* For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge |
* and the response. The response has this structure: |
* struct rad_mschapv2value { |
* u_char ident; |
* u_char flags; |
* u_char pchallenge[16]; |
* u_char reserved[8]; |
* u_char response[24]; |
* }; |
* where pchallenge is the peer challenge. Like for MS-CHAPv1 we set the flags field to 1. |
* @return void |
*/ |
function putAuthAttributes() |
{ |
if (isset($this->username)) { |
$this->putAttribute(RADIUS_USER_NAME, $this->username); |
} |
if (isset($this->response) && isset($this->peerChallenge)) { |
// Response: chapid, flags (1 = use NT Response), Peer challenge, reserved, Response |
$resp = pack('CCa16a8a24',$this->chapid , 1, $this->peerChallenge, str_repeat("\0", 8), $this->response); |
$this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP2_RESPONSE, $resp); |
} |
if (isset($this->challenge)) { |
$this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge); |
} |
} |
/** |
* Frees resources. |
* |
* Calling this method is always a good idea, because all security relevant |
* attributes are filled with Nullbytes to leave nothing in the mem. |
* |
* @access public |
*/ |
function close() |
{ |
Auth_RADIUS_MSCHAPv1::close(); |
$this->peerChallenge = str_repeat("\0", strlen($this->peerChallenge)); |
} |
} |
/** |
* class Auth_RADIUS_Acct |
* |
* Class for RADIUS accounting |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_Acct extends Auth_RADIUS |
{ |
/** |
* Defines where the Authentication was made, possible values are: |
* RADIUS_AUTH_RADIUS, RADIUS_AUTH_LOCAL, RADIUS_AUTH_REMOTE |
* @var integer |
*/ |
var $authentic = null; |
/** |
* Defines the type of the accounting request, on of: |
* RADIUS_START, RADIUS_STOP, RADIUS_ACCOUNTING_ON, RADIUS_ACCOUNTING_OFF |
* @var integer |
*/ |
var $status_type = null; |
/** |
* The time the user was logged in in seconds |
* @var integer |
*/ |
var $session_time = null; |
/** |
* A uniq identifier for the session of the user, maybe the PHP-Session-Id |
* @var string |
*/ |
var $session_id = null; |
/** |
* Constructor |
* |
* Generates a predefined session_id. We use the Remote-Address, the PID, and the Current user. |
* @return void |
*/ |
function Auth_RADIUS_Acct() |
{ |
$this->Auth_RADIUS(); |
if (isset($_SERVER)) { |
$var = &$_SERVER; |
} else { |
$var = &$GLOBALS['HTTP_SERVER_VARS']; |
} |
$this->session_id = sprintf("%s:%d-%s", isset($var['REMOTE_ADDR']) ? $var['REMOTE_ADDR'] : '127.0.0.1' , getmypid(), get_current_user()); |
} |
/** |
* Creates a RADIUS resource |
* |
* Creates a RADIUS resource for accounting. This should be the first |
* call before you make any other things with the library. |
* |
* @return bool true on success, false on error |
*/ |
function open() |
{ |
$this->res = radius_acct_open(); |
if (!$this->res) { |
return false; |
} |
return true; |
} |
/** |
* Creates an accounting request |
* |
* Creates an accounting request. |
* You MUST call this method before you can put any attribute. |
* |
* @return bool true on success, false on error |
*/ |
function createRequest() |
{ |
if (!radius_create_request($this->res, RADIUS_ACCOUNTING_REQUEST)) { |
return false; |
} |
return true; |
} |
/** |
* Put attributes for accounting. |
* |
* Here we put some accounting values. There many more attributes for accounting, |
* but for web-applications only certain attributes make sense. |
* @return void |
*/ |
function putAuthAttributes() |
{ |
$this->putAttribute(RADIUS_ACCT_SESSION_ID, $this->session_id); |
$this->putAttribute(RADIUS_ACCT_STATUS_TYPE, $this->status_type); |
if (isset($this->session_time) && $this->status_type == RADIUS_STOP) { |
$this->putAttribute(RADIUS_ACCT_SESSION_TIME, $this->session_time); |
} |
if (isset($this->authentic)) { |
$this->putAttribute(RADIUS_ACCT_AUTHENTIC, $this->authentic); |
} |
} |
} |
/** |
* class Auth_RADIUS_Acct_Start |
* |
* Class for RADIUS accounting. Its usualy used, after the user has logged in. |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_Acct_Start extends Auth_RADIUS_Acct |
{ |
/** |
* Defines the type of the accounting request. |
* It is set to RADIUS_START by default in this class. |
* @var integer |
*/ |
var $status_type = Auth_RADIUS_Acct_Stop; |
} |
/** |
* class Auth_RADIUS_Acct_Start |
* |
* Class for RADIUS accounting. Its usualy used, after the user has logged out. |
* |
* @package Auth_RADIUS |
*/ |
class Auth_RADIUS_Acct_Stop extends Auth_RADIUS_Acct |
{ |
/** |
* Defines the type of the accounting request. |
* It is set to RADIUS_STOP by default in this class. |
* @var integer |
*/ |
var $status_type = RADIUS_STOP; |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Anonymous.php |
---|
New file |
0,0 → 1,138 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Anonymous authentication support |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Anonymous.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Include Auth package |
*/ |
require_once 'Auth.php'; |
/** |
* Anonymous Authentication |
* |
* This class provides anonymous authentication if username and password |
* were not supplied |
* |
* @category Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Anonymous extends Auth |
{ |
// {{{ properties |
/** |
* Whether to allow anonymous authentication |
* |
* @var boolean |
*/ |
var $allow_anonymous = true; |
/** |
* Username to use for anonymous user |
* |
* @var string |
*/ |
var $anonymous_username = 'anonymous'; |
// }}} |
// {{{ Auth_Anonymous() [constructor] |
/** |
* Pass all parameters to Parent Auth class |
* |
* 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 |
* @see Auth::Auth() |
*/ |
function Auth_Anonymous($storageDriver, $options = '', $loginFunction = '', $showLogin = true) { |
parent::Auth($storageDriver, $options, $loginFunction, $showLogin); |
} |
// }}} |
// {{{ login() |
/** |
* Login function |
* |
* If no username & password is passed then login as the username |
* provided in $this->anonymous_username else call standard login() |
* function. |
* |
* @return void |
* @access private |
* @see Auth::login() |
*/ |
function login() { |
if ( $this->allow_anonymous |
&& empty($this->username) |
&& empty($this->password) ) { |
$this->setAuth($this->anonymous_username); |
if (is_callable($this->loginCallback)) { |
call_user_func_array($this->loginCallback, array($this->username, $this) ); |
} |
} else { |
// Call normal login system |
parent::login(); |
} |
} |
// }}} |
// {{{ forceLogin() |
/** |
* Force the user to login |
* |
* Calling this function forces the user to provide a real username and |
* password before continuing. |
* |
* @return void |
*/ |
function forceLogin() { |
$this->allow_anonymous = false; |
if( !empty($this->session['username']) && $this->session['username'] == $this->anonymous_username ) { |
$this->logout(); |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth/Frontend/md5.js |
---|
New file |
0,0 → 1,256 |
/* |
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message |
* Digest Algorithm, as defined in RFC 1321. |
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. |
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet |
* Distributed under the BSD License |
* See http://pajhome.org.uk/crypt/md5 for more info. |
*/ |
/* |
* Configurable variables. You may need to tweak these to be compatible with |
* the server-side, but the defaults work in most cases. |
*/ |
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ |
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ |
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ |
/* |
* These are the functions you'll usually want to call |
* They take string arguments and return either hex or base-64 encoded strings |
*/ |
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} |
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} |
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} |
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } |
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } |
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } |
/* |
* Perform a simple self-test to see if the VM is working |
*/ |
function md5_vm_test() |
{ |
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; |
} |
/* |
* Calculate the MD5 of an array of little-endian words, and a bit length |
*/ |
function core_md5(x, len) |
{ |
/* append padding */ |
x[len >> 5] |= 0x80 << ((len) % 32); |
x[(((len + 64) >>> 9) << 4) + 14] = len; |
var a = 1732584193; |
var b = -271733879; |
var c = -1732584194; |
var d = 271733878; |
for(var i = 0; i < x.length; i += 16) |
{ |
var olda = a; |
var oldb = b; |
var oldc = c; |
var oldd = d; |
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); |
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); |
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); |
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); |
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); |
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); |
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); |
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); |
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); |
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); |
c = md5_ff(c, d, a, b, x[i+10], 17, -42063); |
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); |
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); |
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); |
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); |
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); |
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); |
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); |
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); |
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); |
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); |
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); |
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); |
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); |
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); |
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); |
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); |
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); |
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); |
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); |
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); |
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); |
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); |
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); |
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); |
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); |
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); |
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); |
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); |
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); |
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); |
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); |
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); |
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); |
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); |
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); |
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); |
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); |
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); |
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); |
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); |
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); |
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); |
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); |
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); |
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); |
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); |
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); |
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); |
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); |
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); |
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); |
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); |
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); |
a = safe_add(a, olda); |
b = safe_add(b, oldb); |
c = safe_add(c, oldc); |
d = safe_add(d, oldd); |
} |
return Array(a, b, c, d); |
} |
/* |
* These functions implement the four basic operations the algorithm uses. |
*/ |
function md5_cmn(q, a, b, x, s, t) |
{ |
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); |
} |
function md5_ff(a, b, c, d, x, s, t) |
{ |
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); |
} |
function md5_gg(a, b, c, d, x, s, t) |
{ |
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); |
} |
function md5_hh(a, b, c, d, x, s, t) |
{ |
return md5_cmn(b ^ c ^ d, a, b, x, s, t); |
} |
function md5_ii(a, b, c, d, x, s, t) |
{ |
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); |
} |
/* |
* Calculate the HMAC-MD5, of a key and some data |
*/ |
function core_hmac_md5(key, data) |
{ |
var bkey = str2binl(key); |
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); |
var ipad = Array(16), opad = Array(16); |
for(var i = 0; i < 16; i++) |
{ |
ipad[i] = bkey[i] ^ 0x36363636; |
opad[i] = bkey[i] ^ 0x5C5C5C5C; |
} |
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); |
return core_md5(opad.concat(hash), 512 + 128); |
} |
/* |
* Add integers, wrapping at 2^32. This uses 16-bit operations internally |
* to work around bugs in some JS interpreters. |
*/ |
function safe_add(x, y) |
{ |
var lsw = (x & 0xFFFF) + (y & 0xFFFF); |
var msw = (x >> 16) + (y >> 16) + (lsw >> 16); |
return (msw << 16) | (lsw & 0xFFFF); |
} |
/* |
* Bitwise rotate a 32-bit number to the left. |
*/ |
function bit_rol(num, cnt) |
{ |
return (num << cnt) | (num >>> (32 - cnt)); |
} |
/* |
* Convert a string to an array of little-endian words |
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored. |
*/ |
function str2binl(str) |
{ |
var bin = Array(); |
var mask = (1 << chrsz) - 1; |
for(var i = 0; i < str.length * chrsz; i += chrsz) |
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); |
return bin; |
} |
/* |
* Convert an array of little-endian words to a string |
*/ |
function binl2str(bin) |
{ |
var str = ""; |
var mask = (1 << chrsz) - 1; |
for(var i = 0; i < bin.length * 32; i += chrsz) |
str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); |
return str; |
} |
/* |
* Convert an array of little-endian words to a hex string. |
*/ |
function binl2hex(binarray) |
{ |
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; |
var str = ""; |
for(var i = 0; i < binarray.length * 4; i++) |
{ |
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + |
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); |
} |
return str; |
} |
/* |
* Convert an array of little-endian words to a base-64 string |
*/ |
function binl2b64(binarray) |
{ |
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
var str = ""; |
for(var i = 0; i < binarray.length * 4; i += 3) |
{ |
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) |
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); |
for(var j = 0; j < 4; j++) |
{ |
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; |
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); |
} |
} |
return str; |
} |
/tags/v2.0-narmer/api/pear/Auth/Frontend/Html.php |
---|
New file |
0,0 → 1,142 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* Standard Html Login form |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Html.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
* @since File available since Release 1.3.0 |
*/ |
/** |
* Standard Html Login form |
* |
* @category Authentication |
* @package Auth |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.1 $ |
* @link http://pear.php.net/package/Auth |
* @since Class available since Release 1.3.0 |
*/ |
class Auth_Frontend_Html { |
// {{{ render() |
/** |
* Displays the login form |
* |
* @param object The calling auth instance |
* @param string The previously used username |
* @return void |
*/ |
function render(&$caller, $username = '') { |
$loginOnClick = 'return true;'; |
// Try To Use Challene response |
// TODO javascript might need some improvement for work on other browsers |
if($caller->advancedsecurity && $caller->storage->supportsChallengeResponse() ) { |
// Init the secret cookie |
$caller->session['loginchallenege'] = md5(microtime()); |
print "\n"; |
print '<script language="JavaScript">'."\n"; |
include 'Auth/Frontend/md5.js'; |
print "\n"; |
print ' function securePassword() { '."\n"; |
print ' var pass = document.getElementById(\''.$caller->getPostPasswordField().'\');'."\n"; |
print ' var secret = document.getElementById(\'authsecret\')'."\n"; |
//print ' alert(pass);alert(secret); '."\n"; |
// If using md5 for password storage md5 the password before |
// we hash it with the secret |
// print ' alert(pass.value);'; |
if ($caller->storage->getCryptType() == 'md5' ) { |
print ' pass.value = hex_md5(pass.value); '."\n"; |
#print ' alert(pass.value);'; |
} |
print ' pass.value = hex_md5(pass.value+\''.$caller->session['loginchallenege'].'\'); '."\n"; |
// print ' alert(pass.value);'; |
print ' secret.value = 1;'."\n"; |
print ' var doLogin = document.getElementById(\'doLogin\')'."\n"; |
print ' doLogin.disabled = true;'."\n"; |
print ' return true;'; |
print ' } '."\n"; |
print '</script>'."\n";; |
print "\n"; |
$loginOnClick = ' return securePassword(); '; |
} |
print '<center>'."\n"; |
$status = ''; |
if (!empty($caller->status) && $caller->status == AUTH_EXPIRED) { |
$status = '<i>Your session has expired. Please login again!</i>'."\n"; |
} else if (!empty($caller->status) && $caller->status == AUTH_IDLED) { |
$status = '<i>You have been idle for too long. Please login again!</i>'."\n"; |
} else if (!empty ($caller->status) && $caller->status == AUTH_WRONG_LOGIN) { |
$status = '<i>Wrong login data!</i>'."\n"; |
} else if (!empty ($caller->status) && $caller->status == AUTH_SECURITY_BREACH) { |
$status = '<i>Security problem detected. </i>'."\n"; |
} |
print '<form method="post" action="'.$caller->server['PHP_SELF'].'" ' |
.'onSubmit="'.$loginOnClick.'">'."\n"; |
print '<table border="0" cellpadding="2" cellspacing="0" ' |
.'summary="login form" align="center" >'."\n"; |
print '<tr>'."\n"; |
print ' <td colspan="2" bgcolor="#eeeeee"><strong>Login </strong>' |
.$status.'</td>'."\n"; |
print '</tr>'."\n"; |
print '<tr>'."\n"; |
print ' <td>Username:</td>'."\n"; |
print ' <td><input type="text" id="'.$caller->getPostUsernameField() |
.'" name="'.$caller->getPostUsernameField().'" value="' . $username |
.'" /></td>'."\n"; |
print '</tr>'."\n"; |
print '<tr>'."\n"; |
print ' <td>Password:</td>'."\n"; |
print ' <td><input type="password" id="'.$caller->getPostPasswordField() |
.'" name="'.$caller->getPostPasswordField().'" /></td>'."\n"; |
print '</tr>'."\n"; |
print '<tr>'."\n"; |
//onClick=" '.$loginOnClick.' " |
print ' <td colspan="2" bgcolor="#eeeeee"><input value="Login" ' |
.'id="doLogin" name="doLogin" type="submit" /></td>'."\n"; |
print '</tr>'."\n"; |
print '</table>'."\n"; |
// Might be a good idea to make the variable name variable |
print '<input type="hidden" id="authsecret" name="authsecret" value="" />'; |
print '</form>'."\n"; |
print '</center>'."\n"; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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("Å‘"=>"õ","ű"=>"û","Å"=>"Õ","Å°" |
=>"Û"); |
> $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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/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; |
} |
} |
} |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/api/pear/HTML/QuickForm.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/HTML/QuickForm.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/api/pear/HTML/Table.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/HTML/Table.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/HTML/Common.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/HTML/Common.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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}"); |
} |
} |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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): ' ') . |
$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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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? '**********': ' ') . |
$this->_getPersistantData(); |
} //end func getFrozenHtml |
// }}} |
} //end class HTML_QuickForm_password |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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('', ''); |
} |
} |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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)/", '
', 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 |
?> |
/tags/v2.0-narmer/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' => ' ', |
'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ärz', 'April', 'Mai', 'Juni', 'Juli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dez'), |
'months_long' => array ('Januar', 'Februar', 'Mä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év', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Déc'), |
'months_long' => array ('Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre') |
), |
'hu' => array ( |
'weekdays_short'=> array ('V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'), |
'weekdays_long' => array ('vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat'), |
'months_short' => array ('jan', 'feb', 'márc', 'ápr', 'máj', 'jún', 'júl', 'aug', 'szept', 'okt', 'nov', 'dec'), |
'months_long' => array ('január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december') |
), |
'pl' => array ( |
'weekdays_short'=> array ('Nie', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'Sob'), |
'weekdays_long' => array ('Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'), |
'months_short' => array ('Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'), |
'months_long' => array ('Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień') |
), |
'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 ('Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'), |
'weekdays_long' => array ('Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'), |
'months_short' => array ('Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'), |
'months_long' => array ('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь') |
), |
'es' => array ( |
'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'), |
'weekdays_long' => array ('Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sá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øn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'), |
'weekdays_long' => array ('Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lø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án', 'Þri', 'Mið', 'Fim', 'Fös', 'Lau'), |
'weekdays_long' => array ('Sunnudagur', 'Mánudagur', 'Þriðjudagur', 'Miðvikudagur', 'Fimmtudagur', 'Föstudagur', 'Laugardagur'), |
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maí', 'Jún', 'Júl', 'Ágú', 'Sep', 'Okt', 'Nóv', 'Des'), |
'months_long' => array ('Janúar', 'Febrúar', 'Mars', 'Apríl', 'Maí', 'Júní', 'Júlí', 'Ágúst', 'September', 'Október', 'Nóvember', 'Desember') |
), |
'it' => array ( |
'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'), |
'weekdays_long' => array ('Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', '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', 'Štv', 'Pia', 'Sob'), |
'weekdays_long' => array ('Nedeža', 'Pondelok', 'Utorok', 'Streda', 'Štvrtok', 'Piatok', 'Sobota'), |
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Júl', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'), |
'months_long' => array ('Január', 'Február', 'Marec', 'Apríl', 'Máj', 'Jún', 'Júl', 'August', 'September', 'Október', 'November', 'December') |
), |
'cs' => array ( |
'weekdays_short'=> array ('Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'), |
'weekdays_long' => array ('Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'), |
'months_short' => array ('Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čen', 'Čec', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'), |
'months_long' => array ('Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec') |
), |
'hy' => array ( |
'weekdays_short'=> array ('Կրկ', 'Երկ', 'Երք', 'Չրք', 'Հնգ', 'Ուր', 'Շբթ'), |
'weekdays_long' => array ('Կիրակի', 'Երկուշաբթի', 'Երեքշաբթի', 'Չորեքշաբթի', 'Հինգշաբթի', 'Ուրբաթ', 'Շաբաթ'), |
'months_short' => array ('Հնվ', 'Փտր', 'Մրտ', 'Ապր', 'Մյս', 'Հնս', 'Հլս', 'Օգս', 'Սպտ', 'Հկտ', 'Նյմ', 'Դկտ'), |
'months_long' => array ('Հունվար', 'Փետրվար', 'Մարտ', 'Ապրիլ', 'Մայիս', 'Հունիս', 'Հուլիս', 'Օգոստոս', 'Սեպտեմբեր', 'Հոկտեմբեր', 'Նոյեմբեր', 'Դեկտեմբեր') |
), |
'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ühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'), |
'months_short' => array ('Jaan', 'Veebr', 'Märts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'), |
'months_long' => array ('Jaanuar', 'Veebruar', 'Märts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'August', 'September', 'Oktoober', 'November', 'Detsember') |
), |
'tr' => array ( |
'weekdays_short'=> array ('Paz', 'Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cts'), |
'weekdays_long' => array ('Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'), |
'months_short' => array ('Ock', 'Şbt', 'Mrt', 'Nsn', 'Mys', 'Hzrn', 'Tmmz', 'Ağst', 'Eyl', 'Ekm', 'Ksm', 'Arlk'), |
'months_long' => array ('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık') |
), |
'no' => array ( |
'weekdays_short'=> array ('Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'), |
'weekdays_long' => array ('Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lø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', 'Ĵaŭ', 'Ven', 'Sab'), |
'weekdays_long' => array ('Dimanĉo', 'Lundo', 'Mardo', 'Merkredo', 'Ĵaŭdo', 'Vendredo', 'Sabato'), |
'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aŭg', 'Sep', 'Okt', 'Nov', 'Dec'), |
'months_long' => array ('Januaro', 'Februaro', 'Marto', 'Aprilo', 'Majo', 'Junio', 'Julio', 'Aŭgusto', 'Septembro', 'Oktobro', 'Novembro', 'Decembro') |
), |
'ua' => array ( |
'weekdays_short'=> array('Ндл', 'Пнд', 'Втр', 'Срд', 'Чтв', 'Птн', 'Сбт'), |
'weekdays_long' => array('Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П\'ятниця', 'Субота'), |
'months_short' => array('Січ', 'Лют', 'Бер', 'Кві', 'Тра', 'Чер', 'Лип', 'Сер', 'Вер', 'Жов', 'Лис', 'Гру'), |
'months_long' => array('Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень') |
), |
'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 ('ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'), |
'weekdays_long' => array ('יום ראשון', 'יום שני', 'יום שלישי', 'יום רביעי', 'יום חמישי', 'יום שישי', 'שבת'), |
'months_short' => array ('ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'), |
'months_long' => array ('ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר') |
), |
'sv' => array ( |
'weekdays_short'=> array ('Sön', 'Mån', 'Tis', 'Ons', 'Tor', 'Fre', 'Lör'), |
'weekdays_long' => array ('Söndag', 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lö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áb'), |
'weekdays_long' => array ('Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'), |
'months_short' => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'), |
'months_long' => array ('Janeiro', 'Fevereiro', 'Març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? ' ': $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); |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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)? ' ': 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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 = ' '; |
} |
$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 |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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 <form> header |
* {form.outputHeader():h} |
* @return string <form attributes> |
*/ |
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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 |
} |
?> |
/tags/v2.0-narmer/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 |
{ |
} |
?> |
/tags/v2.0-narmer/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)? ' ': $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; |
} |
} |
?> |
/tags/v2.0-narmer/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 |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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]; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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]; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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]) |
); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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]; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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]; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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) |
); |
} |
} |
?> |
/tags/v2.0-narmer/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) |
); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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>"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 :-) |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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", |
' ' => ' ', |
'<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"; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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 {} |
?> |
/tags/v2.0-narmer/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}"; |
} |
} |
?> |
/tags/v2.0-narmer/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/>"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 '}'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 '}'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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} "; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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}"; |
} |
} |
?> |
/tags/v2.0-narmer/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 '}'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 '}'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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>"; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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>'; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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}"; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 { |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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']); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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 ''; |
} |
} |
?> |
/tags/v2.0-narmer/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']); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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']); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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"; |
} |
} |
?> |
/tags/v2.0-narmer/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']; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's ifx extension |
* for interacting with Informix databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* More info on Informix errors can be found at: |
* http://www.informix.com/answers/english/ierrors.htm |
* |
* TODO: |
* - set needed env Informix vars on connect |
* - implement native prepare/execute |
* |
* @category Database |
* @package DB |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet.php |
---|
New file |
0,0 → 1,2747 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet | |
// +----------------------------------------------------------------------+ |
// | 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 |f |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// | Jason Rust <jason@rustyparts.com> | |
// +----------------------------------------------------------------------+ |
// $Id: NestedSet.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
// |
// CREDITS: |
// -------- |
// - Thanks to Kristian Koehntopp for publishing an explanation of the Nested Set |
// technique and for the great work he did and does for the php community |
// - Thanks to Daniel T. Gorski for his great tutorial on www.develnet.org |
// |
// - Thanks to my parents for ... just kidding :] |
require_once 'PEAR.php'; |
// {{{ constants |
// Error and message codes |
define('NESE_ERROR_RECURSION', 'E100'); |
define('NESE_ERROR_NODRIVER', 'E200'); |
define('NESE_ERROR_NOHANDLER', 'E300'); |
define('NESE_ERROR_TBLOCKED', 'E010'); |
define('NESE_MESSAGE_UNKNOWN', 'E0'); |
define('NESE_ERROR_NOTSUPPORTED', 'E1'); |
define('NESE_ERROR_PARAM_MISSING','E400'); |
define('NESE_ERROR_NOT_FOUND', 'E500'); |
define('NESE_ERROR_WRONG_MPARAM', 'E2'); |
// for moving a node before another |
define('NESE_MOVE_BEFORE', 'BE'); |
// for moving a node after another |
define('NESE_MOVE_AFTER', 'AF'); |
// for moving a node below another |
define('NESE_MOVE_BELOW', 'SUB'); |
// Sortorders |
define('NESE_SORT_LEVEL', 'SLV'); |
define('NESE_SORT_PREORDER', 'SPO'); |
// }}} |
// {{{ DB_NestedSet:: class |
/** |
* DB_NestedSet is a class for handling nested sets |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet { |
// {{{ properties |
/** |
* @var array The field parameters of the table with the nested set. Format: 'realFieldName' => 'fieldId' |
* @access public |
*/ |
var $params = array( |
'STRID' => 'id', |
'ROOTID'=> 'rootid', |
'l' => 'l', |
'r' => 'r', |
'STREH' => 'norder', |
'LEVEL' => 'level', |
// 'parent'=>'parent', // Optional but very useful |
'STRNA' => 'name' |
); |
// To be used with 2.0 - would be an api break atm |
// var $quotedParams = array('name'); |
/** |
* @var string The table with the actual tree data |
* @access public |
*/ |
var $node_table = 'tb_nodes'; |
/** |
* @var string The table to handle locking |
* @access public |
*/ |
var $lock_table = 'tb_locks'; |
/** |
* @var string The table used for sequences |
* @access public |
*/ |
var $sequence_table; |
/** |
* Secondary order field. Normally this is the order field, but can be changed to |
* something else (i.e. the name field so that the tree can be shown alphabetically) |
* |
* @var string |
* @access public |
*/ |
var $secondarySort; |
/** |
* Used to store the secondary sort method set by the user while doing manipulative queries |
* |
* @var string |
* @access private |
*/ |
var $_userSecondarySort = false; |
/** |
* The default sorting field - will be set to the table column inside the constructor |
* |
* @var string |
* @access private |
*/ |
var $_defaultSecondarySort = 'norder'; |
/** |
* @var int The time to live of the lock |
* @access public |
*/ |
var $lockTTL = 1; |
/** |
* @var bool Enable debugging statements? |
* @access public |
*/ |
var $debug = 0; |
/** |
* @var bool Lock the structure of the table? |
* @access private |
*/ |
var $_structureTableLock = false; |
/** |
* @var bool Don't allow unlocking (used inside of moves) |
* @access private |
*/ |
var $_lockExclusive = false; |
/** |
* @var object cache Optional PEAR::Cache object |
* @access public |
*/ |
var $cache = false; |
/** |
* Specify the sortMode of the query methods |
* NESE_SORT_LEVEL is the 'old' sorting method and sorts a tree by level |
* all nodes of level 1, all nodes of level 2,... |
* NESE_SORT_PREORDER will sort doing a preorder walk. |
* So all children of node x will come right after it |
* Note that moving a node within it's siblings will obviously not change the output |
* in this mode |
* |
* @var constant Order method (NESE_SORT_LEVEL|NESE_SORT_PREORDER) |
* @access private |
*/ |
var $_sortMode = NESE_SORT_LEVEL; |
/** |
* @var array Available sortModes |
* @access private |
*/ |
var $_sortModes = array(NESE_SORT_LEVEL, NESE_SORT_PREORDER); |
/** |
* @var array An array of field ids that must exist in the table |
* @access private |
*/ |
var $_requiredParams = array('id', 'rootid', 'l', 'r', 'norder', 'level'); |
/** |
* @var bool Skip the callback events? |
* @access private |
*/ |
var $_skipCallbacks = false; |
/** |
* @var bool Do we want to use caching |
* @access private |
*/ |
var $_caching = false; |
/** |
* @var array The above parameters flipped for easy access |
* @access private |
*/ |
var $_flparams = array(); |
/** |
* |
* @var bool Temporary switch for cache |
* @access private |
*/ |
var $_restcache = false; |
/** |
* Used to determine the presence of listeners for an event in triggerEvent() |
* |
* If any event listeners are registered for an event, the event name will |
* have a key set in this array, otherwise, it will not be set. |
* @see triggerEvent() |
* @var arrayg |
* @access private |
*/ |
var $_hasListeners = array(); |
/** |
* @var string packagename |
* @access private |
*/ |
var $_packagename = 'DB_NestedSet'; |
/** |
* @var int Majorversion |
* @access private |
*/ |
var $_majorversion = 1; |
/** |
* @var string Minorversion |
* @access private |
*/ |
var $_minorversion = '3'; |
/** |
* @var array Used for mapping a cloned tree to the real tree for move_* operations |
* @access private |
*/ |
var $_relations = array(); |
/** |
* Used for _internal_ tree conversion |
* @var bool Turn off user param verification and id generation |
* @access private |
*/ |
var $_dumbmode = false; |
/** |
* @var array Map of error messages to their descriptions |
*/ |
var $messages = array( |
NESE_ERROR_RECURSION => '%s: This operation would lead to a recursion', |
NESE_ERROR_TBLOCKED => 'The structure Table is locked for another database operation, please retry.', |
NESE_ERROR_NODRIVER => 'The selected database driver %s wasn\'t found', |
NESE_ERROR_NOTSUPPORTED => 'Method not supported yet', |
NESE_ERROR_NOHANDLER => 'Event handler not found', |
NESE_ERROR_PARAM_MISSING=> 'Parameter missing', |
NESE_MESSAGE_UNKNOWN => 'Unknown error or message', |
NESE_ERROR_NOT_FOUND => '%s: Node %s not found', |
NESE_ERROR_WRONG_MPARAM => '%s: %s' |
); |
/** |
* @var array The array of event listeners |
* @access private |
*/ |
var $eventListeners = array(); |
// }}} |
// +---------------------------------------+ |
// | Base methods | |
// +---------------------------------------+ |
// {{{ constructor |
/** |
* Constructor |
* |
* @param array $params Database column fields which should be returned |
* |
* @access private |
* @return void |
*/ |
function DB_NestedSet($params) { |
if ($this->debug) { |
$this->_debugMessage('DB_NestedSet()'); |
} |
if (is_array($params) && count($params) > 0) { |
$this->params = $params; |
} |
$this->_flparams = array_flip($this->params); |
$this->sequence_table = $this->node_table . '_' . $this->_flparams['id']; |
$this->secondarySort = $this->_flparams[$this->_defaultSecondarySort]; |
register_shutdown_function(array(&$this,'_DB_NestedSet')); |
} |
// }}} |
// {{{ destructor |
/** |
* PEAR Destructor |
* Releases all locks |
* Closes open database connections |
* |
* @access private |
* @return void |
*/ |
function _DB_NestedSet() { |
if ($this->debug) { |
$this->_debugMessage('_DB_NestedSet()'); |
} |
$this->_releaseLock(true); |
} |
// }}} |
// {{{ factory |
/** |
* Handles the returning of a concrete instance of DB_NestedSet based on the driver. |
* If the class given by $driver allready exists it will be used. |
* If not the driver will be searched inside the default path ./NestedSet/ |
* |
* @param string $driver The driver, such as DB or MDB |
* @param string $dsn The dsn for connecting to the database |
* @param array $params The field name params for the node table |
* |
* @static |
* @access public |
* @return object The DB_NestedSet object |
*/ |
function & factory($driver, $dsn, $params = array()) { |
$classname = 'DB_NestedSet_' . $driver; |
if (!class_exists($classname)) { |
$driverpath = dirname(__FILE__).'/NestedSet/'.$driver.'.php'; |
if(!file_exists($driverpath) || !$driver) { |
return PEAR::raiseError("factory(): The database driver '$driver' wasn't found", NESE_ERROR_NODRIVER, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
include_once($driverpath); |
} |
return new $classname($dsn, $params); |
} |
// }}} |
// }}} |
// +----------------------------------------------+ |
// | NestedSet manipulation and query methods | |
// |----------------------------------------------+ |
// | Querying the tree | |
// +----------------------------------------------+ |
// {{{ getAllNodes() |
/** |
* Fetch the whole NestedSet |
* |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getAllNodes($keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getAllNodes()'); |
} |
if($this->_sortMode == NESE_SORT_LEVEL) { |
$sql = sprintf('SELECT %s %s FROM %s %s %s ORDER BY %s.%s, %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$this->_flparams['level'], |
$this->node_table, |
$this->secondarySort); |
} elseif ($this->_sortMode == NESE_SORT_PREORDER) { |
$nodeSet = array(); |
$rootnodes = $this->getRootNodes(true); |
foreach($rootnodes AS $rid=>$rootnode) { |
$nodeSet = $nodeSet+$this->getBranch($rootnode, true); |
} |
return $nodeSet; |
} |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
return $nodeSet; |
} |
// }}} |
// {{{ getRootNodes() |
/** |
* Fetches the first level (the rootnodes) of the NestedSet |
* |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getRootNodes($keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getRootNodes()'); |
} |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s.%s %s ORDER BY %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['id'], |
$this->node_table, |
$this->_flparams['rootid'], |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$this->secondarySort); |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
return $nodeSet; |
} |
// }}} |
// {{{ getBranch() |
/** |
* Fetch the whole branch where a given node id is in |
* |
* @param int $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getBranch($id, $keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getBranch($id)'); |
} |
if (!($thisnode = $this->pickNode($id, true))) { |
$epr = array('getBranch()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_NOTICE, $epr); |
} |
if($this->_sortMode == NESE_SORT_LEVEL) { |
$firstsort = $this->_flparams['level']; |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s %s ORDER BY %s.%s, %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$firstsort, |
$this->node_table, |
$this->secondarySort); |
} elseif($this->_sortMode == NESE_SORT_PREORDER) { |
$firstsort = $this->_flparams['l']; |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s %s ORDER BY %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$firstsort); |
} |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
if($this->_sortMode == NESE_SORT_PREORDER && ($this->params[$this->secondarySort] != $this->_defaultSecondarySort)) { |
uasort($nodeSet, array($this, '_secSort')); |
} |
return $nodeSet; |
} |
// }}} |
// {{{ getParents() |
/** |
* Fetch the parents of a node given by id |
* |
* @param int $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getParents($id, $keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getParents($id)'); |
} |
if (!($child = $this->pickNode($id, true))) { |
$epr = array('getParents()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_NOTICE, $epr); |
} |
$sql = sprintf('SELECT %s %s FROM %s %s |
WHERE %s.%s=%s AND %s.%s<%s AND %s.%s<%s AND %s.%s>%s %s |
ORDER BY %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['rootid'], |
$child['rootid'], |
$this->node_table, |
$this->_flparams['level'], |
$child['level'], |
$this->node_table, |
$this->_flparams['l'], |
$child['l'], |
$this->node_table, |
$this->_flparams['r'], |
$child['r'], |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$this->_flparams['level']); |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
return $nodeSet; |
} |
// }}} |
// {{{ getParent() |
/** |
* Fetch the immediate parent of a node given by id |
* |
* @param int $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or the parent node |
*/ |
function getParent($id, $keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getParent($id)'); |
} |
if (!($child = $this->pickNode($id, true))) { |
$epr = array('getParent()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_NOTICE, $epr); |
} |
if($child['id'] == $child['rootid']) { |
return false; |
} |
// If parent node is set inside the db simply return it |
if(isset($child['parent']) && !empty($child['parent'])) { |
return $this->pickNode($child['parent'], $keepAsArray, $aliasFields, 'id', $addSQL); |
} |
$addSQL['append'] = sprintf('AND %s.%s = %s', |
$this->node_table, |
$this->_flparams['level'], |
$child['level']-1); |
$nodeSet = $this->getParents($id, $keepAsArray, $aliasFields, $addSQL); |
if(!empty($nodeSet)) { |
$keys = array_keys($nodeSet); |
return $nodeSet[$keys[0]]; |
} else { |
return false; |
} |
} |
// }}} |
// {{{ getSiblings) |
/** |
* Fetch all siblings of the node given by id |
* Important: The node given by ID will also be returned |
* Do a unset($array[$id]) on the result if you don't want that |
* |
* @param int $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or the parent node |
*/ |
function getSiblings($id, $keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getParents($id)'); |
} |
if (!($sibling = $this->pickNode($id, true))) { |
$epr = array('getSibling()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_NOTICE, $epr); |
} |
$parent = $this->getParent($sibling, true); |
return $this->getChildren($parent, $keepAsArray, $aliasFields, $addSQL); |
} |
// }}} |
// {{{ getChildren() |
/** |
* Fetch the children _one level_ after of a node given by id |
* |
* @param int $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param bool $forceNorder (optional) Force the result to be ordered by the norder |
* param (as opposed to the value of secondary sort). Used by the move and |
* add methods. |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getChildren($id, $keepAsArray = false, $aliasFields = true, $forceNorder = false, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getChildren($id)'); |
} |
if (!($parent = $this->pickNode($id, true))) { |
$epr = array('getChildren()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_NOTICE, $epr); |
} |
if (!$parent || $parent['l'] == ($parent['r'] - 1)) { |
return false; |
} |
$sql = sprintf('SELECT %s %s FROM %s %s |
WHERE %s.%s=%s AND %s.%s=%s+1 AND %s.%s BETWEEN %s AND %s %s |
ORDER BY %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['rootid'], |
$parent['rootid'], |
$this->node_table, |
$this->_flparams['level'], |
$parent['level'], |
$this->node_table, |
$this->_flparams['l'], |
$parent['l'], |
$parent['r'], |
$this->_addSQL($addSQL, 'append'), |
$this->node_table, |
$this->secondarySort); |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
return $nodeSet; |
} |
// }}} |
// {{{ getSubBranch() |
/** |
* Fetch all the children of a node given by id |
* |
* getChildren only queries the immediate children |
* getSubBranch returns all nodes below the given node |
* |
* @param string $id The node ID |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function getSubBranch($id, $keepAsArray = false, $aliasFields = true, $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('getSubBranch($id)'); |
} |
if (!($parent = $this->pickNode($id, true))) { |
$epr = array('getSubBranch()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, E_USER_NOTICE, $epr); |
} |
if($this->_sortMode == NESE_SORT_LEVEL) { |
$firstsort = $this->_flparams['level']; |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s BETWEEN %s AND %s AND %s.%s=%s AND %s.%s!=%s %s ORDER BY %s.%s, %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['l'], |
$parent['l'], |
$parent['r'], |
$this->node_table, |
$this->_flparams['rootid'], |
$parent['rootid'], |
$this->node_table, |
$this->_flparams['id'], |
$this->_addSQL($addSQL, 'append'), |
$id, |
$this->node_table, |
$firstsort, |
$this->node_table, |
$this->secondarySort |
); |
} elseif($this->_sortMode == NESE_SORT_PREORDER) { |
$firstsort = $this->_flparams['l']; |
$firstsort = $this->_flparams['level']; |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s BETWEEN %s AND %s AND %s.%s=%s AND %s.%s!=%s %s ORDER BY %s.%s ASC', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams['l'], |
$parent['l'], |
$parent['r'], |
$this->node_table, |
$this->_flparams['rootid'], |
$parent['rootid'], |
$this->node_table, |
$this->_flparams['id'], |
$this->_addSQL($addSQL, 'append'), |
$id, |
$this->node_table, |
$firstsort |
); |
} |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
} |
} |
if($this->params[$this->secondarySort] != $this->_defaultSecondarySort) { |
uasort($nodeSet, array($this, '_secSort')); |
} |
return $nodeSet; |
} |
// }}} |
// {{{ pickNode() |
/** |
* Fetch the data of a node with the given id |
* |
* @param int $id The node id of the node to fetch |
* @param bool $keepAsArray (optional) Keep the result as an array or transform it into |
* a set of DB_NestedSet_Node objects? |
* @param bool $aliasFields (optional) Should we alias the fields so they are the names |
* of the parameter keys, or leave them as is? |
* @param string $idfield (optional) Which field has to be compared with $id? |
* This is can be used to pick a node by other values (e.g. it's name). |
* @param array $addSQL (optional) Array of additional params to pass to the query. |
* |
* @see _addSQL() |
* @access public |
* @return mixed False on error, or an array of nodes |
*/ |
function pickNode($id, $keepAsArray = false, $aliasFields = true, $idfield = 'id', $addSQL = array()) { |
if ($this->debug) { |
$this->_debugMessage('pickNode($id)'); |
} |
if (is_object($id) && $id->id) { |
return $id; |
} elseif (is_array($id) && isset($id['id'])) { |
return $id; |
} |
if(!$id) { |
return false; |
} |
$sql = sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s %s', |
$this->_getSelectFields($aliasFields), |
$this->_addSQL($addSQL, 'cols'), |
$this->node_table, |
$this->_addSQL($addSQL, 'join'), |
$this->node_table, |
$this->_flparams[$idfield], |
$id, |
$this->_addSQL($addSQL, 'append')); |
if (!$this->_caching) { |
$nodeSet = $this->_processResultSet($sql, $keepAsArray, $aliasFields); |
} else { |
$nodeSet = $this->cache->call('DB_NestedSet->_processResultSet', $sql, $keepAsArray, $aliasFields); |
} |
$nsKey = false; |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeLoad'])) { |
// EVENT (nodeLoad) |
foreach (array_keys($nodeSet) as $key) { |
$this->triggerEvent('nodeLoad', $nodeSet[$key]); |
$nsKey = $key; |
} |
} else { |
foreach (array_keys($nodeSet) as $key) { |
$nsKey = $key; |
} |
} |
if (is_array($nodeSet) && $idfield != 'id') { |
$id = $nsKey; |
} |
return isset($nodeSet[$id]) ? $nodeSet[$id] : false; |
} |
// }}} |
// {{{ isParent() |
/** |
* See if a given node is a parent of another given node |
* |
* A node is considered to be a parent if it resides above the child |
* So it doesn't mean that the node has to be an immediate parent. |
* To get this information simply compare the levels of the two nodes |
* after you know that you have a parent relation. |
* |
* @param mixed $parent The parent node as array or object |
* @param mixed $child The child node as array or object |
* |
* @access public |
* @return bool True if it's a parent |
*/ |
function isParent($parent, $child) { |
if ($this->debug) { |
$this->_debugMessage('isParent($parent, $child)'); |
} |
if (!isset($parent)|| !isset($child)) { |
return false; |
} |
if (is_array($parent)) { |
$p_rootid = $parent['rootid']; |
$p_l = $parent['l']; |
$p_r = $parent['r']; |
} elseif (is_object($parent)) { |
$p_rootid = $parent->rootid; |
$p_l = $parent->l; |
$p_r = $parent->r; |
} |
if (is_array($child)) { |
$c_rootid = $child['rootid']; |
$c_l = $child['l']; |
$c_r = $child['r']; |
} elseif (is_object($child)) { |
$c_rootid = $child->rootid; |
$c_l = $child->l; |
$c_r = $child->r; |
} |
if (($p_rootid == $c_rootid) && ($p_l < $c_l && $p_r > $c_r)) { |
return true; |
} |
return false; |
} |
// }}} |
// +----------------------------------------------+ |
// | NestedSet manipulation and query methods | |
// |----------------------------------------------+ |
// | insert / delete / update of nodes | |
// +----------------------------------------------+ |
// | [PUBLIC] | |
// +----------------------------------------------+ |
// {{{ createRootNode() |
/** |
* Creates a new root node |
* Optionally it deletes the whole tree and creates one initial rootnode |
* |
* <pre> |
* +-- root1 [target] |
* | |
* +-- root2 [new] |
* | |
* +-- root3 |
* </pre> |
* |
* @param array $values Hash with param => value pairs of the node (see $this->params) |
* @param integer $id ID of target node (the rootnode after which the node should be inserted) |
* @param bool $first Danger: Deletes and (re)init's the hole tree - sequences are reset |
* |
* @access public |
* @return mixed The node id or false on error |
*/ |
function createRootNode($values, $id = false, $first = false, $_pos = 'AF') { |
if ($this->debug) { |
$this->_debugMessage('createRootNode($values, $id = false, $first = false, $_pos = \'AF\')'); |
} |
$this->_verifyUserValues('createRootNode()', $values); |
if(!$first && (!$id || !$parent = $this->pickNode($id, true))) { |
$epr = array('createRootNode()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} elseif($first && $id) { |
// No notice for now. |
// But tehese 2 params don't make sense together |
$epr = array( |
'createRootNode()', |
'[id] AND [first] were passed - that doesn\'t make sense'); |
//$this->_raiseError(NESE_ERROR_WRONG_MPARAM, E_USER_WARNING, $epr); |
} |
// Try to aquire a table lock |
if(PEAR::isError($lock=$this->_setLock())) { |
return $lock; |
} |
$sql = array(); |
$addval = array(); |
$addval[$this->_flparams['level']] = 1; |
// Shall we delete the existing tree (reinit) |
if ($first) { |
$dsql = sprintf('DELETE FROM %s', |
$this->node_table); |
$this->db->query($dsql); |
$this->db->dropSequence($this->sequence_table); |
// New order of the new node will be 1 |
$addval[$this->_flparams['norder']] = 1; |
} else { |
// Let's open a gap for the new node |
if($_pos == NESE_MOVE_AFTER) { |
$addval[$this->_flparams['norder']] = $parent['norder'] + 1; |
$sql[] = sprintf('UPDATE %s SET %s=%s+1 WHERE %s=%s AND %s > %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['id'], |
$this->_flparams['rootid'], |
$this->_flparams['norder'], |
$parent['norder']); |
} elseif($_pos == NESE_MOVE_BEFORE) { |
$addval[$this->_flparams['norder']] = $parent['norder']; |
$sql[] = sprintf('UPDATE %s SET %s=%s+1 WHERE %s=%s AND %s >= %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['id'], |
$this->_flparams['rootid'], |
$this->_flparams['norder'], |
$parent['norder']); |
} |
} |
if(isset($this->_flparams['parent'])) { |
$addval[$this->_flparams['parent']] = 0; |
} |
// Sequence of node id (equals to root id in this case |
if(!$this->_dumbmode || !$node_id=isset($values[$this->_flparams['id']]) || !isset($values[$this->_flparams['rootid']])) { |
$addval[$this->_flparams['rootid']] = $node_id = $addval[$this->_flparams['id']] = $this->db->nextId($this->sequence_table); |
} else { |
$node_id = $values[$this->_flparams['id']]; |
} |
// Left/Right values for rootnodes |
$addval[$this->_flparams['l']] = 1; |
$addval[$this->_flparams['r']] = 2; |
// Transform the node data hash to a query |
if (!$qr = $this->_values2Query($values, $addval)) { |
$this->_releaseLock(); |
return false; |
} |
// Insert the new node |
$sql[] = sprintf('INSERT INTO %s SET %s', |
$this->node_table, |
$qr); |
for($i=0;$i<count($sql);$i++) { |
$res = $this->db->query($sql[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
// EVENT (nodeCreate) |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeCreate'])) { |
$this->triggerEvent('nodeCreate', $this->pickNode($node_id)); |
} |
$this->_releaseLock(); |
return $node_id; |
} |
// }}} |
// {{{ createSubNode() |
/** |
* Creates a subnode |
* |
* <pre> |
* +-- root1 |
* | |
* +-\ root2 [target] |
* | | |
* | |-- subnode1 [new] |
* | |
* +-- root3 |
* </pre> |
* |
* @param integer $id Parent node ID |
* @param array $values Hash with param => value pairs of the node (see $this->params) |
* |
* @access public |
* @return mixed The node id or false on error |
*/ |
function createSubNode($id, $values) { |
if ($this->debug) { |
$this->_debugMessage('createSubNode($id, $values)'); |
} |
// invalid parent id, bail out |
if (!($thisnode = $this->pickNode($id, true))) { |
$epr = array('createSubNode()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
// Try to aquire a table lock |
if(PEAR::isError($lock = $this->_setLock())) { |
return $lock; |
} |
$this->_verifyUserValues('createRootNode()', $values); |
// Get the children of the target node |
$children = $this->getChildren($id, true); |
// We have children here |
if ($thisnode['r']-1 != $thisnode['l']) { |
// Get the last child |
$last = array_pop($children); |
// What we have to do is virtually an insert of a node after the last child |
// So we don't have to proceed creating a subnode |
$newNode = $this->createRightNode($last['id'], $values); |
$this->_releaseLock(); |
return $newNode; |
} |
$sql = array(); |
$sql[] = sprintf(' |
UPDATE %s SET |
%s=IF(%s>=%s, %s+2, %s), |
%s=IF(%s>=%s, %s+2, %s) |
WHERE %s=%s', |
$this->node_table, |
$this->_flparams['l'], |
$this->_flparams['l'], |
$thisnode['r'], |
$this->_flparams['l'], |
$this->_flparams['l'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$thisnode['r'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$this->_flparams['rootid'], |
$thisnode['rootid'] |
); |
$addval = array(); |
if(isset($this->_flparams['parent'])) { |
$addval[$this->_flparams['parent']] = $thisnode['id']; |
} |
$addval[$this->_flparams['l']] = $thisnode['r']; |
$addval[$this->_flparams['r']] = $thisnode['r'] + 1; |
$addval[$this->_flparams['rootid']] = $thisnode['rootid']; |
$addval[$this->_flparams['norder']] = 1; |
$addval[$this->_flparams['level']] = $thisnode['level'] + 1; |
if(!$this->_dumbmode || !$node_id=isset($values[$this->_flparams['id']])) { |
$node_id = $addval[$this->_flparams['id']] = $this->db->nextId($this->sequence_table); |
} else { |
$node_id = $values[$this->_flparams['id']]; |
} |
if (!$qr = $this->_values2Query($values, $addval)) { |
$this->_releaseLock(); |
return false; |
} |
$sql[] = sprintf('INSERT INTO %s SET %s', |
$this->node_table, |
$qr); |
for($i=0;$i<count($sql);$i++) { |
$res = $this->db->query($sql[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
// EVENT (NodeCreate) |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeCreate'])) { |
$thisnode = $this->pickNode($node_id); |
$this->triggerEvent('nodeCreate', $this->pickNode($id)); |
} |
$this->_releaseLock(); |
return $node_id; |
} |
// }}} |
// {{{ createLeftNode() |
/** |
* Creates a node before a given node |
* <pre> |
* +-- root1 |
* | |
* +-\ root2 |
* | | |
* | |-- subnode2 [new] |
* | |-- subnode1 [target] |
* | |-- subnode3 |
* | |
* +-- root3 |
* </pre> |
* |
* @param int $id Target node ID |
* @param array $values Hash with param => value pairs of the node (see $this->params) |
* @param bool $returnID Tell the method to return a node id instead of an object. |
* ATTENTION: That the method defaults to return an object instead of the node id |
* has been overseen and is basically a bug. We have to keep this to maintain BC. |
* You will have to set $returnID to true to make it behave like the other creation methods. |
* This flaw will get fixed with the next major version. |
* |
* @access public |
* @return mixed The node id or false on error |
*/ |
function createLeftNode($id, $values) { |
if ($this->debug) { |
$this->_debugMessage('createLeftNode($target, $values)'); |
} |
$this->_verifyUserValues('createLeftode()', $values); |
// invalid target node, bail out |
if (!($thisnode = $this->pickNode($id, true))) { |
$epr = array('createLeftNode()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
if(PEAR::isError($lock=$this->_setLock())) { |
return $lock; |
} |
// If the target node is a rootnode we virtually want to create a new root node |
if ($thisnode['rootid'] == $thisnode['id']) { |
return $this->createRootNode($values, $id, false, NESE_MOVE_BEFORE); |
} |
$addval = array(); |
$parent = $this->getParent($id, true); |
if(isset($this->_flparams['parent'])) { |
$addval[$this->_flparams['parent']] = $parent['id']; |
} |
$sql = array(); |
$sql[] = sprintf('UPDATE %s SET %s=%s+1 |
WHERE |
%s=%s AND %s>=%s AND %s=%s AND %s BETWEEN %s AND %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_flparams['norder'], |
$thisnode['norder'], |
$this->_flparams['level'], |
$thisnode['level'], |
$this->_flparams['l'], |
$parent['l'], |
$parent['r']); |
// Update all nodes which have dependent left and right values |
$sql[] = sprintf(' |
UPDATE %s SET |
%s=IF(%s>=%s, %s+2, %s), |
%s=IF(%s>=%s, %s+2, %s) |
WHERE %s=%s', |
$this->node_table, |
$this->_flparams['l'], |
$this->_flparams['l'], |
$thisnode['l'], |
$this->_flparams['l'], |
$this->_flparams['l'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$thisnode['r'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$this->_flparams['rootid'], |
$thisnode['rootid'] |
); |
$addval[$this->_flparams['norder']] = $thisnode['norder']; |
$addval[$this->_flparams['l']] = $thisnode['l']; |
$addval[$this->_flparams['r']] = $thisnode['l']+1; |
$addval[$this->_flparams['rootid']] = $thisnode['rootid']; |
$addval[$this->_flparams['level']] = $thisnode['level']; |
if(!$this->_dumbmode || !$node_id=isset($values[$this->_flparams['id']])) { |
$node_id = $addval[$this->_flparams['id']] = $this->db->nextId($this->sequence_table); |
} else { |
$node_id = $values[$this->_flparams['id']]; |
} |
if (!$qr = $this->_values2Query($values, $addval)) { |
$this->_releaseLock(); |
return false; |
} |
// Insert the new node |
$sql[] = sprintf('INSERT INTO %s SET %s', |
$this->node_table, |
$qr); |
for($i=0;$i<count($sql);$i++) { |
$res = $this->db->query($sql[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
// EVENT (NodeCreate) |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeCreate'])) { |
$this->triggerEvent('nodeCreate', $this->pickNode($id)); |
} |
$this->_releaseLock(); |
return $node_id; |
} |
/** |
* Creates a node after a given node |
* <pre> |
* +-- root1 |
* | |
* +-\ root2 |
* | | |
* | |-- subnode1 [target] |
* | |-- subnode2 [new] |
* | |-- subnode3 |
* | |
* +-- root3 |
* </pre> |
* |
* @param int $id Target node ID |
* @param array $values Hash with param => value pairs of the node (see $this->params) |
* @param bool $returnID Tell the method to return a node id instead of an object. |
* ATTENTION: That the method defaults to return an object instead of the node id |
* has been overseen and is basically a bug. We have to keep this to maintain BC. |
* You will have to set $returnID to true to make it behave like the other creation methods. |
* This flaw will get fixed with the next major version. |
* |
* @access public |
* @return mixed The node id or false on error |
*/ |
function createRightNode($id, $values) { |
if ($this->debug) { |
$this->_debugMessage('createRightNode($target, $values)'); |
} |
$this->_verifyUserValues('createRootNode()', $values); |
// invalid target node, bail out |
if (!($thisnode = $this->pickNode($id, true))) { |
$epr = array('createRightNode()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
if(PEAR::isError($lock=$this->_setLock())) { |
return $lock; |
} |
// If the target node is a rootnode we virtually want to create a new root node |
if ($thisnode['rootid'] == $thisnode['id']) { |
$nid = $this->createRootNode($values, $id); |
$this->_releaseLock(); |
return $nid; |
} |
$addval = array(); |
$parent = $this->getParent($id, true); |
if(isset($this->_flparams['parent'])) { |
$addval[$this->_flparams['parent']] = $parent['id']; |
} |
$sql = array(); |
$sql[] = sprintf('UPDATE %s SET %s=%s+1 |
WHERE |
%s=%s AND %s>%s AND %s=%s AND %s BETWEEN %s AND %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_flparams['norder'], |
$thisnode['norder'], |
$this->_flparams['level'], |
$thisnode['level'], |
$this->_flparams['l'], |
$parent['l'], |
$parent['r']); |
// Update all nodes which have dependent left and right values |
$sql[] = sprintf(' |
UPDATE %s SET |
%s=IF(%s>%s, %s+2, %s), |
%s=IF(%s>%s, %s+2, %s) |
WHERE %s=%s', |
$this->node_table, |
$this->_flparams['l'], |
$this->_flparams['l'], |
$thisnode['r'], |
$this->_flparams['l'], |
$this->_flparams['l'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$thisnode['r'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$this->_flparams['rootid'], |
$thisnode['rootid'] |
); |
$addval[$this->_flparams['norder']] = $thisnode['norder'] + 1; |
$addval[$this->_flparams['l']] = $thisnode['r'] + 1; |
$addval[$this->_flparams['r']] = $thisnode['r'] + 2; |
$addval[$this->_flparams['rootid']] = $thisnode['rootid']; |
$addval[$this->_flparams['level']] = $thisnode['level']; |
if(!$this->_dumbmode || !isset($values[$this->_flparams['id']])) { |
$node_id = $addval[$this->_flparams['id']] = $this->db->nextId($this->sequence_table); |
} else { |
$node_id = $values[$this->_flparams['id']]; |
} |
if (!$qr = $this->_values2Query($values, $addval)) { |
$this->_releaseLock(); |
return false; |
} |
// Insert the new node |
$sql[] = sprintf('INSERT INTO %s SET %s', $this->node_table, $qr); |
for($i=0;$i<count($sql);$i++) { |
$res = $this->db->query($sql[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
// EVENT (NodeCreate) |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeCreate'])) { |
$this->triggerEvent('nodeCreate', $this->pickNode($id)); |
} |
$this->_releaseLock(); |
return $node_id; |
} |
// }}} |
// {{{ deleteNode() |
/** |
* Deletes a node |
* |
* @param int $id ID of the node to be deleted |
* |
* @access public |
* @return bool True if the delete succeeds |
*/ |
function deleteNode($id) { |
if ($this->debug) { |
$this->_debugMessage("deleteNode($id)"); |
} |
// invalid target node, bail out |
if (!($thisnode = $this->pickNode($id, true))) { |
$epr = array('deleteNode()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
if (PEAR::isError($lock = $this->_setLock())) { |
return $lock; |
} |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeDelete'])) { |
// EVENT (NodeDelete) |
$this->triggerEvent('nodeDelete', $this->pickNode($id)); |
} |
$parent = $this->getParent($id, true); |
$len = $thisnode['r'] - $thisnode['l'] + 1; |
$sql = array(); |
// Delete the node |
$sql[] = sprintf('DELETE FROM %s WHERE %s BETWEEN %s AND %s AND %s=%s', |
$this->node_table, |
$this->_flparams['l'], |
$thisnode['l'], |
$thisnode['r'], |
$this->_flparams['rootid'], |
$thisnode['rootid'] |
); |
if ($thisnode['id'] != $thisnode['rootid']) { |
// The node isn't a rootnode so close the gap |
$sql[] = sprintf('UPDATE %s SET |
%s=IF(%s>%s, %s-%s, %s), |
%s=IF(%s>%s, %s-%s, %s) |
WHERE %s=%s AND |
(%s>%s OR %s>%s)', |
$this->node_table, |
$this->_flparams['l'], |
$this->_flparams['l'], |
$thisnode['l'], |
$this->_flparams['l'], |
$len, |
$this->_flparams['l'], |
$this->_flparams['r'], |
$this->_flparams['r'], |
$thisnode['l'], |
$this->_flparams['r'], |
$len, |
$this->_flparams['r'], |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_flparams['l'], |
$thisnode['l'], |
$this->_flparams['r'], |
$thisnode['r'] |
); |
// Re-order |
$sql[] = sprintf('UPDATE %s SET %s=%s-1 WHERE %s=%s AND %s=%s AND %s>%s AND %s BETWEEN %s AND %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['rootid'], |
$thisnode['rootid'], |
$this->_flparams['level'], |
$thisnode['level'], |
$this->_flparams['norder'], |
$thisnode['norder'], |
$this->_flparams['l'], |
$parent['l'], |
$parent['r']); |
} else { |
// A rootnode was deleted and we only have to close the gap inside the order |
$sql[] = sprintf('UPDATE %s SET %s=%s+1 WHERE %s=%s AND %s > %s', |
$this->node_table, |
$this->_flparams['norder'], |
$this->_flparams['norder'], |
$this->_flparams['rootid'], |
$this->_flparams['id'], |
$this->_flparams['norder'], |
$thisnode['norder']); |
} |
for($i=0;$i<count($sql);$i++) { |
$res = $this->db->query($sql[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
$this->_releaseLock(); |
return true; |
} |
// }}} |
// {{{ updateNode() |
/** |
* Changes the payload of a node |
* |
* @param int $id Node ID |
* @param array $values Hash with param => value pairs of the node (see $this->params) |
* @param bool $_intermal Internal use only. Used to skip value validation. Leave this as it is. |
* |
* @access public |
* @return bool True if the update is successful |
*/ |
function updateNode($id, $values, $_internal=false) { |
if ($this->debug) { |
$this->_debugMessage('updateNode($id, $values)'); |
} |
if (PEAR::isError($lock = $this->_setLock())) { |
return $lock; |
} |
if(!$_internal) { |
$this->_verifyUserValues('createRootNode()', $values); |
} |
$eparams = array('values' => $values); |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeUpdate'])) { |
// EVENT (NodeUpdate) |
$this->triggerEvent('nodeUpdate', $this->pickNode($id), $eparams); |
} |
$addvalues = array(); |
if (!$qr = $this->_values2Query($values, $addvalues)) { |
$this->_releaseLock(); |
return false; |
} |
$sql = sprintf('UPDATE %s SET %s WHERE %s = %s', |
$this->node_table, |
$qr, |
$this->_flparams['id'], |
$id); |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$this->_releaseLock(); |
return true; |
} |
// }}} |
// +----------------------------------------------+ |
// | Moving and copying | |
// |----------------------------------------------+ |
// | [PUBLIC] | |
// +----------------------------------------------+ |
// {{{ moveTree() |
/** |
* Wrapper for node moving and copying |
* |
* @param int $id Source ID |
* @param int $target Target ID |
* @param constant $pos Position (use one of the NESE_MOVE_* constants) |
* @param bool $copy Shall we create a copy |
* |
* @see _moveInsideLevel |
* @see _moveAcross |
* @see _moveRoot2Root |
* @access public |
* @return int ID of the moved node or false on error |
*/ |
function moveTree($id, $targetid, $pos, $copy = false) { |
if ($this->debug) { |
$this->_debugMessage('moveTree($id, $target, $pos, $copy = false)'); |
} |
if($id == $targetid && !$copy) { |
// TRIGGER BOGUS MESSAGE |
return false; |
} |
// Get information about source and target |
if (!($source = $this->pickNode($id, true))) { |
$epr = array('moveTree()', $id); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
if (!($target = $this->pickNode($targetid, true))) { |
$epr = array('moveTree()', $targetid); |
return $this->_raiseError(NESE_ERROR_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR, $epr); |
} |
if (PEAR::isError($lock = $this->_setLock(true))) { |
return $lock; |
} |
$this->_relations = array(); |
// This operations don't need callbacks except the copy handler |
// which ignores this setting |
$this->_skipCallbacks = true; |
if(!$copy) { |
// We have a recursion - let's stop |
if (($target['rootid'] == $source['rootid']) && |
(($source['l'] <= $target['l']) && |
($source['r'] >= $target['r']))) { |
$this->_releaseLock(true); |
$epr = array('moveTree()'); |
return $this->_raiseError(NESE_ERROR_RECURSION, PEAR_ERROR_RETURN, E_USER_NOTICE, $epr); |
} |
// Insert/move before or after |
if (($source['rootid'] == $source['id']) && |
($target['rootid'] == $target['id'])) { |
// We have to move a rootnode which is different from moving inside a tree |
$nid = $this->_moveRoot2Root($source, $target, $pos, $copy); |
$this->_releaseLock(true); |
return $nid; |
} |
} elseif(($target['rootid'] == $source['rootid']) && |
(($source['l'] < $target['l']) && |
($source['r'] > $target['r']))) { |
$this->_releaseLock(true); |
$epr = array('moveTree()'); |
return $this->_raiseError(NESE_ERROR_RECURSION, PEAR_ERROR_RETURN, E_USER_NOTICE, $epr); |
} |
// We have to move between different levels and maybe subtrees - let's rock ;) |
$this->_moveAcross($source, $target, $pos); |
$this->_moveCleanup($copy); |
$this->_releaseLock(true); |
} |
// }}} |
// {{{ _moveAcross() |
/** |
* Moves nodes and trees to other subtrees or levels |
* |
* <pre> |
* [+] <--------------------------------+ |
* +-[\] root1 [target] | |
* <-------------------------+ |p |
* +-\ root2 | | |
* | | | | |
* | |-- subnode1 [target] | |B |
* | |-- subnode2 [new] |S |E |
* | |-- subnode3 |U |F |
* | |B |O |
* +-\ root3 | |R |
* |-- subnode 3.1 | |E |
* |-\ subnode 3.2 [source] >--+------+ |
* |-- subnode 3.2.1 |
*</pre> |
* |
* @param object NodeCT $source Source node |
* @param object NodeCT $target Target node |
* @param string $pos Position [SUBnode/BEfore] |
* @param bool $copy Shall we create a copy |
* |
* @access private |
* @see moveTree |
* @see _r_moveAcross |
* @see _moveCleanup |
*/ |
function _moveAcross($source, $target, $pos) { |
if ($this->debug) { |
$this->_debugMessage('_moveAcross($source, $target, $pos, $copy = false)'); |
} |
// Get the current data from a node and exclude the id params which will be changed |
// because of the node move |
$values = array(); |
foreach($this->params as $key => $val) { |
if ($source[$val] && !in_array($val, $this->_requiredParams)) { |
$values[$key] = trim($source[$val]); |
} |
} |
switch($pos) { |
case NESE_MOVE_BEFORE: |
$clone_id = $this->createLeftNode($target['id'], $values); |
break; |
case NESE_MOVE_AFTER: |
$clone_id = $this->createRightNode($target['id'], $values); |
break; |
case NESE_MOVE_BELOW: |
$clone_id = $this->createSubNode($target['id'], $values); |
break; |
} |
$children = $this->getChildren($source['id'], true, true, true); |
if ($children) { |
$pos = NESE_MOVE_BELOW; |
$sclone_id = $clone_id; |
// Recurse through the child nodes |
foreach($children AS $cid => $child) { |
$sclone = $this->pickNode($sclone_id, true); |
$sclone_id = $this->_moveAcross($child, $sclone, $pos); |
$pos = NESE_MOVE_AFTER; |
} |
} |
$this->_relations[$source['id']] = $clone_id; |
return $clone_id; |
} |
// }}} |
// {{{ _moveCleanup() |
/** |
* Deletes the old subtree (node) and writes the node id's into the cloned tree |
* |
* |
* @param array $relations Hash in der Form $h[alteid]=neueid |
* @param array $copy Are we in copy mode? |
* @access private |
*/ |
function _moveCleanup($copy = false) { |
$relations = $this->_relations; |
if ($this->debug) { |
$this->_debugMessage('_moveCleanup($relations, $copy = false)'); |
} |
$deletes = array(); |
$updates = array(); |
$tb = $this->node_table; |
$fid = $this->_flparams['id']; |
$froot = $this->_flparams['rootid']; |
foreach($relations AS $key => $val) { |
$clone = $this->pickNode($val); |
if ($copy) { |
// EVENT (NodeCopy) |
$eparams = array('clone' => $clone); |
if (!$this->_skipCallbacks && isset($this->_hasListeners['nodeCopy'])) { |
$this->triggerEvent('nodeCopy', $this->pickNode($key), $eparams); |
} |
continue; |
} |
// No callbacks here because the node itself doesn't get changed |
// Only it's position |
// If one needs a callback here please let me know |
$deletes[] = $key; |
// It's isn't a rootnode |
if ($clone->id != $clone->rootid) { |
$sql = sprintf('UPDATE %s SET %s=%s WHERE %s = %s', |
$this->node_table, |
$fid, |
$key, |
$fid, |
$val); |
$updates[] = $sql; |
} else { |
$sql = sprintf('UPDATE %s SET %s=%s, %s=%s WHERE %s=%s', |
$tb, |
$fid, |
$key, |
$froot, |
$val, |
$fid, |
$val); |
$updates[] = $sql; |
$orootid = $clone->rootid; |
$sql = sprintf('UPDATE %s SET %s=%s WHERE %s=%s', |
$tb, |
$froot, |
$key, |
$froot, |
$orootid); |
$updates[] = $sql; |
} |
$this->_skipCallbacks = false; |
} |
if(!empty($deletes)) { |
for($i=0;$i<count($deletes);$i++) { |
$this->deleteNode($deletes[$i]); |
} |
} |
if(!empty($updates)) { |
for($i=0;$i<count($updates);$i++) { |
$res = $this->db->query($updates[$i]); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
} |
return true; |
} |
// }}} |
// {{{ _moveRoot2Root() |
/** |
* Moves rootnodes |
* |
* <pre> |
* +-- root1 |
* | |
* +-\ root2 |
* | | |
* | |-- subnode1 [target] |
* | |-- subnode2 [new] |
* | |-- subnode3 |
* | |
* +-\ root3 |
* [|] <-----------------------+ |
* |-- subnode 3.1 [target] | |
* |-\ subnode 3.2 [source] >--+ |
* |-- subnode 3.2.1 |
* </pre> |
* |
* @param object NodeCT $source Source |
* @param object NodeCT $target Target |
* @param string $pos BEfore | AFter |
* @access private |
* @see moveTree |
*/ |
function _moveRoot2Root($source, $target, $pos) { |
if ($this->debug) { |
$this->_debugMessage('_moveRoot2Root($source, $target, $pos, $copy)'); |
} |
if(PEAR::isError($lock=$this->_setLock())) { |
return $lock; |
} |
$tb = $this->node_table; |
$fid = $this->_flparams['id']; |
$froot = $this->_flparams['rootid']; |
$freh = $this->_flparams['norder']; |
$s_order = $source['norder']; |
$t_order = $target['norder']; |
$s_id = $source['id']; |
$t_id = $target['id']; |
if ($s_order < $t_order) { |
if ($pos == NESE_MOVE_BEFORE) { |
$sql = "UPDATE $tb SET $freh=$freh-1 |
WHERE $freh BETWEEN $s_order AND $t_order AND |
$fid!=$t_id AND |
$fid!=$s_id AND |
$froot=$fid"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$sql = "UPDATE $tb SET $freh=$t_order -1 WHERE $fid=$s_id"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
elseif($pos == NESE_MOVE_AFTER) { |
$sql = "UPDATE $tb SET $freh=$freh-1 |
WHERE $freh BETWEEN $s_order AND $t_order AND |
$fid!=$s_id AND |
$froot=$fid"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$sql = "UPDATE $tb SET $freh=$t_order WHERE $fid=$s_id"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
} |
if ($s_order > $t_order) { |
if ($pos == NESE_MOVE_BEFORE) { |
$sql = "UPDATE $tb SET $freh=$freh+1 |
WHERE $freh BETWEEN $t_order AND $s_order AND |
$fid != $s_id AND |
$froot=$fid"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$sql = "UPDATE $tb SET $freh=$t_order WHERE $fid=$s_id"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
elseif ($pos == NESE_MOVE_AFTER) { |
$sql = "UPDATE $tb SET $freh=$freh+1 |
WHERE $freh BETWEEN $t_order AND $s_order AND |
$fid!=$t_id AND |
$fid!=$s_id AND |
$froot=$fid"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$sql = "UPDATE $tb SET $freh=$t_order+1 WHERE $fid = $s_id"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
} |
$this->_releaseLock(); |
return $source->id; |
} |
// }}} |
// +-----------------------+ |
// | Helper methods | |
// +-----------------------+ |
// }}} |
// {{{ _secSort() |
/** |
* Callback for uasort used to sort siblings |
* |
* @access private |
*/ |
function _secSort($node1, $node2) { |
// Within the same level? |
if($node1['level'] != $node2['level']) { |
return strnatcmp($node1['l'], $node2['l']); |
} |
// Are they siblings? |
$p1 = $this->getParent($node1); |
$p2 = $this->getParent($node2); |
if($p1['id'] != $p2['id']) { |
return strnatcmp($node1['l'], $node2['l']); |
} |
// Same field value? Use the lft value then |
$field = $this->params[$this->secondarySort]; |
if($node1[$field] == $node2[$field]) { |
return strnatcmp($node1['l'], $node2[l]); |
} |
// Compare between siblings with different field value |
return strnatcmp($node1[$field], $node2[$field]); |
} |
// }}} |
// {{{ _addSQL() |
/** |
* Adds a specific type of SQL to a query string |
* |
* @param array $addSQL The array of SQL strings to add. Example value: |
* $addSQL = array( |
* 'cols' => 'tb2.col2, tb2.col3', // Additional tables/columns |
* 'join' => 'LEFT JOIN tb1 USING(STRID)', // Join statement |
* 'append' => 'GROUP by tb1.STRID'); // Group condition |
* @param string $type The type of SQL. Can be 'cols', 'join', or 'append'. |
* |
* @access private |
* @return string The SQL, properly formatted |
*/ |
function _addSQL($addSQL, $type) { |
if (!isset($addSQL[$type])) { |
return ''; |
} |
switch($type) { |
case 'cols': |
return ', ' . $addSQL[$type]; |
default: |
return $addSQL[$type]; |
} |
} |
// }}} |
// {{{ _getSelectFields() |
/** |
* Gets the select fields based on the params |
* |
* @param bool $aliasFields Should we alias the fields so they are the names of the |
* parameter keys, or leave them as is? |
* |
* @access private |
* @return string A string of query fields to select |
*/ |
function _getSelectFields($aliasFields) { |
$queryFields = array(); |
foreach ($this->params as $key => $val) { |
$tmp_field = $this->node_table . '.' . $key; |
if ($aliasFields) { |
$tmp_field .= ' AS ' . $val; |
} |
$queryFields[] = $tmp_field; |
} |
$fields = implode(', ', $queryFields); |
return $fields; |
} |
// }}} |
// {{{ _processResultSet() |
/** |
* Processes a DB result set by checking for a DB error and then transforming the result |
* into a set of DB_NestedSet_Node objects or leaving it as an array. |
* |
* @param string $sql The sql query to be done |
* @param bool $keepAsArray Keep the result as an array or transform it into a set of |
* DB_NestedSet_Node objects? |
* @param bool $fieldsAreAliased Are the fields aliased? |
* |
* @access private |
* @return mixed False on error or the transformed node set. |
*/ |
function _processResultSet($sql, $keepAsArray, $fieldsAreAliased) { |
$result = $this->db->getAll($sql); |
if ($this->_testFatalAbort($result, __FILE__, __LINE__)) { |
return false; |
} |
$nodes = array(); |
$idKey = $fieldsAreAliased ? 'id' : $this->_flparams['id']; |
foreach ($result as $row) { |
$node_id = $row[$idKey]; |
if ($keepAsArray) { |
$nodes[$node_id] = $row; |
} else { |
// Create an instance of the node container |
$nodes[$node_id] =& new DB_NestedSet_Node($row); |
} |
} |
return $nodes; |
} |
// }}} |
// {{{ _testFatalAbort() |
/** |
* Error Handler |
* |
* Tests if a given ressource is a PEAR error object |
* ans raises a fatal error in case of an error object |
* |
* @param object PEAR::Error $errobj The object to test |
* @param string $file The filename wher the error occured |
* @param int $line The line number of the error |
* @return void |
* @access private |
*/ |
function _testFatalAbort($errobj, $file, $line) { |
if (!$this->_isDBError($errobj)) { |
return false; |
} |
if ($this->debug) { |
$this->_debugMessage('_testFatalAbort($errobj, $file, $line)'); |
} |
if ($this->debug) { |
$message = $errobj->getUserInfo(); |
$code = $errobj->getCode(); |
$msg = "$message ($code) in file $file at line $line"; |
} else { |
$msg = $errobj->getMessage(); |
$code = $errobj->getCode(); } |
PEAR::raiseError($msg, $code, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// {{{ __raiseError() |
/** |
* @access private |
*/ |
function _raiseError($code, $mode, $option, $epr=array()) { |
$message = vsprintf($this->_getMessage($code), $epr); |
return PEAR::raiseError($message, $code, $mode, $option); |
} |
// }}} |
// {{{ addListener() |
/** |
* Add an event listener |
* |
* Adds an event listener and returns an ID for it |
* |
* @param string $event The ivent name |
* @param string $listener The listener object |
* @return string |
* @access public |
*/ |
function addListener($event, &$listener) { |
$listenerID = uniqid('el'); |
$this->eventListeners[$event][$listenerID] =& $listener; |
$this->_hasListeners[$event] = true; |
return $listenerID; |
} |
// }}} |
// {{{ removeListener() |
/** |
* Removes an event listener |
* |
* Removes the event listener with the given ID |
* |
* @param string $event The ivent name |
* @param string $listenerID The listener's ID |
* @return bool |
* @access public |
*/ |
function removeListener($event, $listenerID) { |
unset($this->eventListeners[$event][$listenerID]); |
if (!isset($this->eventListeners[$event]) || |
!is_array($this->eventListeners[$event]) || |
count($this->eventListeners[$event]) == 0) { |
unset($this->_hasListeners[$event]); |
} |
return true; |
} |
// }}} |
// {{{ triggerEvent() |
/** |
* Triggers and event an calls the event listeners |
* |
* @param string $event The Event that occured |
* @param object node $node A Reference to the node object which was subject to changes |
* @param array $eparams A associative array of params which may be needed by the handler |
* @return bool |
* @access public |
*/ |
function triggerEvent($event, &$node, $eparams = false) { |
if ($this->_skipCallbacks || !isset($this->_hasListeners[$event])) { |
return false; |
} |
foreach($this->eventListeners[$event] as $key => $val) { |
if (!method_exists($val, 'callEvent')) { |
return new PEAR_Error($this->_getMessage(NESE_ERROR_NOHANDLER), NESE_ERROR_NOHANDLER); |
} |
$val->callEvent($event, $node, $eparams); |
} |
return true; |
} |
// }}} |
// {{{ apiVersion() |
function apiVersion() { |
return array( |
'package:'=>$this->_packagename, |
'majorversion'=>$this->_majorversion, |
'minorversion'=>$this->_minorversion, |
'version'=>sprintf('%s.%s',$this->_majorversion, $this->_minorversion), |
'revision'=>str_replace('$', '',"$Revision: 1.1 $") |
); |
} |
// }}} |
// {{{ setAttr() |
/** |
* Sets an object attribute |
* |
* @param array $attr An associative array with attributes |
* |
* @return bool |
* @access public |
*/ |
function setAttr($attr) { |
static $hasSetSequence; |
if (!isset($hasSetSequence)) { |
$hasSetSequence = false; |
} |
if (!is_array($attr) || count($attr) == 0) { |
return false; |
} |
foreach ($attr as $key => $val) { |
$this->$key = $val; |
if ($key == 'sequence_table') { |
$hasSetSequence = true; |
} |
// only update sequence to reflect new table if they haven't set it manually |
if (!$hasSetSequence && $key == 'node_table') { |
$this->sequence_table = $this->node_table . '_' . $this->_flparams['id']; |
} |
if($key == 'cache' && is_object($val)) { |
$this->_caching = true; |
$GLOBALS['DB_NestedSet'] = & $this; |
} |
} |
return true; |
} |
// }}} |
// {{{ setsortMode() |
/** |
* This enables you to set specific options for each output method |
* |
* @param constant $sortMode |
* |
* @access public |
* @return Current sortMode |
*/ |
function setsortMode($sortMode=false) { |
if($sortMode && in_array($sortMode, $this->_sortModes)) { |
$this->_sortMode = $sortMode; |
} else { |
return $this->_sortMode; |
} |
return $this->_sortMode; |
} |
// }}} |
// {{{ setDbOption() |
/** |
* Sets a db option. Example, setting the sequence table format |
* |
* @var string $option The option to set |
* @var string $val The value of the option |
* |
* @access public |
* @return void |
*/ |
function setDbOption($option, $val) { |
$this->db->setOption($option, $val); |
} |
// }}} |
// {{{ testLock() |
/** |
* Tests if a database lock is set |
* |
* @access public |
*/ |
function testLock() { |
if ($this->debug) { |
$this->_debugMessage('testLock()'); |
} |
if($lockID = $this->_structureTableLock) { |
return $lockID; |
} |
$this->_lockGC(); |
$sql = sprintf('SELECT lockID FROM %s WHERE lockTable=%s', |
$this->lock_table, |
$this->_quote($this->node_table)) ; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
if ($this->_numRows($res)) { |
return new PEAR_Error($this->_getMessage(NESE_ERROR_TBLOCKED),NESE_ERROR_TBLOCKED); |
} |
return false; |
} |
// }}} |
// {{{ _setLock() |
/** |
* @access private |
*/ |
function _setLock($exclusive=false) { |
$lock = $this->testLock(); |
if(PEAR::isError($lock)) { |
return $lock; |
} |
if ($this->debug) { |
$this->_debugMessage('_setLock()'); |
} |
if($this->_caching) { |
@$this->cache->flush('function_cache'); |
$this->_caching = false; |
$this->_restcache = true; |
} |
if (!$lockID = $this->_structureTableLock) { |
$lockID = $this->_structureTableLock = uniqid('lck-'); |
$sql = sprintf('INSERT INTO %s SET lockID=%s, lockTable=%s, lockStamp=%s', |
$this->lock_table, |
$this->_quote($lockID), |
$this->_quote($this->node_table), |
time()); |
} else { |
$sql = sprintf('UPDATE %s set lockStamp=%s WHERE lockID=%s AND lockTable=%s', |
$this->lock_table, |
time(), |
$this->_quote($lockID), |
$this->_quote($this->node_table)); |
} |
if($exclusive) { |
$this->_lockExclusive = true; |
} |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
return $lockID; |
} |
// }}} |
// {{{ _releaseLock() |
/** |
* @access private |
*/ |
function _releaseLock($exclusive=false) { |
if ($this->debug) { |
$this->_debugMessage('_releaseLock()'); |
} |
if($exclusive) { |
$this->_lockExclusive = false; |
} |
if ((!$lockID = $this->_structureTableLock) || $this->_lockExclusive) { |
return false; |
} |
$tb = $this->lock_table; |
$stb = $this->node_table; |
$sql = "DELETE FROM $tb |
WHERE lockTable=" . $this->_quote($stb) . " AND |
lockID=" . $this->_quote($lockID); |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
$this->_structureTableLock = false; |
if($this->_restcache) { |
$this->_caching = true; |
$this->_restcache = false; |
} |
return true; |
} |
// }}} |
// {{{ _lockGC() |
/** |
* @access private |
*/ |
function _lockGC() { |
if ($this->debug) { |
$this->_debugMessage('_lockGC()'); |
} |
$tb = $this->lock_table; |
$stb = $this->node_table; |
$lockTTL = time() - $this->lockTTL; |
$sql = "DELETE FROM $tb |
WHERE lockTable=" . $this->_quote($stb) . " AND |
lockStamp < $lockTTL"; |
$res = $this->db->query($sql); |
$this->_testFatalAbort($res, __FILE__, __LINE__); |
} |
// }}} |
// {{{ _values2Query() |
/** |
* @access private |
*/ |
function _values2Query($values, $addval = false) { |
if ($this->debug) { |
$this->_debugMessage('_values2Query($values, $addval = false)'); |
} |
if (is_array($addval)) { |
$values = $values + $addval; |
} |
$arq = array(); |
foreach($values AS $key => $val) { |
$k = trim($key); |
$v = trim($val); |
if ($k) { |
// To be used with the next mahor version |
// $iv = in_array($this->params[$k], $this->_quotedParams) ? $this->_quote($v) : $v; |
$iv = $this->_quote($v); |
$arq[] = "$k=$iv"; |
} |
} |
if (!is_array($arq) || count($arq) == 0) { |
return false; |
} |
$query = implode(', ', $arq); |
return $query; |
} |
// }}} |
// {{{ _verifyUserValues() |
/** |
* Clean values from protected or unknown columns |
* |
* @var string $caller The calling method |
* @var string $values The values array |
* |
* @access private |
* @return void |
*/ |
function _verifyUserValues($caller, &$values) { |
if($this->_dumbmode) { |
return true; |
} |
foreach($values AS $field=>$value) { |
if(!isset($this->params[$field])) { |
$epr = array( |
$caller, |
sprintf('Unknown column/param \'%s\'', $field)); |
$this->_raiseError(NESE_ERROR_WRONG_MPARAM, PEAR_ERROR_RETURN, E_USER_NOTICE, $epr); |
unset($values[$field]); |
} else { |
$flip = $this->params[$field]; |
if(in_array($flip, $this->_requiredParams)) { |
$epr = array( |
$caller, |
sprintf('\'%s\' is autogenerated and can\'t be passed - it will be ignored', $field)); |
$this->_raiseError(NESE_ERROR_WRONG_MPARAM, PEAR_ERROR_RETURN, E_USER_NOTICE, $epr); |
unset($values[$field]); |
} |
} |
} |
} |
// }}} |
// {{{ _debugMessage() |
/** |
* @access private |
*/ |
function _debugMessage($msg) { |
if ($this->debug) { |
$time = $this->_getmicrotime(); |
echo "$time::Debug:: $msg<br />\n"; |
} |
} |
// }}} |
// {{{ _getMessage() |
/** |
* @access private |
*/ |
function _getMessage($code) { |
if ($this->debug) { |
$this->_debugMessage('_getMessage($code)'); |
} |
return isset($this->messages[$code]) ? $this->messages[$code] : $this->messages[NESE_MESSAGE_UNKNOWN]; |
} |
// }}} |
// {{{ _getmicrotime() |
/** |
* @access private |
*/ |
function _getmicrotime() { |
list($usec, $sec) = explode(' ', microtime()); |
return ((float)$usec + (float)$sec); |
} |
// }}} |
// {{{ convertTreeModel() |
/** |
* Convert a <1.3 tree into a 1.3 tree format |
* |
* This will convert the tree into a format needed for some new features in |
* 1.3. Your <1.3 tree will still work without converting but some new features |
* like preorder sorting won't work as expected. |
* |
* <pre> |
* Usage: |
* - Create a new node table (tb_nodes2) from the current node table (tb_nodes1) (only copy the structure). |
* - Create a nested set instance of the 'old' set (NeSe1) and one of the new set (NeSe2) |
* - Now you have 2 identical objects where only node_table differs |
* - Call DB_NestedSet::convertTreeModel(&$orig, &$copy); |
* - After that you have a cleaned up copy of tb_nodes1 inside tb_nodes2 |
* </pre> |
* |
* @param object DB_NestedSet $orig Nested set we want to copy |
* @param object DB_NestedSet $copy Object where the new tree is copied to |
* @param integer $_parent ID of the parent node (private) |
* |
* @static |
* @access public |
* @return bool True uns success |
*/ |
function convertTreeModel(&$orig, &$copy, $_parent=false) { |
static $firstSet; |
$isRoot = false; |
if(!$_parent) { |
if(!is_object($orig) || !is_object($copy)) { |
return false; |
} |
if($orig->node_table == $copy->node_table) { |
return false; |
} |
$copy->_dumbmode = true; |
$orig->sortMode = NESE_SORT_LEVEL; |
$copy->sortMode = NESE_SORT_LEVEL; |
$sibl = $orig->getRootNodes(true); |
$isRoot = true; |
} else { |
$sibl = $orig->getChildren($_parent, true); |
} |
if(empty($sibl)) { |
return false; |
} |
foreach($sibl AS $sid=>$sibling) { |
unset($sibling['l']); |
unset($sibling['r']); |
unset($sibling['norder']); |
$values = array(); |
foreach($sibling AS $key=>$val) { |
if(!isset($copy->_flparams[$key])) { |
continue; |
} |
$values[$copy->_flparams[$key]] = $val; |
} |
if(!$firstSet) { |
$psid = $copy->createRootNode($values, false, true); |
$firstSet = true; |
} elseif($isRoot) { |
$psid = $copy->createRightNode($psid, $values); |
} else { |
$copy->createSubNode($_parent, $values); |
} |
DB_NestedSet::convertTreeModel($orig, $copy, $sid); |
} |
return true; |
} |
// }}} |
// {{{ _numRows() |
/** |
* Fetches the number of rows the last query returned |
* @access private |
* @abstract |
*/ |
function _numRows($res) { |
} |
// }}} |
// {{{ _isDBError() |
/** |
* Returns true if a db return value is an error object |
* @access private |
* @abstract |
*/ |
function _isDBError($err) { |
} |
// }}} |
// {{{ quote() |
/** |
* Quotes a string to use it inside queries |
* @access private |
* @abstract |
*/ |
function _quote($str) { |
} |
} |
// {{{ DB_NestedSet_Node:: class |
/** |
* Generic class for node objects |
* |
* @autor Daniel Khan <dk@webcluster.at>; |
* @version $Revision: 1.1 $ |
* @package DB_NestedSet |
* |
* @access private |
*/ |
class DB_NestedSet_Node { |
// {{{ constructor |
/** |
* Constructor |
*/ |
function DB_NestedSet_Node($data) { |
if (!is_array($data) || count($data) == 0) { |
return new PEAR_ERROR($data, NESE_ERROR_PARAM_MISSING); |
} |
$this->setAttr($data); |
return true; |
} |
// }}} |
// {{{ setAttr() |
function setAttr($data) { |
if(!is_array($data) || count($data) == 0) { |
return false; |
} |
foreach ($data as $key => $val) { |
$this->$key = $val; |
} |
} |
// }}} |
} |
// }}} |
?> |
/tags/v2.0-narmer/api/pear/DB/Pager.php |
---|
New file |
0,0 → 1,250 |
<?php |
// |
// Pear DB Pager - Retrieve and return information of databases |
// result sets |
// |
// Copyright (C) 2001 Tomas Von Veschler Cox <cox@idecnet.com> |
// |
// This library is free software; you can redistribute it and/or |
// modify it under the terms of the GNU Lesser General Public |
// License as published by the Free Software Foundation; either |
// version 2.1 of the License, or (at your option) any later version. |
// |
// This library is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
// Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public |
// License along with this library; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// |
// |
// $Id: Pager.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
require_once 'PEAR.php'; |
require_once 'DB.php'; |
/** |
* This class handles all the stuff needed for displaying paginated results |
* from a database query of Pear DB, in a very easy way. |
* Documentation and examples of use, can be found in: |
* http://vulcanonet.com/soft/pager/ (could be outdated) |
* |
* IMPORTANT! |
* Since PEAR DB already support native row limit (more fast and avaible in |
* all the drivers), there is no more need to use $pager->build() or |
* the $pager->fetch*() methods. |
* |
* Usage example: |
* |
*< ?php |
* require_once 'DB/Pager.php'; |
* $db = DB::connect('your DSN string'); |
* $from = 0; // The row to start to fetch from (you might want to get this |
* // param from the $_GET array |
* $limit = 10; // The number of results per page |
* $maxpages = 10; // The number of pages for displaying in the pager (optional) |
* $res = $db->limitQuery($sql, $from, $limit); |
* $nrows = 0; // Alternative you could use $res->numRows() |
* while ($row = $res->fetchrow()) { |
* // XXX code for building the page here |
* $nrows++; |
* } |
* $data = DB_Pager::getData($from, $limit, $nrows, $maxpages); |
* // XXX code for building the pager here |
* ? > |
* |
* @version 0.7 |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @see http://vulcanonet.com/soft/pager/ |
*/ |
class DB_Pager extends PEAR |
{ |
/** |
* Constructor |
* |
* @param object $res A DB_result object from Pear_DB |
* @param int $from The row to start fetching |
* @param int $limit How many results per page |
* @param int $numrows Pager will automatically |
* find this param if is not given. If your Pear_DB backend extension |
* doesn't support numrows(), you can manually calculate it |
* and supply later to the constructor |
* @deprecated |
*/ |
function DB_Pager (&$res, $from, $limit, $numrows = null) |
{ |
$this->res = $res; |
$this->from = $from; |
$this->limit = $limit; |
$this->numrows = $numrows; |
} |
/** |
* Calculates all the data needed by Pager to work |
* |
* @return mixed An assoc array with all the data (see getData) |
* or DB_Error on error |
* @see DB_Pager::getData |
* @deprecated |
*/ |
function build() |
{ |
// if there is no numrows given, calculate it |
if ($this->numrows === null) { |
$this->numrows = $this->res->numrows(); |
if (DB::isError($this->numrows)) { |
return $this->numrows; |
} |
} |
$data = $this->getData($this->from, $this->limit, $this->numrows); |
if (DB::isError($data)) { |
return $data; |
} |
$this->current = $this->from - 1; |
$this->top = $data['to']; |
return $data; |
} |
/** |
* @deprecated |
*/ |
function fetchRow($mode=DB_FETCHMODE_DEFAULT) |
{ |
$this->current++; |
if ($this->current >= $this->top) { |
return null; |
} |
return $this->res->fetchRow($mode, $this->current); |
} |
/** |
* @deprecated |
*/ |
function fetchInto(&$arr, $mode=DB_FETCHMODE_DEFAULT) |
{ |
$this->current++; |
if ($this->current >= $this->top) { |
return null; |
} |
return $this->res->fetchInto($arr, $mode, $this->current); |
} |
/* |
* Gets all the data needed to paginate results |
* This is an associative array with the following |
* values filled in: |
* |
* array( |
* 'current' => X, // current page you are |
* 'numrows' => X, // total number of results |
* 'next' => X, // row number where next page starts |
* 'prev' => X, // row number where prev page starts |
* 'remain' => X, // number of results remaning *in next page* |
* 'numpages'=> X, // total number of pages |
* 'from' => X, // the row to start fetching |
* 'to' => X, // the row to stop fetching |
* 'limit' => X, // how many results per page |
* 'maxpages' => X, // how many pages to show (google style) |
* 'firstpage' => X, // the row number of the first page |
* 'lastpage' => X, // the row number where the last page starts |
* 'pages' => array( // assoc with page "number => start row" |
* 1 => X, |
* 2 => X, |
* 3 => X |
* ) |
* ); |
* @param int $from The row to start fetching |
* @param int $limit How many results per page |
* @param int $numrows Number of results from query |
* |
* @return array associative array with data or DB_error on error |
* |
*/ |
function &getData($from, $limit, $numrows, $maxpages = false) |
{ |
if (empty($numrows) || ($numrows < 0)) { |
return null; |
} |
$from = (empty($from)) ? 0 : $from; |
if ($limit <= 0) { |
return PEAR::raiseError (null, 'wrong "limit" param', null, |
null, null, 'DB_Error', true); |
} |
// Total number of pages |
$pages = ceil($numrows/$limit); |
$data['numpages'] = $pages; |
// first & last page |
$data['firstpage'] = 1; |
$data['lastpage'] = $pages; |
// Build pages array |
$data['pages'] = array(); |
for ($i=1; $i <= $pages; $i++) { |
$offset = $limit * ($i-1); |
$data['pages'][$i] = $offset; |
// $from must point to one page |
if ($from == $offset) { |
// The current page we are |
$data['current'] = $i; |
} |
} |
if (!isset($data['current'])) { |
return PEAR::raiseError (null, 'wrong "from" param', null, |
null, null, 'DB_Error', true); |
} |
// Limit number of pages (goole algoritm) |
if ($maxpages) { |
$radio = floor($maxpages/2); |
$minpage = $data['current'] - $radio; |
if ($minpage < 1) { |
$minpage = 1; |
} |
$maxpage = $data['current'] + $radio - 1; |
if ($maxpage > $data['numpages']) { |
$maxpage = $data['numpages']; |
} |
foreach (range($minpage, $maxpage) as $page) { |
$tmp[$page] = $data['pages'][$page]; |
} |
$data['pages'] = $tmp; |
$data['maxpages'] = $maxpages; |
} else { |
$data['maxpages'] = null; |
} |
// Prev link |
$prev = $from - $limit; |
$data['prev'] = ($prev >= 0) ? $prev : null; |
// Next link |
$next = $from + $limit; |
$data['next'] = ($next < $numrows) ? $next : null; |
// Results remaining in next page & Last row to fetch |
if ($data['current'] == $pages) { |
$data['remain'] = 0; |
$data['to'] = $numrows; |
} else { |
if ($data['current'] == ($pages - 1)) { |
$data['remain'] = $numrows - ($limit*($pages-1)); |
} else { |
$data['remain'] = $limit; |
} |
$data['to'] = $data['current'] * $limit; |
} |
$data['numrows'] = $numrows; |
$data['from'] = $from + 1; |
$data['limit'] = $limit; |
return $data; |
} |
} |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/DataObject.php |
---|
New file |
0,0 → 1,3827 |
<?php |
/** |
* Object Based Database Query Builder and data store |
* |
* 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_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: DataObject.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
/* =========================================================================== |
* |
* !!!!!!!!!!!!! W A R N I N G !!!!!!!!!!! |
* |
* THIS MAY SEGFAULT PHP IF YOU ARE USING THE ZEND OPTIMIZER (to fix it, |
* just add "define('DB_DATAOBJECT_NO_OVERLOAD',true);" before you include |
* this file. reducing the optimization level may also solve the segfault. |
* =========================================================================== |
*/ |
/** |
* The main "DB_DataObject" class is really a base class for your own tables classes |
* |
* // Set up the class by creating an ini file (refer to the manual for more details |
* [DB_DataObject] |
* database = mysql:/username:password@host/database |
* schema_location = /home/myapplication/database |
* class_location = /home/myapplication/DBTables/ |
* clase_prefix = DBTables_ |
* |
* |
* //Start and initialize...................... - dont forget the & |
* $config = parse_ini_file('example.ini',true); |
* $options = &PEAR::getStaticProperty('DB_DataObject','options'); |
* $options = $config['DB_DataObject']; |
* |
* // example of a class (that does not use the 'auto generated tables data') |
* class mytable extends DB_DataObject { |
* // mandatory - set the table |
* var $_database_dsn = "mysql://username:password@localhost/database"; |
* var $__table = "mytable"; |
* function table() { |
* return array( |
* 'id' => 1, // integer or number |
* 'name' => 2, // string |
* ); |
* } |
* function keys() { |
* return array('id'); |
* } |
* } |
* |
* // use in the application |
* |
* |
* Simple get one row |
* |
* $instance = new mytable; |
* $instance->get("id",12); |
* echo $instance->somedata; |
* |
* |
* Get multiple rows |
* |
* $instance = new mytable; |
* $instance->whereAdd("ID > 12"); |
* $instance->whereAdd("ID < 14"); |
* $instance->find(); |
* while ($instance->fetch()) { |
* echo $instance->somedata; |
* } |
/** |
* Needed classes |
* - we use getStaticProperty from PEAR pretty extensively (cant remove it ATM) |
*/ |
require_once 'PEAR.php'; |
/** |
* We are setting a global fetchmode assoc constant of 2 to be compatible with |
* both DB and MDB2 |
*/ |
define('DB_DATAOBJECT_FETCHMODE_ASSOC',2); |
/** |
* these are constants for the get_table array |
* user to determine what type of escaping is required around the object vars. |
*/ |
define('DB_DATAOBJECT_INT', 1); // does not require '' |
define('DB_DATAOBJECT_STR', 2); // requires '' |
define('DB_DATAOBJECT_DATE', 4); // is date #TODO |
define('DB_DATAOBJECT_TIME', 8); // is time #TODO |
define('DB_DATAOBJECT_BOOL', 16); // is boolean #TODO |
define('DB_DATAOBJECT_TXT', 32); // is long text #TODO |
define('DB_DATAOBJECT_BLOB', 64); // is blob type |
define('DB_DATAOBJECT_NOTNULL', 128); // not null col. |
define('DB_DATAOBJECT_MYSQLTIMESTAMP' , 256); // mysql timestamps (ignored by update/insert) |
/* |
* Define this before you include DataObjects.php to disable overload - if it segfaults due to Zend optimizer.. |
*/ |
//define('DB_DATAOBJECT_NO_OVERLOAD',true) |
/** |
* Theses are the standard error codes, most methods will fail silently - and return false |
* to access the error message either use $table->_lastError |
* or $last_error = PEAR::getStaticProperty('DB_DataObject','lastError'); |
* the code is $last_error->code, and the message is $last_error->message (a standard PEAR error) |
*/ |
define('DB_DATAOBJECT_ERROR_INVALIDARGS', -1); // wrong args to function |
define('DB_DATAOBJECT_ERROR_NODATA', -2); // no data available |
define('DB_DATAOBJECT_ERROR_INVALIDCONFIG', -3); // something wrong with the config |
define('DB_DATAOBJECT_ERROR_NOCLASS', -4); // no class exists |
define('DB_DATAOBJECT_ERROR_INVALID_CALL' ,-7); // overlad getter/setter failure |
/** |
* Used in methods like delete() and count() to specify that the method should |
* build the condition only out of the whereAdd's and not the object parameters. |
*/ |
define('DB_DATAOBJECT_WHEREADD_ONLY', true); |
/** |
* |
* storage for connection and result objects, |
* it is done this way so that print_r()'ing the is smaller, and |
* it reduces the memory size of the object. |
* -- future versions may use $this->_connection = & PEAR object.. |
* although will need speed tests to see how this affects it. |
* - includes sub arrays |
* - connections = md5 sum mapp to pear db object |
* - results = [id] => map to pear db object |
* - resultseq = sequence id for results & results field |
* - resultfields = [id] => list of fields return from query (for use with toArray()) |
* - ini = mapping of database to ini file results |
* - links = mapping of database to links file |
* - lasterror = pear error objects for last error event. |
* - config = aliased view of PEAR::getStaticPropery('DB_DataObject','options') * done for performance. |
* - array of loaded classes by autoload method - to stop it doing file access request over and over again! |
*/ |
$GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['RESULTSEQ'] = 1; |
$GLOBALS['_DB_DATAOBJECT']['RESULTFIELDS'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['INI'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['LINKS'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['SEQUENCE'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['LASTERROR'] = null; |
$GLOBALS['_DB_DATAOBJECT']['CONFIG'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['CACHE'] = array(); |
$GLOBALS['_DB_DATAOBJECT']['OVERLOADED'] = false; |
$GLOBALS['_DB_DATAOBJECT']['QUERYENDTIME'] = 0; |
// this will be horrifically slow!!!! |
// NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer (see define before..) |
// these two are BC/FC handlers for call in PHP4/5 |
if ( substr(phpversion(),0,1) == 5) { |
class DB_DataObject_Overload |
{ |
function __call($method,$args) |
{ |
$return = null; |
$this->_call($method,$args,$return); |
return $return; |
} |
function __sleep() |
{ |
return array_keys(get_object_vars($this)) ; |
} |
} |
} else { |
if (version_compare(phpversion(),'4.3.10','eq') && !defined('DB_DATAOBJECT_NO_OVERLOAD')) { |
trigger_error( |
"overload does not work with PHP4.3.10, either upgrade |
(snaps.php.net) or more recent version |
or define DB_DATAOBJECT_NO_OVERLOAD as per the manual. |
",E_USER_ERROR); |
} |
if (!function_exists('clone')) { |
// emulate clone - as per php_compact, slow but really the correct behaviour.. |
eval('function clone($t) { $r = $t; if (method_exists($r,"__clone")) { $r->__clone(); } return $r; }'); |
} |
eval(' |
class DB_DataObject_Overload { |
function __call($method,$args,&$return) { |
return $this->_call($method,$args,$return); |
} |
} |
'); |
} |
/* |
* |
* @package DB_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @since PHP 4.0 |
*/ |
class DB_DataObject extends DB_DataObject_Overload |
{ |
/** |
* The Version - use this to check feature changes |
* |
* @access private |
* @var string |
*/ |
var $_DB_DataObject_version = "1.7.15"; |
/** |
* The Database table (used by table extends) |
* |
* @access private |
* @var string |
*/ |
var $__table = ''; // database table |
/** |
* The Number of rows returned from a query |
* |
* @access public |
* @var int |
*/ |
var $N = 0; // Number of rows returned from a query |
/* ============================================================= */ |
/* Major Public Methods */ |
/* (designed to be optionally then called with parent::method()) */ |
/* ============================================================= */ |
/** |
* Get a result using key, value. |
* |
* for example |
* $object->get("ID",1234); |
* Returns Number of rows located (usually 1) for success, |
* and puts all the table columns into this classes variables |
* |
* see the fetch example on how to extend this. |
* |
* if no value is entered, it is assumed that $key is a value |
* and get will then use the first key in keys() |
* to obtain the key. |
* |
* @param string $k column |
* @param string $v value |
* @access public |
* @return int No. of rows |
*/ |
function get($k = null, $v = null) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
$keys = array(); |
if ($v === null) { |
$v = $k; |
$keys = $this->keys(); |
if (!$keys) { |
$this->raiseError("No Keys available for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
$k = $keys[0]; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("$k $v " .print_r($keys,true), "GET"); |
} |
if ($v === null) { |
$this->raiseError("No Value specified for get", DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
$this->$k = $v; |
return $this->find(1); |
} |
/** |
* An autoloading, caching static get method using key, value (based on get) |
* |
* Usage: |
* $object = DB_DataObject::staticGet("DbTable_mytable",12); |
* or |
* $object = DB_DataObject::staticGet("DbTable_mytable","name","fred"); |
* |
* or write it into your extended class: |
* function &staticGet($k,$v=NULL) { return DB_DataObject::staticGet("This_Class",$k,$v); } |
* |
* @param string $class class name |
* @param string $k column (or value if using keys) |
* @param string $v value (optional) |
* @access public |
* @return object |
*/ |
function &staticGet($class, $k, $v = null) |
{ |
$lclass = strtolower($class); |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
$key = "$k:$v"; |
if ($v === null) { |
$key = $k; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
DB_DataObject::debug("$class $key","STATIC GET - TRY CACHE"); |
} |
if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) { |
return $_DB_DATAOBJECT['CACHE'][$lclass][$key]; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
DB_DataObject::debug("$class $key","STATIC GET - NOT IN CACHE"); |
} |
$obj = DB_DataObject::factory(substr($class,strlen($_DB_DATAOBJECT['CONFIG']['class_prefix']))); |
if (PEAR::isError($obj)) { |
DB_DataObject::raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS); |
return false; |
} |
if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) { |
$_DB_DATAOBJECT['CACHE'][$lclass] = array(); |
} |
if (!$obj->get($k,$v)) { |
DB_DataObject::raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
$_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj; |
return $_DB_DATAOBJECT['CACHE'][$lclass][$key]; |
} |
/** |
* find results, either normal or crosstable |
* |
* for example |
* |
* $object = new mytable(); |
* $object->ID = 1; |
* $object->find(); |
* |
* |
* will set $object->N to number of rows, and expects next command to fetch rows |
* will return $object->N |
* |
* @param boolean $n Fetch first result |
* @access public |
* @return mixed (number of rows returned, or true if numRows fetching is not supported) |
*/ |
function find($n = false) |
{ |
global $_DB_DATAOBJECT; |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug($n, "__find",1); |
} |
if (!$this->__table) { |
// xdebug can backtrace this! |
php_error("NO \$__table SPECIFIED in class definition",E_USER_ERROR); |
} |
$this->N = 0; |
$query_before = $this->_query; |
$this->_build_condition($this->table()) ; |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
/* We are checking for method modifyLimitQuery as it is PEAR DB specific */ |
$sql = 'SELECT ' . |
$this->_query['data_select'] . |
' FROM ' . ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table) . " " . |
$this->_join . |
$this->_query['condition'] . ' '. |
$this->_query['group_by'] . ' '. |
$this->_query['having'] . ' '. |
$this->_query['order_by'] . ' '; |
if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) || |
($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) { |
/* PEAR DB specific */ |
if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) { |
$sql = $DB->modifyLimitQuery($sql,$this->_query['limit_start'], $this->_query['limit_count']); |
} |
} else { |
/* theoretically MDB! */ |
if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) { |
$DB->setLimit($this->_query['limit_count'],$this->_query['limit_start']); |
} |
} |
$this->_query($sql); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("CHECK autofetchd $n", "__find", 1); |
} |
// unset the |
if ($n && $this->N > 0 ) { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("ABOUT TO AUTOFETCH", "__find", 1); |
} |
$this->fetch() ; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("DONE", "__find", 1); |
} |
$this->_query = $query_before; |
return $this->N; |
} |
/** |
* fetches next row into this objects var's |
* |
* returns 1 on success 0 on failure |
* |
* |
* |
* Example |
* $object = new mytable(); |
* $object->name = "fred"; |
* $object->find(); |
* $store = array(); |
* while ($object->fetch()) { |
* echo $this->ID; |
* $store[] = $object; // builds an array of object lines. |
* } |
* |
* to add features to a fetch |
* function fetch () { |
* $ret = parent::fetch(); |
* $this->date_formated = date('dmY',$this->date); |
* return $ret; |
* } |
* |
* @access public |
* @return boolean on success |
*/ |
function fetch() |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
if (empty($this->N)) { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("No data returned from FIND (eg. N is 0)","FETCH", 3); |
} |
return false; |
} |
if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) || |
!is_object($result = &$_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) |
{ |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug('fetched on object after fetch completed (no results found)'); |
} |
return false; |
} |
$array = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ASSOC); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug(serialize($array),"FETCH"); |
} |
if ($array === null) { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$t= explode(' ',microtime()); |
$this->debug("Last Data Fetch'ed after " . |
($t[0]+$t[1]- $_DB_DATAOBJECT['QUERYENDTIME'] ) . |
" seconds", |
"FETCH", 1); |
} |
// reduce the memory usage a bit... (but leave the id in, so count() works ok on it) |
unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]); |
// this is probably end of data!! |
//DB_DataObject::raiseError("fetch: no data returned", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
if (!isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) { |
// note: we dont declare this to keep the print_r size down. |
$_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]= array_flip(array_keys($array)); |
} |
foreach($array as $k=>$v) { |
$kk = str_replace(".", "_", $k); |
$kk = str_replace(" ", "_", $kk); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("$kk = ". $array[$k], "fetchrow LINE", 3); |
} |
$this->$kk = $array[$k]; |
} |
// set link flag |
$this->_link_loaded=false; |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("{$this->__table} DONE", "fetchrow",2); |
} |
if (isset($this->_query) && empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) { |
unset($this->_query); |
} |
return true; |
} |
/** |
* Adds a condition to the WHERE statement, defaults to AND |
* |
* $object->whereAdd(); //reset or cleaer ewhwer |
* $object->whereAdd("ID > 20"); |
* $object->whereAdd("age > 20","OR"); |
* |
* @param string $cond condition |
* @param string $logic optional logic "OR" (defaults to "AND") |
* @access public |
* @return string|PEAR::Error - previous condition or Error when invalid args found |
*/ |
function whereAdd($cond = false, $logic = 'AND') |
{ |
if (!isset($this->_query)) { |
return $this->raiseError( |
"You cannot do two queries on the same object (clone it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
if ($cond === false) { |
$r = $this->_query['condition']; |
$this->_query['condition'] = ''; |
return $r; |
} |
// check input...= 0 or ' ' == error! |
if (!trim($cond)) { |
return $this->raiseError("WhereAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
$r = $this->_query['condition']; |
if ($this->_query['condition']) { |
$this->_query['condition'] .= " {$logic} {$cond}"; |
return $r; |
} |
$this->_query['condition'] = " WHERE {$cond}"; |
return $r; |
} |
/** |
* Adds a order by condition |
* |
* $object->orderBy(); //clears order by |
* $object->orderBy("ID"); |
* $object->orderBy("ID,age"); |
* |
* @param string $order Order |
* @access public |
* @return none|PEAR::Error - invalid args only |
*/ |
function orderBy($order = false) |
{ |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($order === false) { |
$this->_query['order_by'] = ''; |
return; |
} |
// check input...= 0 or ' ' == error! |
if (!trim($order)) { |
return $this->raiseError("orderBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
if (!$this->_query['order_by']) { |
$this->_query['order_by'] = " ORDER BY {$order} "; |
return; |
} |
$this->_query['order_by'] .= " , {$order}"; |
} |
/** |
* Adds a group by condition |
* |
* $object->groupBy(); //reset the grouping |
* $object->groupBy("ID DESC"); |
* $object->groupBy("ID,age"); |
* |
* @param string $group Grouping |
* @access public |
* @return none|PEAR::Error - invalid args only |
*/ |
function groupBy($group = false) |
{ |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($group === false) { |
$this->_query['group_by'] = ''; |
return; |
} |
// check input...= 0 or ' ' == error! |
if (!trim($group)) { |
return $this->raiseError("groupBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
if (!$this->_query['group_by']) { |
$this->_query['group_by'] = " GROUP BY {$group} "; |
return; |
} |
$this->_query['group_by'] .= " , {$group}"; |
} |
/** |
* Adds a having clause |
* |
* $object->having(); //reset the grouping |
* $object->having("sum(value) > 0 "); |
* |
* @param string $having condition |
* @access public |
* @return none|PEAR::Error - invalid args only |
*/ |
function having($having = false) |
{ |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($having === false) { |
$this->_query['having'] = ''; |
return; |
} |
// check input...= 0 or ' ' == error! |
if (!trim($having)) { |
return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
if (!$this->_query['having']) { |
$this->_query['having'] = " HAVING {$having} "; |
return; |
} |
$this->_query['having'] .= " AND {$having}"; |
} |
/** |
* Sets the Limit |
* |
* $boject->limit(); // clear limit |
* $object->limit(12); |
* $object->limit(12,10); |
* |
* Note this will emit an error on databases other than mysql/postgress |
* as there is no 'clean way' to implement it. - you should consider refering to |
* your database manual to decide how you want to implement it. |
* |
* @param string $a limit start (or number), or blank to reset |
* @param string $b number |
* @access public |
* @return none|PEAR::Error - invalid args only |
*/ |
function limit($a = null, $b = null) |
{ |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($a === null) { |
$this->_query['limit_start'] = ''; |
$this->_query['limit_count'] = ''; |
return; |
} |
// check input...= 0 or ' ' == error! |
if ((!is_int($a) && ((string)((int)$a) !== (string)$a)) |
|| (($b !== null) && (!is_int($b) && ((string)((int)$b) !== (string)$b)))) { |
return $this->raiseError("limit: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
global $_DB_DATAOBJECT; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$this->_query['limit_start'] = ($b == null) ? 0 : (int)$a; |
$this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b; |
} |
/** |
* Adds a select columns |
* |
* $object->selectAdd(); // resets select to nothing! |
* $object->selectAdd("*"); // default select |
* $object->selectAdd("unixtime(DATE) as udate"); |
* $object->selectAdd("DATE"); |
* |
* to prepend distict: |
* $object->selectAdd('distinct ' . $object->selectAdd()); |
* |
* @param string $k |
* @access public |
* @return mixed null or old string if you reset it. |
*/ |
function selectAdd($k = null) |
{ |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($k === null) { |
$old = $this->_query['data_select']; |
$this->_query['data_select'] = ''; |
return $old; |
} |
// check input...= 0 or ' ' == error! |
if (!trim($k)) { |
return $this->raiseError("selectAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
if ($this->_query['data_select']) { |
$this->_query['data_select'] .= ', '; |
} |
$this->_query['data_select'] .= " $k "; |
} |
/** |
* Adds multiple Columns or objects to select with formating. |
* |
* $object->selectAs(null); // adds "table.colnameA as colnameA,table.colnameB as colnameB,......" |
* // note with null it will also clear the '*' default select |
* $object->selectAs(array('a','b'),'%s_x'); // adds "a as a_x, b as b_x" |
* $object->selectAs(array('a','b'),'ddd_%s','ccc'); // adds "ccc.a as ddd_a, ccc.b as ddd_b" |
* $object->selectAdd($object,'prefix_%s'); // calls $object->get_table and adds it all as |
* objectTableName.colnameA as prefix_colnameA |
* |
* @param array|object|null the array or object to take column names from. |
* @param string format in sprintf format (use %s for the colname) |
* @param string table name eg. if you have joinAdd'd or send $from as an array. |
* @access public |
* @return void |
*/ |
function selectAs($from = null,$format = '%s',$tableName=false) |
{ |
global $_DB_DATAOBJECT; |
if (!isset($this->_query)) { |
$this->raiseError( |
"You cannot do two queries on the same object (copy it before finding)", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if ($from === null) { |
// blank the '*' |
$this->selectAdd(); |
$from = $this; |
} |
$table = $this->__table; |
if (is_object($from)) { |
$table = $from->__table; |
$from = array_keys($from->table()); |
} |
if ($tableName !== false) { |
$table = $tableName; |
} |
$s = '%s'; |
if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) { |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$s = $DB->quoteIdentifier($s); |
} |
foreach ($from as $k) { |
$this->selectAdd(sprintf("{$s}.{$s} as {$format}",$table,$k,$k)); |
} |
$this->_query['data_select'] .= "\n"; |
} |
/** |
* Insert the current objects variables into the database |
* |
* Returns the ID of the inserted element (if auto increment or sequences are used.) |
* |
* for example |
* |
* Designed to be extended |
* |
* $object = new mytable(); |
* $object->name = "fred"; |
* echo $object->insert(); |
* |
* @access public |
* @return mixed false on failure, int when auto increment or sequence used, otherwise true on success |
*/ |
function insert() |
{ |
global $_DB_DATAOBJECT; |
// we need to write to the connection (For nextid) - so us the real |
// one not, a copyied on (as ret-by-ref fails with overload!) |
if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
$this->_connect(); |
} |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$items = isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ? |
$_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table(); |
if (!$items) { |
$this->raiseError("insert:No table definition for {$this->__table}", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
$options = &$_DB_DATAOBJECT['CONFIG']; |
$datasaved = 1; |
$leftq = ''; |
$rightq = ''; |
$seqKeys = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table]) ? |
$_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] : |
$this->sequenceKey(); |
$key = isset($seqKeys[0]) ? $seqKeys[0] : false; |
$useNative = isset($seqKeys[1]) ? $seqKeys[1] : false; |
$seq = isset($seqKeys[2]) ? $seqKeys[2] : false; |
$dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["phptype"]; |
// nativeSequences or Sequences.. |
// big check for using sequences |
if (($key !== false) && !$useNative) { |
if (!$seq) { |
$this->$key = $DB->nextId($this->__table); |
} else { |
$f = $DB->getOption('seqname_format'); |
$DB->setOption('seqname_format','%s'); |
$this->$key = $DB->nextId($seq); |
$DB->setOption('seqname_format',$f); |
} |
} |
foreach($items as $k => $v) { |
// if we are using autoincrement - skip the column... |
if ($key && ($k == $key) && $useNative) { |
continue; |
} |
if (!isset($this->$k)) { |
continue; |
} |
// dont insert data into mysql timestamps |
// use query() if you really want to do this!!!! |
if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) { |
continue; |
} |
if ($leftq) { |
$leftq .= ', '; |
$rightq .= ', '; |
} |
$leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ') : "$k "); |
if (is_a($this->$k,'db_dataobject_cast')) { |
$value = $this->$k->toString($v,$DB); |
if (PEAR::isError($value)) { |
$this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG); |
return false; |
} |
$rightq .= $value; |
continue; |
} |
if ((strtolower($this->$k) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) { |
$rightq .= " NULL "; |
continue; |
} |
// DATE is empty... on a col. that can be null.. |
// note: this may be usefull for time as well.. |
if (!$this->$k && |
(($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) && |
!($v & DB_DATAOBJECT_NOTNULL)) { |
$rightq .= " NULL "; |
continue; |
} |
if ($v & DB_DATAOBJECT_STR) { |
$rightq .= $this->_quote((string) ( |
($v & DB_DATAOBJECT_BOOL) ? |
// this is thanks to the braindead idea of postgres to |
// use t/f for boolean. |
(($this->$k == 'f') ? 0 : (int)(bool) $this->$k) : |
$this->$k |
)) . " "; |
continue; |
} |
if (is_numeric($this->$k)) { |
$rightq .=" {$this->$k} "; |
continue; |
} |
// at present we only cast to integers |
// - V2 may store additional data about float/int |
$rightq .= ' ' . intval($this->$k) . ' '; |
} |
// not sure why we let empty insert here.. - I guess to generate a blank row.. |
if ($leftq || $useNative) { |
$table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table); |
$r = $this->_query("INSERT INTO {$table} ($leftq) VALUES ($rightq) "); |
if (PEAR::isError($r)) { |
$this->raiseError($r); |
return false; |
} |
if ($r < 1) { |
return 0; |
} |
// now do we have an integer key! |
if ($key && $useNative) { |
switch ($dbtype) { |
case 'mysql': |
case 'mysqli': |
$method = "{$dbtype}_insert_id"; |
$this->$key = $method( |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection |
); |
break; |
case 'mssql': |
// note this is not really thread safe - you should wrapp it with |
// transactions = eg. |
// $db->query('BEGIN'); |
// $db->insert(); |
// $db->query('COMMIT'); |
$mssql_key = $DB->getOne("SELECT @@IDENTITY"); |
if (PEAR::isError($mssql_key)) { |
$this->raiseError($r); |
return false; |
} |
$this->$key = $mssql_key; |
break; |
case 'pgsql': |
if (!$seq) { |
$seq = $DB->getSequenceName($this->__table ); |
} |
$pgsql_key = $DB->getOne("SELECT last_value FROM ".$seq); |
if (PEAR::isError($pgsql_key)) { |
$this->raiseError($r); |
return false; |
} |
$this->$key = $pgsql_key; |
break; |
case 'ifx': |
$this->$key = array_shift ( |
ifx_fetch_row ( |
ifx_query( |
"select DBINFO('sqlca.sqlerrd1') FROM systables where tabid=1", |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection, |
IFX_SCROLL |
), |
"FIRST" |
) |
); |
break; |
} |
} |
if (isset($_DB_DATAOBJECT['CACHE'][strtolower(get_class($this))])) { |
$this->_clear_cache(); |
} |
if ($key) { |
return $this->$key; |
} |
return true; |
} |
$this->raiseError("insert: No Data specifed for query", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
/** |
* Updates current objects variables into the database |
* uses the keys() to decide how to update |
* Returns the true on success |
* |
* for example |
* |
* $object = DB_DataObject::factory('mytable'); |
* $object->get("ID",234); |
* $object->email="testing@test.com"; |
* if(!$object->update()) |
* echo "UPDATE FAILED"; |
* |
* to only update changed items : |
* $dataobject->get(132); |
* $original = $dataobject; // clone/copy it.. |
* $dataobject->setFrom($_POST); |
* if ($dataobject->validate()) { |
* $dataobject->update($original); |
* } // otherwise an error... |
* |
* performing global updates: |
* $object = DB_DataObject::factory('mytable'); |
* $object->status = "dead"; |
* $object->whereAdd('age > 150'); |
* $object->update(DB_DATAOBJECT_WHEREADD_ONLY); |
* |
* @param object dataobject (optional) | DB_DATAOBJECT_WHEREADD_ONLY - used to only update changed items. |
* @access public |
* @return int rows affected or false on failure |
*/ |
function update($dataObject = false) |
{ |
global $_DB_DATAOBJECT; |
// connect will load the config! |
$this->_connect(); |
$original_query = isset($this->_query) ? $this->_query : null; |
$items = isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ? |
$_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table(); |
// only apply update against sequence key if it is set????? |
$seq = $this->sequenceKey(); |
if ($seq[0] !== false) { |
$keys = array($seq[0]); |
if (empty($this->{$keys[0]}) && $dataObject !== true) { |
$this->raiseError("update: trying to perform an update without |
the key set, and argument to update is not |
DB_DATAOBJECT_WHEREADD_ONLY |
", DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
} else { |
$keys = $this->keys(); |
} |
if (!$items) { |
$this->raiseError("update:No table definition for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
$datasaved = 1; |
$settings = ''; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$dbtype = $DB->dsn["phptype"]; |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
foreach($items as $k => $v) { |
if (!isset($this->$k)) { |
continue; |
} |
// ignore stuff thats |
// dont write things that havent changed.. |
if (($dataObject !== false) && isset($dataObject->$k) && ($dataObject->$k == $this->$k)) { |
continue; |
} |
// - dont write keys to left.!!! |
if (in_array($k,$keys)) { |
continue; |
} |
// dont insert data into mysql timestamps |
// use query() if you really want to do this!!!! |
if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) { |
continue; |
} |
if ($settings) { |
$settings .= ', '; |
} |
$kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k); |
if (is_a($this->$k,'db_dataobject_cast')) { |
$value = $this->$k->toString($v,$DB); |
if (PEAR::isError($value)) { |
$this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG); |
return false; |
} |
$settings .= "$kSql = $value "; |
continue; |
} |
// special values ... at least null is handled... |
if ((strtolower($this->$k) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) { |
$settings .= "$kSql = NULL "; |
continue; |
} |
// DATE is empty... on a col. that can be null.. |
// note: this may be usefull for time as well.. |
if (!$this->$k && |
(($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) && |
!($v & DB_DATAOBJECT_NOTNULL)) { |
$settings .= "$kSql = NULL "; |
continue; |
} |
if ($v & DB_DATAOBJECT_STR) { |
$settings .= "$kSql = ". $this->_quote((string) ( |
($v & DB_DATAOBJECT_BOOL) ? |
// this is thanks to the braindead idea of postgres to |
// use t/f for boolean. |
(($this->$k == 'f') ? 0 : (int)(bool) $this->$k) : |
$this->$k |
)) . ' '; |
continue; |
} |
if (is_numeric($this->$k)) { |
$settings .= "$kSql = {$this->$k} "; |
continue; |
} |
// at present we only cast to integers |
// - V2 may store additional data about float/int |
$settings .= "$kSql = " . intval($this->$k) . ' '; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("got keys as ".serialize($keys),3); |
} |
if ($dataObject !== true) { |
$this->_build_condition($items,$keys); |
} else { |
// prevent wiping out of data! |
if (empty($this->_query['condition'])) { |
$this->raiseError("update: global table update not available |
do \$do->whereAdd('1=1'); if you really want to do that. |
", DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
} |
// echo " $settings, $this->condition "; |
if ($settings && isset($this->_query) && $this->_query['condition']) { |
$table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table); |
$r = $this->_query("UPDATE {$table} SET {$settings} {$this->_query['condition']} "); |
// restore original query conditions. |
$this->_query = $original_query; |
if (PEAR::isError($r)) { |
$this->raiseError($r); |
return false; |
} |
if ($r < 1) { |
return 0; |
} |
$this->_clear_cache(); |
return $r; |
} |
// restore original query conditions. |
$this->_query = $original_query; |
// if you manually specified a dataobject, and there where no changes - then it's ok.. |
if ($dataObject !== false) { |
return true; |
} |
$this->raiseError( |
"update: No Data specifed for query $settings , {$this->_query['condition']}", |
DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
/** |
* Deletes items from table which match current objects variables |
* |
* Returns the true on success |
* |
* for example |
* |
* Designed to be extended |
* |
* $object = new mytable(); |
* $object->ID=123; |
* echo $object->delete(); // builds a conditon |
* |
* $object = new mytable(); |
* $object->whereAdd('age > 12'); |
* $object->limit(1); |
* $object->orderBy('age DESC'); |
* $object->delete(true); // dont use object vars, use the conditions, limit and order. |
* |
* @param bool $useWhere (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then |
* we will build the condition only using the whereAdd's. Default is to |
* build the condition only using the object parameters. |
* |
* @access public |
* @return mixed True on success, false on failure, 0 on no data affected |
*/ |
function delete($useWhere = false) |
{ |
global $_DB_DATAOBJECT; |
// connect will load the config! |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
$extra_cond = ' ' . (isset($this->_query['order_by']) ? $this->_query['order_by'] : ''); |
if (!$useWhere) { |
$keys = $this->keys(); |
$this->_query = array(); // as it's probably unset! |
$this->_query['condition'] = ''; // default behaviour not to use where condition |
$this->_build_condition($this->table(),$keys); |
// if primary keys are not set then use data from rest of object. |
if (!$this->_query['condition']) { |
$this->_build_condition($this->table(),array(),$keys); |
} |
$extra_cond = ''; |
} |
// don't delete without a condition |
if (isset($this->_query) && $this->_query['condition']) { |
$table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table); |
$sql = "DELETE FROM {$table} {$this->_query['condition']}{$extra_cond}"; |
// add limit.. |
if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) { |
if (!isset($_DB_DATAOBJECT['CONFIG']['db_driver']) || |
($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) { |
// pear DB |
$sql = $DB->modifyLimitQuery($sql,$this->_query['limit_start'], $this->_query['limit_count']); |
} else { |
// MDB |
$DB->setLimit( $this->_query['limit_count'],$this->_query['limit_start']); |
} |
} |
$r = $this->_query($sql); |
if (PEAR::isError($r)) { |
$this->raiseError($r); |
return false; |
} |
if ($r < 1) { |
return 0; |
} |
$this->_clear_cache(); |
return $r; |
} else { |
$this->raiseError("delete: No condition specifed for query", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
} |
/** |
* fetches a specific row into this object variables |
* |
* Not recommended - better to use fetch() |
* |
* Returens true on success |
* |
* @param int $row row |
* @access public |
* @return boolean true on success |
*/ |
function fetchRow($row = null) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
$this->_loadConfig(); |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("{$this->__table} $row of {$this->N}", "fetchrow",3); |
} |
if (!$this->__table) { |
$this->raiseError("fetchrow: No table", DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
if ($row === null) { |
$this->raiseError("fetchrow: No row specified", DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
if (!$this->N) { |
$this->raiseError("fetchrow: No results avaiable", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("{$this->__table} $row of {$this->N}", "fetchrow",3); |
} |
$result = &$_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]; |
$array = $result->fetchrow(DB_DATAOBJECT_FETCHMODE_ASSOC,$row); |
if (!is_array($array)) { |
$this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
foreach($array as $k => $v) { |
$kk = str_replace(".", "_", $k); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("$kk = ". $array[$k], "fetchrow LINE", 3); |
} |
$this->$kk = $array[$k]; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("{$this->__table} DONE", "fetchrow", 3); |
} |
return true; |
} |
/** |
* Find the number of results from a simple query |
* |
* for example |
* |
* $object = new mytable(); |
* $object->name = "fred"; |
* echo $object->count(); |
* echo $object->count(true); // dont use object vars. |
* echo $object->count('distinct mycol'); count distinct mycol. |
* echo $object->count('distinct mycol',true); // dont use object vars. |
* echo $object->count('distinct'); // count distinct id (eg. the primary key) |
* |
* |
* @param bool|string (optional) |
* (true|false => see below not on whereAddonly) |
* (string) |
* "DISTINCT" => does a distinct count on the tables 'key' column |
* otherwise => normally it counts primary keys - you can use |
* this to do things like $do->count('distinct mycol'); |
* |
* @param bool $whereAddOnly (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then |
* we will build the condition only using the whereAdd's. Default is to |
* build the condition using the object parameters as well. |
* |
* @access public |
* @return int |
*/ |
function count($countWhat = false,$whereAddOnly = false) |
{ |
global $_DB_DATAOBJECT; |
if (is_bool($countWhat)) { |
$whereAddOnly = $countWhat; |
} |
$t = clone($this); |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
$items = $t->table(); |
if (!isset($t->_query)) { |
$this->raiseError( |
"You cannot do run count after you have run fetch()", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
if (!$whereAddOnly && $items) { |
$t->_build_condition($items); |
} |
$keys = $this->keys(); |
if (!$keys[0] && !is_string($countWhat)) { |
$this->raiseError( |
"You cannot do run count without keys - use \$do->keys('id');", |
DB_DATAOBJECT_ERROR_INVALIDARGS,PEAR_ERROR_DIE); |
return false; |
} |
$table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table); |
$key_col = ($quoteIdentifiers ? $DB->quoteIdentifier($keys[0]) : $keys[0]); |
$as = ($quoteIdentifiers ? $DB->quoteIdentifier('DATAOBJECT_NUM') : 'DATAOBJECT_NUM'); |
// support distinct on default keys. |
$countWhat = (strtoupper($countWhat) == 'DISTINCT') ? |
"DISTINCT {$table}.{$key_col}" : $countWhat; |
$countWhat = is_string($countWhat) ? $countWhat : "{$table}.{$key_col}"; |
$r = $t->_query( |
"SELECT count({$countWhat}) as $as |
FROM $table {$t->_join} {$t->_query['condition']}"); |
if (PEAR::isError($r)) { |
return false; |
} |
$result = &$_DB_DATAOBJECT['RESULTS'][$t->_DB_resultid]; |
$l = $result->fetchRow(); |
return $l[0]; |
} |
/** |
* sends raw query to database |
* |
* Since _query has to be a private 'non overwriteable method', this is a relay |
* |
* @param string $string SQL Query |
* @access public |
* @return void or DB_Error |
*/ |
function query($string) |
{ |
return $this->_query($string); |
} |
/** |
* an escape wrapper around DB->escapeSimple() |
* can be used when adding manual queries or clauses |
* eg. |
* $object->query("select * from xyz where abc like '". $object->escape($_GET['name']) . "'"); |
* |
* @param string $string value to be escaped |
* @access public |
* @return string |
*/ |
function escape($string) |
{ |
global $_DB_DATAOBJECT; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
// mdb uses escape... |
$dd = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver']; |
return ($dd == 'DB') ? $DB->escapeSimple($string) : $DB->escape($string); |
} |
/* ==================================================== */ |
/* Major Private Vars */ |
/* ==================================================== */ |
/** |
* The Database connection dsn (as described in the PEAR DB) |
* only used really if you are writing a very simple application/test.. |
* try not to use this - it is better stored in configuration files.. |
* |
* @access private |
* @var string |
*/ |
var $_database_dsn = ''; |
/** |
* The Database connection id (md5 sum of databasedsn) |
* |
* @access private |
* @var string |
*/ |
var $_database_dsn_md5 = ''; |
/** |
* The Database name |
* created in __connection |
* |
* @access private |
* @var string |
*/ |
var $_database = ''; |
/** |
* The QUERY rules |
* This replaces alot of the private variables |
* used to build a query, it is unset after find() is run. |
* |
* |
* |
* @access private |
* @var array |
*/ |
var $_query = array( |
'condition' => '', // the WHERE condition |
'group_by' => '', // the GROUP BY condition |
'order_by' => '', // the ORDER BY condition |
'having' => '', // the HAVING condition |
'limit_start' => '', // the LIMIT condition |
'limit_count' => '', // the LIMIT condition |
'data_select' => '*', // the columns to be SELECTed |
); |
/** |
* Database result id (references global $_DB_DataObject[results] |
* |
* @access private |
* @var integer |
*/ |
var $_DB_resultid; // database result object |
/* ============================================================== */ |
/* Table definition layer (started of very private but 'came out'*/ |
/* ============================================================== */ |
/** |
* Autoload or manually load the table definitions |
* |
* |
* usage : |
* DB_DataObject::databaseStructure( 'databasename', |
* parse_ini_file('mydb.ini',true), |
* parse_ini_file('mydb.link.ini',true)); |
* |
* obviously you dont have to use ini files.. (just return array similar to ini files..) |
* |
* It should append to the table structure array |
* |
* |
* @param optional string name of database to assign / read |
* @param optional array structure of database, and keys |
* @param optional array table links |
* |
* @access public |
* @return true or PEAR:error on wrong paramenters.. or false if no file exists.. |
* or the array(tablename => array(column_name=>type)) if called with 1 argument.. (databasename) |
*/ |
function databaseStructure() |
{ |
global $_DB_DATAOBJECT; |
// Assignment code |
if ($args = func_get_args()) { |
if (count($args) == 1) { |
// this returns all the tables and their structure.. |
$x = new DB_DataObject; |
$x->_database = $args[0]; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$tables = $DB->getListOf('tables'); |
require_once 'DB/DataObject/Generator.php'; |
foreach($tables as $table) { |
$y = new DB_DataObject_Generator; |
$y->fillTableSchema($x->_database,$table); |
} |
return $_DB_DATAOBJECT['INI'][$x->_database]; |
} else { |
$_DB_DATAOBJECT['INI'][$args[0]] = isset($_DB_DATAOBJECT['INI'][$args[0]]) ? |
$_DB_DATAOBJECT['INI'][$args[0]] + $args[1] : $args[1]; |
if (isset($args[1])) { |
$_DB_DATAOBJECT['LINKS'][$args[0]] = isset($_DB_DATAOBJECT['LINKS'][$args[0]]) ? |
$_DB_DATAOBJECT['LINKS'][$args[0]] + $args[2] : $args[2]; |
} |
return true; |
} |
} |
if (!$this->_database) { |
$this->_connect(); |
} |
// loaded already? |
if (!empty($_DB_DATAOBJECT['INI'][$this->_database])) { |
// database loaded - but this is table is not available.. |
if (empty($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) { |
require_once 'DB/DataObject/Generator.php'; |
$x = new DB_DataObject_Generator; |
$x->fillTableSchema($this->_database,$this->__table); |
} |
return true; |
} |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
// if you supply this with arguments, then it will take those |
// as the database and links array... |
$schemas = isset($_DB_DATAOBJECT['CONFIG']['schema_location']) ? |
array("{$_DB_DATAOBJECT['CONFIG']['schema_location']}/{$this->_database}.ini") : |
array() ; |
if (isset($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"])) { |
$schemas = is_array($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]) ? |
$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"] : |
explode(PATH_SEPARATOR,$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]); |
} |
foreach ($schemas as $ini) { |
$links = |
isset($_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"]) ? |
$_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"] : |
str_replace('.ini','.links.ini',$ini); |
if (file_exists($ini) && is_file($ini)) { |
$_DB_DATAOBJECT['INI'][$this->_database] = parse_ini_file($ini, true); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("Loaded ini file: $ini","databaseStructure",1); |
} |
} else { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("Missing ini file: $ini","databaseStructure",1); |
} |
} |
if (empty($_DB_DATAOBJECT['LINKS'][$this->_database]) && file_exists($links) && is_file($links)) { |
/* not sure why $links = ... here - TODO check if that works */ |
$_DB_DATAOBJECT['LINKS'][$this->_database] = parse_ini_file($links, true); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("Loaded links.ini file: $links","databaseStructure",1); |
} |
} else { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("Missing links.ini file: $links","databaseStructure",1); |
} |
} |
} |
// now have we loaded the structure.. - if not try building it.. |
if (empty($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) { |
require_once 'DB/DataObject/Generator.php'; |
$x = new DB_DataObject_Generator; |
$x->fillTableSchema($this->_database,$this->__table); |
} |
return true; |
} |
/** |
* Return or assign the name of the current table |
* |
* |
* @param string optinal table name to set |
* @access public |
* @return string The name of the current table |
*/ |
function tableName() |
{ |
$args = func_get_args(); |
if (count($args)) { |
$this->__table = $args[0]; |
} |
return $this->__table; |
} |
/** |
* Return or assign the name of the current database |
* |
* @param string optional database name to set |
* @access public |
* @return string The name of the current database |
*/ |
function database() |
{ |
$args = func_get_args(); |
if (count($args)) { |
$this->_database = $args[0]; |
} |
return $this->_database; |
} |
/** |
* get/set an associative array of table columns |
* |
* @access public |
* @param array key=>type array |
* @return array (associative) |
*/ |
function table() |
{ |
// for temporary storage of database fields.. |
// note this is not declared as we dont want to bloat the print_r output |
$args = func_get_args(); |
if (count($args)) { |
$this->_database_fields = $args[0]; |
} |
if (isset($this->_database_fields)) { |
return $this->_database_fields; |
} |
global $_DB_DATAOBJECT; |
if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
$this->_connect(); |
} |
if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) { |
return $_DB_DATAOBJECT['INI'][$this->_database][$this->__table]; |
} |
$this->databaseStructure(); |
$ret = array(); |
if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) { |
$ret = $_DB_DATAOBJECT['INI'][$this->_database][$this->__table]; |
} |
return $ret; |
} |
/** |
* get/set an array of table primary keys |
* |
* set usage: $do->keys('id','code'); |
* |
* This is defined in the table definition if it gets it wrong, |
* or you do not want to use ini tables, you can override this. |
* @param string optional set the key |
* @param * optional set more keys |
* @access private |
* @return array |
*/ |
function keys() |
{ |
// for temporary storage of database fields.. |
// note this is not declared as we dont want to bloat the print_r output |
$args = func_get_args(); |
if (count($args)) { |
$this->_database_keys = $args; |
} |
if (isset($this->_database_keys)) { |
return $this->_database_keys; |
} |
global $_DB_DATAOBJECT; |
if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
$this->_connect(); |
} |
if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) { |
return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]); |
} |
$this->databaseStructure(); |
if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) { |
return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]); |
} |
return array(); |
} |
/** |
* get/set an sequence key |
* |
* by default it returns the first key from keys() |
* set usage: $do->sequenceKey('id',true); |
* |
* override this to return array(false,false) if table has no real sequence key. |
* |
* @param string optional the key sequence/autoinc. key |
* @param boolean optional use native increment. default false |
* @param false|string optional native sequence name |
* @access private |
* @return array (column,use_native,sequence_name) |
*/ |
function sequenceKey() |
{ |
global $_DB_DATAOBJECT; |
// call setting |
if (!$this->_database) { |
$this->_connect(); |
} |
if (!isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database])) { |
$_DB_DATAOBJECT['SEQUENCE'][$this->_database] = array(); |
} |
$args = func_get_args(); |
if (count($args)) { |
$args[1] = isset($args[1]) ? $args[1] : false; |
$args[2] = isset($args[2]) ? $args[2] : false; |
$_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = $args; |
} |
if (isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table])) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table]; |
} |
// end call setting (eg. $do->sequenceKeys(a,b,c); ) |
$keys = $this->keys(); |
if (!$keys) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] |
= array(false,false,false);; |
} |
$table = isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ? |
$_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table(); |
$dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype']; |
$usekey = $keys[0]; |
$seqname = false; |
if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table])) { |
$usekey = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table]; |
if (strpos($usekey,':') !== false) { |
list($usekey,$seqname) = explode(':',$usekey); |
} |
} |
// if the key is not an integer - then it's not a sequence or native |
if (!($table[$usekey] & DB_DATAOBJECT_INT)) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,false); |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'])) { |
$ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys']; |
if (is_string($ignore) && (strtoupper($ignore) == 'ALL')) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname); |
} |
if (is_string($ignore)) { |
$ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'] = explode(',',$ignore); |
} |
if (in_array($this->__table,$ignore)) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname); |
} |
} |
$realkeys = $_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]; |
// if you are using an old ini file - go back to old behaviour... |
if (is_numeric($realkeys[$usekey])) { |
$realkeys[$usekey] = 'N'; |
} |
// multiple unique primary keys without a native sequence... |
if (($realkeys[$usekey] == 'K') && (count($keys) > 1)) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname); |
} |
// use native sequence keys... |
// technically postgres native here... |
// we need to get the new improved tabledata sorted out first. |
if ( in_array($dbtype , array( 'mysql', 'mysqli', 'mssql', 'ifx')) && |
($table[$usekey] & DB_DATAOBJECT_INT) && |
isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N') |
) { |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array($usekey,true,$seqname); |
} |
// if not a native autoinc, and we have not assumed all primary keys are sequence |
if (($realkeys[$usekey] != 'N') && |
!empty($_DB_DATAOBJECT['CONFIG']['dont_use_pear_sequences'])) { |
return array(false,false,false); |
} |
// I assume it's going to try and be a nextval DB sequence.. (not native) |
return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array($usekey,false,$seqname); |
} |
/* =========================================================== */ |
/* Major Private Methods - the core part! */ |
/* =========================================================== */ |
/** |
* clear the cache values for this class - normally done on insert/update etc. |
* |
* @access private |
* @return void |
*/ |
function _clear_cache() |
{ |
global $_DB_DATAOBJECT; |
$class = get_class($this); |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("Clearing Cache for ".$class,1); |
} |
if (!empty($_DB_DATAOBJECT['CACHE'][$class])) { |
unset($_DB_DATAOBJECT['CACHE'][$class]); |
} |
} |
/** |
* backend wrapper for quoting, as MDB and DB do it differently... |
* |
* @access private |
* @return string quoted |
*/ |
function _quote($str) |
{ |
global $_DB_DATAOBJECT; |
return (empty($_DB_DATAOBJECT['CONFIG']['db_driver']) || |
($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) |
? $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quoteSmart($str) |
: $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->quote($str); |
} |
/** |
* connects to the database |
* |
* |
* TODO: tidy this up - This has grown to support a number of connection options like |
* a) dynamic changing of ini file to change which database to connect to |
* b) multi data via the table_{$table} = dsn ini option |
* c) session based storage. |
* |
* @access private |
* @return true | PEAR::error |
*/ |
function _connect() |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
$this->_loadConfig(); |
} |
// is it already connected ? |
if ($this->_database_dsn_md5 && !empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
if (PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
return $this->raiseError( |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->message, |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code, PEAR_ERROR_DIE |
); |
} |
if (!$this->_database) { |
$this->_database = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['database']; |
if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite') |
&& is_file($this->_database)) |
{ |
$this->_database = basename($this->_database); |
} |
} |
// theoretically we have a md5, it's listed in connections and it's not an error. |
// so everything is ok! |
return true; |
} |
// it's not currently connected! |
// try and work out what to use for the dsn ! |
$options= &$_DB_DATAOBJECT['CONFIG']; |
$dsn = isset($this->_database_dsn) ? $this->_database_dsn : null; |
if (!$dsn) { |
if (!$this->_database) { |
$this->_database = isset($options["table_{$this->__table}"]) ? $options["table_{$this->__table}"] : null; |
} |
if ($this->_database && !empty($options["database_{$this->_database}"])) { |
$dsn = $options["database_{$this->_database}"]; |
} else if (!empty($options['database'])) { |
$dsn = $options['database']; |
} |
} |
// if still no database... |
if (!$dsn) { |
return $this->raiseError( |
"No database name / dsn found anywhere", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG, PEAR_ERROR_DIE |
); |
} |
$this->_database_dsn_md5 = md5($dsn); |
if (!empty($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("USING CACHED CONNECTION", "CONNECT",3); |
} |
if (!$this->_database) { |
$this->_database = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["database"]; |
if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite') |
&& is_file($this->_database)) |
{ |
$this->_database = basename($this->_database); |
} |
} |
return true; |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug("NEW CONNECTION", "CONNECT",3); |
/* actualy make a connection */ |
$this->debug("{$dsn} {$this->_database_dsn_md5}", "CONNECT",3); |
} |
// Note this is verbose deliberatly! |
if (!isset($_DB_DATAOBJECT['CONFIG']['db_driver']) || |
($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) { |
/* PEAR DB connect */ |
// this allows the setings of compatibility on DB |
$db_options = PEAR::getStaticProperty('DB','options'); |
require_once 'DB.php'; |
if ($db_options) { |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn,$db_options); |
} else { |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn); |
} |
} else { |
/* assumption is MDB */ |
require_once 'MDB2.php'; |
// this allows the setings of compatibility on MDB2 |
$db_options = PEAR::getStaticProperty('MDB2','options'); |
if ($db_options) { |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = MDB2::connect($dsn,$db_options); |
} else { |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = MDB2::connect($dsn); |
} |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug(serialize($_DB_DATAOBJECT['CONNECTIONS']), "CONNECT",5); |
} |
if (PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
$this->debug($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->toString(), "CONNECT FAILED",5); |
return $this->raiseError( |
"Connect failed, turn on debugging to 5 see why", |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->code, PEAR_ERROR_DIE |
); |
} |
if (!$this->_database) { |
$this->_database = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["database"]; |
if (($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'] == 'sqlite') |
&& is_file($this->_database)) |
{ |
$this->_database = basename($this->_database); |
} |
} |
// Oracle need to optimize for portibility - not sure exactly what this does though :) |
$c = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
return true; |
} |
/** |
* sends query to database - this is the private one that must work |
* - internal functions use this rather than $this->query() |
* |
* @param string $string |
* @access private |
* @return mixed none or PEAR_Error |
*/ |
function _query($string) |
{ |
global $_DB_DATAOBJECT; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$options = &$_DB_DATAOBJECT['CONFIG']; |
$_DB_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? |
'DB': $_DB_DATAOBJECT['CONFIG']['db_driver']; |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug($string,$log="QUERY"); |
} |
if (strtoupper($string) == 'BEGIN') { |
if ($_DB_driver == 'DB') { |
$DB->autoCommit(false); |
} else { |
$DB->beginTransaction(); |
} |
// db backend adds begin anyway from now on.. |
return true; |
} |
if (strtoupper($string) == 'COMMIT') { |
$res = $DB->commit(); |
if ($_DB_driver == 'DB') { |
$DB->autoCommit(true); |
} |
return $res; |
} |
if (strtoupper($string) == 'ROLLBACK') { |
$DB->rollback(); |
if ($_DB_driver == 'DB') { |
$DB->autoCommit(true); |
} |
return true; |
} |
if (!empty($options['debug_ignore_updates']) && |
(strtolower(substr(trim($string), 0, 6)) != 'select') && |
(strtolower(substr(trim($string), 0, 4)) != 'show') && |
(strtolower(substr(trim($string), 0, 8)) != 'describe')) { |
$this->debug('Disabling Update as you are in debug mode'); |
return $this->raiseError("Disabling Update as you are in debug mode", null) ; |
} |
//if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 1) { |
// this will only work when PEAR:DB supports it. |
//$this->debug($DB->getAll('explain ' .$string,DB_DATAOBJECT_FETCHMODE_ASSOC), $log="sql",2); |
//} |
// some sim |
$t= explode(' ',microtime()); |
$_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0]+$t[1]; |
$result = $DB->query($string); |
if (is_a($result,'DB_Error')) { |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug($result->toString(), "Query Error",1 ); |
} |
return $this->raiseError($result); |
} |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$t= explode(' ',microtime()); |
$_DB_DATAOBJECT['QUERYENDTIME'] = $t[0]+$t[1]; |
$this->debug('QUERY DONE IN '.($t[0]+$t[1]-$time)." seconds", 'query',1); |
} |
switch (strtolower(substr(trim($string),0,6))) { |
case 'insert': |
case 'update': |
case 'delete': |
if ($_DB_driver == 'DB') { |
// pear DB specific |
return $DB->affectedRows(); |
} |
return $result; |
} |
if (is_object($result)) { |
// lets hope that copying the result object is OK! |
$_DB_resultid = $GLOBALS['_DB_DATAOBJECT']['RESULTSEQ']++; |
$_DB_DATAOBJECT['RESULTS'][$_DB_resultid] = $result; |
$this->_DB_resultid = $_DB_resultid; |
} |
$this->N = 0; |
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { |
$this->debug(serialize($result), 'RESULT',5); |
} |
if (method_exists($result, 'numrows')) { |
$DB->expectError(DB_ERROR_UNSUPPORTED); |
$this->N = $result->numrows(); |
if (is_a($this->N,'DB_Error')) { |
$this->N = true; |
} |
$DB->popExpect(); |
} |
} |
/** |
* Builds the WHERE based on the values of of this object |
* |
* @param mixed $keys |
* @param array $filter (used by update to only uses keys in this filter list). |
* @param array $negative_filter (used by delete to prevent deleting using the keys mentioned..) |
* @access private |
* @return string |
*/ |
function _build_condition($keys, $filter = array(),$negative_filter=array()) |
{ |
global $_DB_DATAOBJECT; |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
// if we dont have query vars.. - reset them. |
if (!isset($this->_query)) { |
$x = new DB_DataObject; |
$this->_query= $x->_query; |
} |
foreach($keys as $k => $v) { |
// index keys is an indexed array |
/* these filter checks are a bit suspicious.. |
- need to check that update really wants to work this way */ |
if ($filter) { |
if (!in_array($k, $filter)) { |
continue; |
} |
} |
if ($negative_filter) { |
if (in_array($k, $negative_filter)) { |
continue; |
} |
} |
if (!isset($this->$k)) { |
continue; |
} |
$kSql = $quoteIdentifiers |
? ( $DB->quoteIdentifier($this->__table) . '.' . $DB->quoteIdentifier($k) ) |
: "{$this->__table}.{$k}"; |
if (is_a($this->$k,'db_dataobject_cast')) { |
$dbtype = $DB->dsn["phptype"]; |
$value = $this->$k->toString($v,$DB); |
if (PEAR::isError($value)) { |
$this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG); |
return false; |
} |
if ((strtolower($value) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) { |
$this->whereAdd(" $kSql IS NULL"); |
continue; |
} |
$this->whereAdd(" $kSql = $value"); |
continue; |
} |
if ((strtolower($this->$k) === 'null') && !($v & DB_DATAOBJECT_NOTNULL)) { |
$this->whereAdd(" $kSql IS NULL"); |
continue; |
} |
if ($v & DB_DATAOBJECT_STR) { |
$this->whereAdd(" $kSql = " . $this->_quote((string) ( |
($v & DB_DATAOBJECT_BOOL) ? |
// this is thanks to the braindead idea of postgres to |
// use t/f for boolean. |
(($this->$k == 'f') ? 0 : (int)(bool) $this->$k) : |
$this->$k |
)) ); |
continue; |
} |
if (is_numeric($this->$k)) { |
$this->whereAdd(" $kSql = {$this->$k}"); |
continue; |
} |
/* this is probably an error condition! */ |
$this->whereAdd(" $kSql = ".intval($this->$k)); |
} |
} |
/** |
* autoload Class relating to a table |
* (depreciated - use ::factory) |
* |
* @param string $table table |
* @access private |
* @return string classname on Success |
*/ |
function staticAutoloadTable($table) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
$p = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ? |
$_DB_DATAOBJECT['CONFIG']['class_prefix'] : ''; |
$class = $p . preg_replace('/[^A-Z0-9]/i','_',ucfirst($table)); |
$class = (class_exists($class)) ? $class : DB_DataObject::_autoloadClass($class); |
return $class; |
} |
/** |
* classic factory method for loading a table class |
* usage: $do = DB_DataObject::factory('person') |
* WARNING - this may emit a include error if the file does not exist.. |
* use @ to silence it (if you are sure it is acceptable) |
* eg. $do = @DB_DataObject::factory('person') |
* |
* table name will eventually be databasename/table |
* - and allow modular dataobjects to be written.. |
* (this also helps proxy creation) |
* |
* |
* @param string $table tablename (use blank to create a new instance of the same class.) |
* @access private |
* @return DataObject|PEAR_Error |
*/ |
function factory($table = '') { |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
if ($table === '') { |
if (is_a($this,'DB_DataObject') && strlen($this->__table)) { |
$table = $this->__table; |
} else { |
return DB_DataObject::raiseError( |
"factory did not recieve a table name", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
} |
} |
$p = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ? |
$_DB_DATAOBJECT['CONFIG']['class_prefix'] : ''; |
$class = $p . preg_replace('/[^A-Z0-9]/i','_',ucfirst($table)); |
$class = (class_exists($class)) ? $class : DB_DataObject::_autoloadClass($class); |
// proxy = full|light |
if (!$class && isset($_DB_DATAOBJECT['CONFIG']['proxy'])) { |
$proxyMethod = 'getProxy'.$_DB_DATAOBJECT['CONFIG']['proxy']; |
require_once 'DB/DataObject/Generator.php'; |
$d = new DB_DataObject; |
$d->__table = $table; |
$d->_connect(); |
$x = new DB_DataObject_Generator; |
return $x->$proxyMethod( $d->_database, $table); |
} |
if (!$class) { |
return DB_DataObject::raiseError( |
"factory could not find class $class from $table", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
} |
return new $class; |
} |
/** |
* autoload Class |
* |
* @param string $class Class |
* @access private |
* @return string classname on Success |
*/ |
function _autoloadClass($class) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
$table = substr($class,strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])); |
// only include the file if it exists - and barf badly if it has parse errors :) |
if (!empty($_DB_DATAOBJECT['CONFIG']['proxy']) && empty($_DB_DATAOBJECT['CONFIG']['class_location'])) { |
return false; |
} |
if (strpos($_DB_DATAOBJECT['CONFIG']['class_location'],'%s') !== false) { |
$file = sprintf($_DB_DATAOBJECT['CONFIG']['class_location'], preg_replace('/[^A-Z0-9]/i','_',ucfirst($table))); |
} else { |
$file = $_DB_DATAOBJECT['CONFIG']['class_location'].'/'.preg_replace('/[^A-Z0-9]/i','_',ucfirst($table)).".php"; |
} |
if (!file_exists($file)) { |
$found = false; |
foreach(explode(PATH_SEPARATOR, ini_get('include_path')) as $p) { |
if (file_exists("$p/$file")) { |
$file = "$p/$file"; |
$found = true; |
break; |
} |
} |
if (!$found) { |
DB_DataObject::raiseError( |
"autoload:Could not find class {$class} using class_location value", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
} |
include_once $file; |
if (!class_exists($class)) { |
DB_DataObject::raiseError( |
"autoload:Could not autoload {$class}", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
return $class; |
} |
/** |
* Have the links been loaded? |
* if they have it contains a array of those variables. |
* |
* @access private |
* @var boolean | array |
*/ |
var $_link_loaded = false; |
/** |
* Get the links associate array as defined by the links.ini file. |
* |
* |
* Experimental... - |
* Should look a bit like |
* [local_col_name] => "related_tablename:related_col_name" |
* |
* |
* @return array|null |
* array = if there are links defined for this table. |
* empty array - if there is a links.ini file, but no links on this table |
* null - if no links.ini exists for this database (hence try auto_links). |
* @access public |
* @see DB_DataObject::getLinks(), DB_DataObject::getLink() |
*/ |
function links() |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
$this->_loadConfig(); |
} |
if (isset($_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table])) { |
return $_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table]; |
} |
$this->databaseStructure(); |
// if there is no link data at all on the file! |
// we return null. |
if (!isset($_DB_DATAOBJECT['LINKS'][$this->_database])) { |
return null; |
} |
if (isset($_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table])) { |
return $_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table]; |
} |
return array(); |
} |
/** |
* load related objects |
* |
* There are two ways to use this, one is to set up a <dbname>.links.ini file |
* into a static property named <dbname>.links and specifies the table joins, |
* the other highly dependent on naming columns 'correctly' :) |
* using colname = xxxxx_yyyyyy |
* xxxxxx = related table; (yyyyy = user defined..) |
* looks up table xxxxx, for value id=$this->xxxxx |
* stores it in $this->_xxxxx_yyyyy |
* you can change what object vars the links are stored in by |
* changeing the format parameter |
* |
* |
* @param string format (default _%s) where %s is the table name. |
* @author Tim White <tim@cyface.com> |
* @access public |
* @return boolean , true on success |
*/ |
function getLinks($format = '_%s') |
{ |
// get table will load the options. |
if ($this->_link_loaded) { |
return true; |
} |
$this->_link_loaded = false; |
$cols = $this->table(); |
$links = $this->links(); |
$loaded = array(); |
if ($links) { |
foreach($links as $key => $match) { |
list($table,$link) = explode(':', $match); |
$k = sprintf($format, str_replace('.', '_', $key)); |
// makes sure that '.' is the end of the key; |
if ($p = strpos($key,'.')) { |
$key = substr($key, 0, $p); |
} |
$this->$k = $this->getLink($key, $table, $link); |
if (is_object($this->$k)) { |
$loaded[] = $k; |
} |
} |
$this->_link_loaded = $loaded; |
return true; |
} |
// this is the autonaming stuff.. |
// it sends the column name down to getLink and lets that sort it out.. |
// if there is a links file then it is not used! |
// IT IS DEPRECIATED!!!! - USE |
if (!is_null($links)) { |
return false; |
} |
foreach (array_keys($cols) as $key) { |
if (!($p = strpos($key, '_'))) { |
continue; |
} |
// does the table exist. |
$k =sprintf($format, $key); |
$this->$k = $this->getLink($key); |
if (is_object($this->$k)) { |
$loaded[] = $k; |
} |
} |
$this->_link_loaded = $loaded; |
return true; |
} |
/** |
* return name from related object |
* |
* There are two ways to use this, one is to set up a <dbname>.links.ini file |
* into a static property named <dbname>.links and specifies the table joins, |
* the other is highly dependant on naming columns 'correctly' :) |
* |
* NOTE: the naming convention is depreciated!!! - use links.ini |
* |
* using colname = xxxxx_yyyyyy |
* xxxxxx = related table; (yyyyy = user defined..) |
* looks up table xxxxx, for value id=$this->xxxxx |
* stores it in $this->_xxxxx_yyyyy |
* |
* you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName') |
* |
* |
* @param string $row either row or row.xxxxx |
* @param string $table name of table to look up value in |
* @param string $link name of column in other table to match |
* @author Tim White <tim@cyface.com> |
* @access public |
* @return mixed object on success |
*/ |
function &getLink($row, $table = null, $link = false) |
{ |
// GUESS THE LINKED TABLE.. (if found - recursevly call self) |
if ($table === null) { |
$links = $this->links(); |
if (is_array($links)) { |
if ($links[$row]) { |
list($table,$link) = explode(':', $links[$row]); |
if ($p = strpos($row,".")) { |
$row = substr($row,0,$p); |
} |
return $r = &$this->getLink($row,$table,$link); |
} |
$this->raiseError( |
"getLink: $row is not defined as a link (normally this is ok)", |
DB_DATAOBJECT_ERROR_NODATA); |
return false; // technically a possible error condition? |
} |
// use the old _ method - this shouldnt happen if called via getLinks() |
if (!($p = strpos($row, '_'))) { |
return null; |
} |
$table = substr($row, 0, $p); |
return $r = &$this->getLink($row, $table); |
} |
if (!isset($this->$row)) { |
$this->raiseError("getLink: row not set $row", DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
// check to see if we know anything about this table.. |
$obj = $this->factory($table); |
if (!is_a($obj,'DB_DataObject')) { |
$this->raiseError( |
"getLink:Could not find class for row $row, table $table", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
if ($link) { |
if ($obj->get($link, $this->$row)) { |
return $obj; |
} |
return false; |
} |
if ($obj->get($this->$row)) { |
return $obj; |
} |
return false; |
} |
/** |
* IS THIS SUPPORTED/USED ANYMORE???? |
*return a list of options for a linked table |
* |
* This is highly dependant on naming columns 'correctly' :) |
* using colname = xxxxx_yyyyyy |
* xxxxxx = related table; (yyyyy = user defined..) |
* looks up table xxxxx, for value id=$this->xxxxx |
* stores it in $this->_xxxxx_yyyyy |
* |
* @access public |
* @return array of results (empty array on failure) |
*/ |
function &getLinkArray($row, $table = null) |
{ |
$ret = array(); |
if (!$table) { |
$links = $this->links(); |
if (is_array($links)) { |
if (!isset($links[$row])) { |
// failed.. |
return $ret; |
} |
list($table,$link) = explode(':',$links[$row]); |
} else { |
if (!($p = strpos($row,'_'))) { |
return $ret; |
} |
$table = substr($row,0,$p); |
} |
} |
$c = $this->factory($table); |
if (!is_a($c,'DB_DataObject')) { |
$this->raiseError( |
"getLinkArray:Could not find class for row $row, table $table", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG |
); |
return $ret; |
} |
// if the user defined method list exists - use it... |
if (method_exists($c, 'listFind')) { |
$c->listFind($this->id); |
} else { |
$c->find(); |
} |
while ($c->fetch()) { |
$ret[] = $c; |
} |
return $ret; |
} |
/** |
* The JOIN condition |
* |
* @access private |
* @var string |
*/ |
var $_join = ''; |
/** |
* joinAdd - adds another dataobject to this, building a joined query. |
* |
* example (requires links.ini to be set up correctly) |
* // get all the images for product 24 |
* $i = new DataObject_Image(); |
* $pi = new DataObjects_Product_image(); |
* $pi->product_id = 24; // set the product id to 24 |
* $i->joinAdd($pi); // add the product_image connectoin |
* $i->find(); |
* while ($i->fetch()) { |
* // do stuff |
* } |
* // an example with 2 joins |
* // get all the images linked with products or productgroups |
* $i = new DataObject_Image(); |
* $pi = new DataObject_Product_image(); |
* $pgi = new DataObject_Productgroup_image(); |
* $i->joinAdd($pi); |
* $i->joinAdd($pgi); |
* $i->find(); |
* while ($i->fetch()) { |
* // do stuff |
* } |
* |
* |
* @param optional $obj object |array the joining object (no value resets the join) |
* If you use an array here it should be in the format: |
* array('local_column','remotetable:remote_column'); |
* if remotetable does not have a definition, you should |
* use @ to hide the include error message.. |
* |
* |
* @param optional $joinType string 'LEFT'|'INNER'|'RIGHT'|'' Inner is default, '' indicates |
* just select ... from a,b,c with no join and |
* links are added as where items. |
* |
* @param optional $joinAs string if you want to select the table as anther name |
* useful when you want to select multiple columsn |
* from a secondary table. |
* @param optional $joinCol string The column on This objects table to match (needed |
* if this table links to the child object in |
* multiple places eg. |
* user->friend (is a link to another user) |
* user->mother (is a link to another user..) |
* |
* @return none |
* @access public |
* @author Stijn de Reede <sjr@gmx.co.uk> |
*/ |
function joinAdd($obj = false, $joinType='INNER', $joinAs=false, $joinCol=false) |
{ |
global $_DB_DATAOBJECT; |
if ($obj === false) { |
$this->_join = ''; |
return; |
} |
// support for array as first argument |
// this assumes that you dont have a links.ini for the specified table. |
// and it doesnt exist as am extended dataobject!! - experimental. |
$ofield = false; // object field |
$tfield = false; // this field |
$toTable = false; |
if (is_array($obj)) { |
$tfield = $obj[0]; |
list($toTable,$ofield) = explode(':',$obj[1]); |
$obj = DB_DataObject::factory($toTable); |
if (!$obj || is_a($obj,'PEAR_Error')) { |
$obj = new DB_DataObject; |
$obj->__table = $toTable; |
} |
$obj->_connect(); |
// set the table items to nothing.. - eg. do not try and match |
// things in the child table...??? |
$items = array(); |
} |
if (!is_object($obj)) { |
$this->raiseError("joinAdd: called without an object", DB_DATAOBJECT_ERROR_NODATA,PEAR_ERROR_DIE); |
} |
/* make sure $this->_database is set. */ |
$this->_connect(); |
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
/* look up the links for obj table */ |
//print_r($obj->links()); |
if (!$ofield && ($olinks = $obj->links())) { |
foreach ($olinks as $k => $v) { |
/* link contains {this column} = {linked table}:{linked column} */ |
$ar = explode(':', $v); |
if ($ar[0] == $this->__table) { |
// you have explictly specified the column |
// and the col is listed here.. |
// not sure if 1:1 table could cause probs here.. |
if ($joinCol !== false) { |
$this->raiseError( |
"joinAdd: You cannot target a join column in the " . |
"'link from' table ({$obj->__table}). " . |
"Either remove the fourth argument to joinAdd() ". |
"({$joinCol}), or alter your links.ini file.", |
DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
$ofield = $k; |
$tfield = $ar[1]; |
break; |
} |
} |
} |
/* otherwise see if there are any links from this table to the obj. */ |
//print_r($this->links()); |
if (($ofield === false) && ($links = $this->links())) { |
foreach ($links as $k => $v) { |
/* link contains {this column} = {linked table}:{linked column} */ |
$ar = explode(':', $v); |
if ($ar[0] == $obj->__table) { |
if ($joinCol !== false) { |
if ($k == $joinCol) { |
$tfield = $k; |
$ofield = $ar[1]; |
break; |
} else { |
continue; |
} |
} else { |
$tfield = $k; |
$ofield = $ar[1]; |
break; |
} |
} |
} |
} |
/* did I find a conneciton between them? */ |
if ($ofield === false) { |
$this->raiseError( |
"joinAdd: {$obj->__table} has no link with {$this->__table}", |
DB_DATAOBJECT_ERROR_NODATA); |
return false; |
} |
$joinType = strtoupper($joinType); |
// we default to joining as the same name (this is remvoed later..) |
if ($joinAs === false) { |
$joinAs = $obj->__table; |
} |
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); |
// not sure how portable adding database prefixes is.. |
$objTable = $quoteIdentifiers ? |
$DB->quoteIdentifier($obj->__table) : |
$obj->__table ; |
// as far as we know only mysql supports database prefixes.. |
if ( |
in_array($DB->dsn['phptype'],array('mysql','mysqli')) && |
($obj->_database != $this->_database) && |
strlen($obj->_database) |
) |
{ |
// prefix database (quoted if neccessary..) |
$objTable = ($quoteIdentifiers |
? $DB->quoteIdentifier($obj->_database) |
: $obj->_database) |
. '.' . $objTable; |
} |
// nested (join of joined objects..) |
$appendJoin = ''; |
if ($obj->_join) { |
// postgres allows nested queries, with ()'s |
// not sure what the results are with other databases.. |
// may be unpredictable.. |
if (in_array($DB->dsn["phptype"],array('pgsql'))) { |
$objTable = "($objTable {$obj->_join})"; |
} else { |
$appendJoin = $obj->_join; |
} |
} |
$table = $this->__table; |
if ($quoteIdentifiers) { |
$joinAs = $DB->quoteIdentifier($joinAs); |
$table = $DB->quoteIdentifier($table); |
$ofield = $DB->quoteIdentifier($ofield); |
$tfield = $DB->quoteIdentifier($tfield); |
} |
// add database prefix if they are different databases |
$fullJoinAs = ''; |
$addJoinAs = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->__table) : $obj->__table) != $joinAs; |
if ($addJoinAs) { |
$fullJoinAs = "AS {$joinAs}"; |
} else { |
// if |
if ( |
in_array($DB->dsn['phptype'],array('mysql','mysqli')) && |
($obj->_database != $this->_database) && |
strlen($this->_database) |
) |
{ |
$joinAs = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->_database) : $obj->_database) . '.' . $joinAs; |
} |
} |
switch ($joinType) { |
case 'INNER': |
case 'LEFT': |
case 'RIGHT': // others??? .. cross, left outer, right outer, natural..? |
$this->_join .= "\n {$joinType} JOIN {$objTable} {$fullJoinAs}". |
" ON {$joinAs}.{$ofield}={$table}.{$tfield} {$appendJoin} "; |
break; |
case '': // this is just a standard multitable select.. |
$this->_join .= "\n , {$objTable} {$fullJoinAs} {$appendJoin}"; |
$this->whereAdd("{$joinAs}.{$ofield}={$table}.{$tfield}"); |
} |
// if obj only a dataobject - eg. no extended class has been defined.. |
// it obvioulsy cant work out what child elements might exist... |
// untill we get on the fly querying of tables.. |
if ( strtolower(get_class($obj)) == 'db_dataobject') { |
return true; |
} |
/* now add where conditions for anything that is set in the object */ |
$items = $obj->table(); |
// will return an array if no items.. |
// only fail if we where expecting it to work (eg. not joined on a array) |
if (!$items) { |
$this->raiseError( |
"joinAdd: No table definition for {$obj->__table}", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return false; |
} |
foreach($items as $k => $v) { |
if (!isset($obj->$k)) { |
continue; |
} |
$kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k); |
if ($v & DB_DATAOBJECT_STR) { |
$this->whereAdd("{$joinAs}.{$kSql} = " . $this->_quote((string) ( |
($v & DB_DATAOBJECT_BOOL) ? |
// this is thanks to the braindead idea of postgres to |
// use t/f for boolean. |
(($obj->$k == 'f') ? 0 : (int)(bool) $obj->$k) : |
$obj->$k |
))); |
continue; |
} |
if (is_numeric($obj->$k)) { |
$this->whereAdd("{$joinAs}.{$kSql} = {$obj->$k}"); |
continue; |
} |
/* this is probably an error condition! */ |
$this->whereAdd("{$joinAs}.{$kSql} = 0"); |
} |
if (!isset($this->_query)) { |
$this->raiseError( |
"joinAdd can not be run from a object that has had a query run on it, |
clone the object or create a new one and use setFrom()", |
DB_DATAOBJECT_ERROR_INVALIDARGS); |
return false; |
} |
// and finally merge the whereAdd from the child.. |
if (!$obj->_query['condition']) { |
return true; |
} |
$cond = preg_replace('/^\sWHERE/i','',$obj->_query['condition']); |
$this->whereAdd("($cond)"); |
return true; |
} |
/** |
* Copies items that are in the table definitions from an |
* array or object into the current object |
* will not override key values. |
* |
* |
* @param array | object $from |
* @param string $format eg. map xxxx_name to $object->name using 'xxxx_%s' (defaults to %s - eg. name -> $object->name |
* @access public |
* @return true on success or array of key=>setValue error message |
*/ |
function setFrom(&$from, $format = '%s', $checkEmpty=false) |
{ |
global $_DB_DATAOBJECT; |
$keys = $this->keys(); |
$items = $this->table(); |
if (!$items) { |
$this->raiseError( |
"setFrom:Could not find table definition for {$this->__table}", |
DB_DATAOBJECT_ERROR_INVALIDCONFIG); |
return; |
} |
$overload_return = array(); |
foreach (array_keys($items) as $k) { |
if (in_array($k,$keys)) { |
continue; // dont overwrite keys |
} |
if (!$k) { |
continue; // ignore empty keys!!! what |
} |
if (is_object($from) && isset($from->{sprintf($format,$k)})) { |
$kk = (strtolower($k) == 'from') ? '_from' : $k; |
if (method_exists($this,'set'.$kk)) { |
$ret = $this->{'set'.$kk}($from->{sprintf($format,$k)}); |
if (is_string($ret)) { |
$overload_return[$k] = $ret; |
} |
continue; |
} |
$this->$k = $from->{sprintf($format,$k)}; |
continue; |
} |
if (is_object($from)) { |
continue; |
} |
if (!isset($from[sprintf($format,$k)])) { |
continue; |
} |
$kk = (strtolower($k) == 'from') ? '_from' : $k; |
if (method_exists($this,'set'. $kk)) { |
$ret = $this->{'set'.$kk}($from[sprintf($format,$k)]); |
if (is_string($ret)) { |
$overload_return[$k] = $ret; |
} |
continue; |
} |
if (is_object($from[sprintf($format,$k)])) { |
continue; |
} |
if (is_array($from[sprintf($format,$k)])) { |
continue; |
} |
$ret = $this->fromValue($k,$from[sprintf($format,$k)]); |
if ($ret !== true) { |
$overload_return[$k] = 'Not A Valid Value'; |
} |
//$this->$k = $from[sprintf($format,$k)]; |
} |
if ($overload_return) { |
return $overload_return; |
} |
return true; |
} |
/** |
* Returns an associative array from the current data |
* (kind of oblivates the idea behind DataObjects, but |
* is usefull if you use it with things like QuickForms. |
* |
* you can use the format to return things like user[key] |
* by sending it $object->toArray('user[%s]') |
* |
* will also return links converted to arrays. |
* |
* @param string sprintf format for array |
* @param bool empty only return elemnts that have a value set. |
* |
* @access public |
* @return array of key => value for row |
*/ |
function toArray($format = '%s', $hideEmpty = false) |
{ |
global $_DB_DATAOBJECT; |
$ret = array(); |
$ar = isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]) ? |
array_merge($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid],$this->table()) : |
$this->table(); |
foreach($ar as $k=>$v) { |
if (!isset($this->$k)) { |
if (!$hideEmpty) { |
$ret[sprintf($format,$k)] = ''; |
} |
continue; |
} |
// call the overloaded getXXXX() method. - except getLink and getLinks |
if (method_exists($this,'get'.$k) && !in_array(strtolower($k),array('links','link'))) { |
$ret[sprintf($format,$k)] = $this->{'get'.$k}(); |
continue; |
} |
// should this call toValue() ??? |
$ret[sprintf($format,$k)] = $this->$k; |
} |
if (!$this->_link_loaded) { |
return $ret; |
} |
foreach($this->_link_loaded as $k) { |
$ret[sprintf($format,$k)] = $this->$k->toArray(); |
} |
return $ret; |
} |
/** |
* validate - override this to set up your validation rules |
* |
* validate the current objects values either just testing strings/numbers or |
* using the user defined validate{Row name}() methods. |
* will attempt to call $this->validate{column_name}() - expects true = ok false = ERROR |
* you can the use the validate Class from your own methods. |
* |
* This should really be in a extenal class - eg. DB_DataObject_Validate. |
* |
* @access public |
* @return array of validation results or true |
*/ |
function validate() |
{ |
require_once 'Validate.php'; |
$table = $this->table(); |
$ret = array(); |
$seq = $this->sequenceKey(); |
foreach($table as $key => $val) { |
// call user defined validation always... |
$method = "Validate" . ucfirst($key); |
if (method_exists($this, $method)) { |
$ret[$key] = $this->$method(); |
continue; |
} |
// if not null - and it's not set....... |
if (!isset($this->$key) && ($val & DB_DATAOBJECT_NOTNULL)) { |
// dont check empty sequence key values.. |
if (($key == $seq[0]) && ($seq[1] == true)) { |
continue; |
} |
$ret[$key] = false; |
continue; |
} |
if (is_string($this->$key) && (strtolower($this->$key) == 'null') && ($val & DB_DATAOBJECT_NOTNULL)) { |
$ret[$key] = false; |
continue; |
} |
// ignore things that are not set. ? |
if (!isset($this->$key)) { |
continue; |
} |
// if the string is empty.. assume it is ok.. |
if (!is_object($this->$key) && !is_array($this->$key) && !strlen((string) $this->$key)) { |
continue; |
} |
switch (true) { |
// todo: date time..... |
case ($val & DB_DATAOBJECT_STR): |
$ret[$key] = Validate::string($this->$key, VALIDATE_PUNCTUATION . VALIDATE_NAME); |
continue; |
case ($val & DB_DATAOBJECT_INT): |
$ret[$key] = Validate::number($this->$key, array('decimal'=>'.')); |
continue; |
} |
} |
foreach ($ret as $key => $val) { |
if ($val === false) { |
return $ret; |
} |
} |
return true; // everything is OK. |
} |
/** |
* Gets the DB object related to an object - so you can use funky peardb stuf with it :) |
* |
* @access public |
* @return object The DB connection |
*/ |
function &getDatabaseConnection() |
{ |
global $_DB_DATAOBJECT; |
if (($e = $this->_connect()) !== true) { |
return $e; |
} |
if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
return false; |
} |
return $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]; |
} |
/** |
* Gets the DB result object related to the objects active query |
* - so you can use funky pear stuff with it - like pager for example.. :) |
* |
* @access public |
* @return object The DB result object |
*/ |
function &getDatabaseResult() |
{ |
global $_DB_DATAOBJECT; |
$this->_connect(); |
if (!isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) { |
return false; |
} |
return $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]; |
} |
/** |
* Overload Extension support |
* - enables setCOLNAME/getCOLNAME |
* if you define a set/get method for the item it will be called. |
* otherwise it will just return/set the value. |
* NOTE this currently means that a few Names are NO-NO's |
* eg. links,link,linksarray, from, Databaseconnection,databaseresult |
* |
* note |
* - set is automatically called by setFrom. |
* - get is automatically called by toArray() |
* |
* setters return true on success. = strings on failure |
* getters return the value! |
* |
* this fires off trigger_error - if any problems.. pear_error, |
* has problems with 4.3.2RC2 here |
* |
* @access public |
* @return true? |
* @see overload |
*/ |
function _call($method,$params,&$return) { |
//$this->debug("ATTEMPTING OVERLOAD? $method"); |
// ignore constructors : - mm |
if (strtolower($method) == strtolower(get_class($this))) { |
return true; |
} |
$type = strtolower(substr($method,0,3)); |
$class = get_class($this); |
if (($type != 'set') && ($type != 'get')) { |
return false; |
} |
// deal with naming conflick of setFrom = this is messy ATM! |
if (strtolower($method) == 'set_from') { |
$return = $this->toValue('from',isset($params[0]) ? $params[0] : null); |
return true; |
} |
$element = substr($method,3); |
// dont you just love php's case insensitivity!!!! |
$array = array_keys(get_class_vars($class)); |
/* php5 version which segfaults on 5.0.3 */ |
if (class_exists('ReflectionClass')) { |
$reflection = new ReflectionClass($class); |
$array = array_keys($reflection->getdefaultProperties()); |
} |
if (!in_array($element,$array)) { |
// munge case |
foreach($array as $k) { |
$case[strtolower($k)] = $k; |
} |
if ((substr(phpversion(),0,1) == 5) && isset($case[strtolower($element)])) { |
trigger_error("PHP5 set/get calls should match the case of the variable",E_USER_WARNING); |
$element = strtolower($element); |
} |
// does it really exist? |
if (!isset($case[$element])) { |
return false; |
} |
// use the mundged case |
$element = $case[$element]; // real case ! |
} |
if ($type == 'get') { |
$return = $this->toValue($element,isset($params[0]) ? $params[0] : null); |
return true; |
} |
$return = $this->fromValue($element, $params[0]); |
return true; |
} |
/** |
* standard set* implementation. |
* |
* takes data and uses it to set dates/strings etc. |
* normally called from __call.. |
* |
* Current supports |
* date = using (standard time format, or unixtimestamp).... so you could create a method : |
* function setLastread($string) { $this->fromValue('lastread',strtotime($string)); } |
* |
* time = using strtotime |
* datetime = using same as date - accepts iso standard or unixtimestamp. |
* string = typecast only.. |
* |
* TODO: add formater:: eg. d/m/Y for date! ??? |
* |
* @param string column of database |
* @param mixed value to assign |
* |
* @return true| false (False on error) |
* @access public |
* @see DB_DataObject::_call |
*/ |
function fromValue($col,$value) |
{ |
$cols = $this->table(); |
// dont know anything about this col.. |
if (!isset($cols[$col])) { |
$this->$col = $value; |
return true; |
} |
//echo "FROM VALUE $col, {$cols[$col]}, $value\n"; |
switch (true) { |
// set to null and column is can be null... |
case ((strtolower($value) == 'null') && (!($cols[$col] & DB_DATAOBJECT_NOTNULL))): |
case (is_object($value) && is_a($value,'DB_DataObject_Cast')): |
$this->$col = $value; |
return true; |
// fail on setting null on a not null field.. |
case ((strtolower($value) == 'null') && ($cols[$col] & DB_DATAOBJECT_NOTNULL)): |
return false; |
case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)): |
// empty values get set to '' (which is inserted/updated as NULl |
if (!$value) { |
$this->$col = ''; |
} |
if (is_numeric($value)) { |
$this->$col = date('Y-m-d H:i:s', $value); |
return true; |
} |
// eak... - no way to validate date time otherwise... |
$this->$col = (string) $value; |
return true; |
case ($cols[$col] & DB_DATAOBJECT_DATE): |
// empty values get set to '' (which is inserted/updated as NULl |
if (!$value) { |
$this->$col = ''; |
return true; |
} |
if (is_numeric($value)) { |
$this->$col = date('Y-m-d',$value); |
return true; |
} |
// try date!!!! |
require_once 'Date.php'; |
$x = new Date($value); |
$this->$col = $x->format("%Y-%m-%d"); |
return true; |
case ($cols[$col] & DB_DATAOBJECT_TIME): |
// empty values get set to '' (which is inserted/updated as NULl |
if (!$value) { |
$this->$col = ''; |
} |
$guess = strtotime($value); |
if ($guess != -1) { |
$this->$col = date('H:i:s', $guess); |
return $return = true; |
} |
// otherwise an error in type... |
return false; |
case ($cols[$col] & DB_DATAOBJECT_STR): |
$this->$col = (string) $value; |
return true; |
// todo : floats numerics and ints... |
default: |
$this->$col = $value; |
return true; |
} |
} |
/** |
* standard get* implementation. |
* |
* with formaters.. |
* supported formaters: |
* date/time : %d/%m/%Y (eg. php strftime) or pear::Date |
* numbers : %02d (eg. sprintf) |
* NOTE you will get unexpected results with times like 0000-00-00 !!! |
* |
* |
* |
* @param string column of database |
* @param format foramt |
* |
* @return true Description |
* @access public |
* @see DB_DataObject::_call(),strftime(),Date::format() |
*/ |
function toValue($col,$format = null) |
{ |
if (is_null($format)) { |
return $this->$col; |
} |
$cols = $this->table(); |
switch (true) { |
case (($cols[$col] & DB_DATAOBJECT_DATE) && ($cols[$col] & DB_DATAOBJECT_TIME)): |
if (!$this->$col) { |
return ''; |
} |
$guess = strtotime($this->$col); |
if ($guess != -1) { |
return strftime($format, $guess); |
} |
// eak... - no way to validate date time otherwise... |
return $this->$col; |
case ($cols[$col] & DB_DATAOBJECT_DATE): |
if (!$this->$col) { |
return ''; |
} |
$guess = strtotime($this->$col); |
if ($guess != -1) { |
return strftime($format,$guess); |
} |
// try date!!!! |
require_once 'Date.php'; |
$x = new Date($this->$col); |
return $x->format($format); |
case ($cols[$col] & DB_DATAOBJECT_TIME): |
if (!$this->$col) { |
return ''; |
} |
$guess = strtotime($this->$col); |
if ($guess > -1) { |
return strftime($format, $guess); |
} |
// otherwise an error in type... |
return $this->$col; |
case ($cols[$col] & DB_DATAOBJECT_MYSQLTIMESTAMP): |
if (!$this->$col) { |
return ''; |
} |
require_once 'Date.php'; |
$x = new Date($this->$col); |
return $x->format($format); |
case ($cols[$col] & DB_DATAOBJECT_BOOLEAN): |
if ($cols[$col] & DB_DATAOBJECT_STR) { |
// it's a 't'/'f' ! |
return ($cols[$col] == 't'); |
} |
return (bool) $cols[$col]; |
default: |
return sprintf($format,$this->col); |
} |
} |
/* ----------------------- Debugger ------------------ */ |
/** |
* Debugger. - use this in your extended classes to output debugging information. |
* |
* Uses DB_DataObject::DebugLevel(x) to turn it on |
* |
* @param string $message - message to output |
* @param string $logtype - bold at start |
* @param string $level - output level |
* @access public |
* @return none |
*/ |
function debug($message, $logtype = 0, $level = 1) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG']['debug']) || |
(is_numeric($_DB_DATAOBJECT['CONFIG']['debug']) && $_DB_DATAOBJECT['CONFIG']['debug'] < $level)) { |
return; |
} |
// this is a bit flaky due to php's wonderfull class passing around crap.. |
// but it's about as good as it gets.. |
$class = (isset($this) && is_a($this,'DB_DataObject')) ? get_class($this) : 'DB_DataObject'; |
if (!is_string($message)) { |
$message = print_r($message,true); |
} |
if (!is_numeric( $_DB_DATAOBJECT['CONFIG']['debug']) && is_callable( $_DB_DATAOBJECT['CONFIG']['debug'])) { |
return call_user_func($_DB_DATAOBJECT['CONFIG']['debug'], $class, $message, $logtype, $level); |
} |
if (!ini_get('html_errors')) { |
echo "$class : $logtype : $message\n"; |
flush(); |
return; |
} |
if (!is_string($message)) { |
$message = print_r($message,true); |
} |
echo "<code><B>$class: $logtype:</B> $message</code><BR>\n"; |
flush(); |
} |
/** |
* sets and returns debug level |
* eg. DB_DataObject::debugLevel(4); |
* |
* @param int $v level |
* @access public |
* @return none |
*/ |
function debugLevel($v = null) |
{ |
global $_DB_DATAOBJECT; |
if (empty($_DB_DATAOBJECT['CONFIG'])) { |
DB_DataObject::_loadConfig(); |
} |
if ($v !== null) { |
$r = isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0; |
$_DB_DATAOBJECT['CONFIG']['debug'] = $v; |
return $r; |
} |
return isset($_DB_DATAOBJECT['CONFIG']['debug']) ? $_DB_DATAOBJECT['CONFIG']['debug'] : 0; |
} |
/** |
* Last Error that has occured |
* - use $this->_lastError or |
* $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); |
* |
* @access public |
* @var object PEAR_Error (or false) |
*/ |
var $_lastError = false; |
/** |
* Default error handling is to create a pear error, but never return it. |
* if you need to handle errors you should look at setting the PEAR_Error callback |
* this is due to the fact it would wreck havoc on the internal methods! |
* |
* @param int $message message |
* @param int $type type |
* @param int $behaviour behaviour (die or continue!); |
* @access public |
* @return error object |
*/ |
function raiseError($message, $type = null, $behaviour = null) |
{ |
global $_DB_DATAOBJECT; |
if ($behaviour == PEAR_ERROR_DIE && !empty($_DB_DATAOBJECT['CONFIG']['dont_die'])) { |
$behaviour = null; |
} |
$error = &PEAR::getStaticProperty('DB_DataObject','lastError'); |
if (PEAR::isError($message)) { |
$error = $message; |
} else { |
require_once 'DB/DataObject/Error.php'; |
$error = PEAR::raiseError($message, $type, $behaviour, |
$opts=null, $userinfo=null, 'DB_DataObject_Error' |
); |
} |
// this will never work totally with PHP's object model. |
// as this is passed on static calls (like staticGet in our case) |
if (isset($this) && is_object($this) && is_subclass_of($this,'db_dataobject')) { |
$this->_lastError = $error; |
} |
$_DB_DATAOBJECT['LASTERROR'] = $error; |
// no checks for production here?....... |
DB_DataObject::debug($message,"ERROR",1); |
return $error; |
} |
/** |
* Define the global $_DB_DATAOBJECT['CONFIG'] as an alias to PEAR::getStaticProperty('DB_DataObject','options'); |
* |
* After Profiling DB_DataObject, I discoved that the debug calls where taking |
* considerable time (well 0.1 ms), so this should stop those calls happening. as |
* all calls to debug are wrapped with direct variable queries rather than actually calling the funciton |
* THIS STILL NEEDS FURTHER INVESTIGATION |
* |
* @access public |
* @return object an error object |
*/ |
function _loadConfig() |
{ |
global $_DB_DATAOBJECT; |
$_DB_DATAOBJECT['CONFIG'] = &PEAR::getStaticProperty('DB_DataObject','options'); |
} |
/** |
* Free global arrays associated with this object. |
* |
* Note: as we now store resultfields in a global, it is never freed, if you do alot of calls to find(), |
* memory will grow gradually. |
* |
* |
* @access public |
* @return none |
*/ |
function free() |
{ |
global $_DB_DATAOBJECT; |
if (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) { |
unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]); |
} |
if (isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) { |
unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]); |
} |
// this is a huge bug in DB! |
if (isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) { |
$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->num_rows = array(); |
} |
} |
/* ---- LEGACY BC METHODS - NOT DOCUMENTED - See Documentation on New Methods. ---*/ |
function _get_table() { return $this->table(); } |
function _get_keys() { return $this->keys(); } |
} |
// technially 4.3.2RC1 was broken!! |
// looks like 4.3.3 may have problems too.... |
if (!defined('DB_DATAOBJECT_NO_OVERLOAD')) { |
if ((phpversion() != '4.3.2-RC1') && (version_compare( phpversion(), "4.3.1") > 0)) { |
if (version_compare( phpversion(), "5") < 0) { |
overload('DB_DataObject'); |
} |
$GLOBALS['_DB_DATAOBJECT']['OVERLOADED'] = true; |
} |
} |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's sqlite extension |
* for interacting with SQLite databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* NOTICE: This driver needs PHP's track_errors ini setting to be on. |
* It is automatically turned on when connecting to the database. |
* Make sure your scripts don't turn it off. |
* |
* @category Database |
* @package DB |
* @author Urs Gehrig <urs@circle.ch> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/QueryTool.php |
---|
New file |
0,0 → 1,63 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool 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_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: QueryTool.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* require the DB_QueryTool_EasyJoin class |
*/ |
require_once 'DB/QueryTool/EasyJoin.php'; |
/** |
* MDB_QueryTool class |
* |
* This class should be extended; it's here to make it easy using the base |
* class of the package by its package name. |
* Since I tried to seperate the functionality a bit inside the |
* really working classes i decided to have this class here just to |
* provide the name, since the functionality inside the other |
* classes might be restructured a bit but this name always stays. |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool extends DB_QueryTool_EasyJoin |
{ |
// {{{ DB_QueryTool() |
/** |
* call parent constructor |
* @param mixed $dsn DSN string, DSN array or DB object |
* @param array $options |
*/ |
function DB_QueryTool($dsn=false, $options=array()) |
{ |
parent::__construct($dsn, $options); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB class so it can be extended from |
*/ |
require_once 'DB.php'; |
/** |
* Provides an object interface to a table row |
* |
* It lets you add, delete and change rows using objects rather than SQL |
* statements. |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <stig@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's odbc extension |
* for interacting with databases via ODBC connections |
* |
* These methods overload the ones declared in DB_common. |
* |
* More info on ODBC errors could be found here: |
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's fbsql extension |
* for interacting with FrontBase databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Frank M. Kromann <frank@frontbase.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/Output.php |
---|
New file |
0,0 → 1,211 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_Output | |
// +----------------------------------------------------------------------+ |
// | 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: Daniel Khan <dk@webcluster.at> | |
// | Jason Rust <jason@rustyparts.com> | |
// +----------------------------------------------------------------------+ |
// $Id: Output.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
require_once 'PEAR.php'; |
// {{{ constants |
define('NESEO_ERROR_NO_METHOD', 'E1000'); |
define('NESEO_DRIVER_NOT_FOUND', 'E1100'); |
define('NESEO_ERROR_NO_OPTIONS', 'E2100'); |
// }}} |
// {{{ DB_NestedSet_Output:: class |
/** |
* DB_NestedSet_Output is a unified API for other output drivers |
* Status is beta |
* |
* At the moment PEAR::HTML_TreeMenu written by Jason Rust is supported |
* A driver for treemenu.org will follow soon. |
* |
* Usage example: |
* |
* require_once('DB_NestedSet/NestedSet/Output.php'); |
* $icon = 'folder.gif'; |
* $expandedIcon = 'folder-expanded.gif'; |
* // get data (important to fetch it as an array, using the true flag) |
* $data = $NeSe->getAllNodes(true); |
* // change the events for one of the elements |
* $data[35]['events'] = array('onexpand' => 'alert("we expanded!");'); |
* // add links to each item |
* foreach ($data as $a_data) { |
* $a_data['link'] = 'http://foo.com/foo.php?' . $a_data['id']; |
* } |
* $params = array( |
* 'structure' => $data, |
* 'options' => array( |
* 'icon' => $icon, |
* 'expandedIcon' => $expandedIcon, |
* ), |
* 'textField' => 'name', |
* 'linkField' => 'link', |
* ); |
* $menu =& DB_NestedSet_Output::factory('TreeMenu', $params); |
* $menu->printListbox(); |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
* |
*/ |
// }}} |
class DB_NestedSet_Output { |
// {{{ properties |
/** |
* @var object The tree menu structure |
* @access private |
*/ |
var $_structTreeMenu = false; |
/** |
* @var array Array of options to be passed to the ouput methods |
* @access public |
*/ |
var $options = array(); |
// }}} |
// {{{ factory() |
/** |
* Returns a output driver object |
* |
* @param array $params A DB_NestedSet nodeset |
* @param string $driver (optional) The driver, such as TreeMenu (default) |
* |
* @access public |
* @return object The DB_NestedSet_Ouput object |
*/ |
function &factory ($params, $driver = 'TreeMenu') { |
$path = dirname(__FILE__).'/'.$driver.'.php'; |
if(is_dir($path) || !file_exists($path)) { |
PEAR::raiseError("The output driver '$driver' wasn't found", NESEO_DRIVER_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
require_once($path); |
$driverClass = 'DB_NestedSet_'.$driver; |
return new $driverClass($params); |
} |
// }}} |
// {{{ setOptions() |
/** |
* Set's options for a specific output group (printTree, printListbox) |
* This enables you to set specific options for each output method |
* |
* @param string $group Output group ATM 'printTree' or 'printListbox' |
* @param array $options Hash with options |
* |
* @access public |
* @return bool |
*/ |
function setOptions($group, $options) { |
$this->options[$group] = $options; |
return true; |
} |
// }}} |
// {{{ _getOptions() |
/** |
* Get's all option for a specific output group (printTree, printListbox) |
* |
* @param string $group Output group ATM 'printTree' or 'printListbox' |
* |
* @access private |
* @return array Options |
*/ |
function _getOptions($group) { |
if (!isset($this->options[$group])) { |
return array(); |
} |
return $this->options[$group]; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* Overriden by the driver class |
* |
* @access public |
*/ |
function printTree() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ printListbox() |
/** |
* Print's a listbox representing the current tree |
* Overriden by the driver class |
* |
* @access public |
*/ |
function printListbox() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ toHTML() |
/** |
* Returns the HTML for the DHTML-menu. This method can be |
* used instead of printMenu() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the menu |
* @author Emanuel Zueger |
*/ |
function tree_toHTML() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ listbox_toHTML() |
/** |
* Returns the HTML for the listbox. This method can be |
* used instead of printListbox() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the listbox |
* @author Emanuel Zueger |
*/ |
function listbox_toHTML() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/Event.php |
---|
New file |
0,0 → 1,79 |
<?php |
/** |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_DB | |
// +----------------------------------------------------------------------+ |
// | 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: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: Event.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
// |
*/ |
/** |
* Poor mans event handler for DB_NestedSet |
* |
* Mostly for demo purposes or for extending it if |
* someone has ideas... |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
Class DB_NestedSetEvent extends PEAR { |
/** |
* Constructor |
* |
* @return void |
*/ |
function DB_NestedSetEvent() { |
$this->PEAR(); |
} |
/** |
* Destructor |
* |
* @return void |
*/ |
function _DB_NestedSetEvent() { |
$this->_PEAR(); |
} |
/** |
* Calls the event handler |
* |
* You may want to do a switch() here and call you methods |
* depending on the event |
* |
* @param string $event The Event that occured |
* @param object node $node A Reference to the node object which was subject to changes |
* @param array $eparams A associative array of params which may be needed by the handler |
* @return void |
* @access private |
*/ |
function callEvent($event, &$node, $eparams = array()) { |
echo "<br>Override callEvent() if you want to have custom event handlers<br>\n"; |
echo "Event $event was called with the following params:<br><br>\n"; |
echo "<PRE>"; |
print_r($eparams); |
echo "</PRE><br>\n"; |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/MDB.php |
---|
New file |
0,0 → 1,136 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_MDB | |
// +----------------------------------------------------------------------+ |
// | 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: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// Thanks to Hans Lellelid for suggesting support for PEAR::MDB |
// and for his help in implementing this. |
// |
// $Id: MDB.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
require_once 'MDB.php'; |
// {{{ DB_NestedSet_MDB:: class |
/** |
* Wrapper class for PEAR::MDB |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_MDB extends DB_NestedSet { |
// {{{ properties |
/** |
* @var object The MDB object |
*/ |
var $db; |
// }}} |
// {{{ constructor |
/** |
* Constructor |
* |
* @param mixed $dsn DSN as PEAR dsn URI or dsn Array |
* @param array $params Database column fields which should be returned |
* |
*/ |
function DB_NestedSet_MDB($dsn, $params = array()) |
{ |
$this->_debugMessage('DB_NestedSet_MDB($dsn, $params = array())'); |
$this->DB_NestedSet($params); |
$this->db =& $this->_db_Connect($dsn); |
$this->db->setFetchMode(MDB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ destructor |
/** |
* Destructor |
*/ |
function _DB_NestedSet_MDB() |
{ |
$this->_debugMessage('_DB_NestedSet_MDB()'); |
$this->_DB_NestedSet(); |
$this->_db_Disconnect(); |
} |
// }}} |
// {{{ _db_Connect() |
/** |
* Connects to the db |
* |
* @return object DB The database object |
* @access private |
*/ |
function &_db_Connect($dsn) |
{ |
$this->_debugMessage('_db_Connect($dsn)'); |
if (is_object($this->db)) { |
return $this->db; |
} |
$db =& MDB::connect($dsn); |
$this->_testFatalAbort($db, __FILE__, __LINE__); |
return $db; |
} |
// }}} |
function _isDBError($err) { |
if(!MDB::isError($err)) { |
return false; |
} |
return true; |
} |
function _numRows($res) { |
return $this->db->numRows($res); |
} |
function _quote($str) { |
return $this->db->getTextValue($str); |
} |
// {{{ _db_Disconnect() |
/** |
* Disconnects from db |
* |
* @return void |
* @access private |
*/ |
function _db_Disconnect() |
{ |
$this->_debugMessage('_db_Disconnect()'); |
if (is_object($this->db)) { |
@$this->db->disconnect(); |
} |
return true; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/TreeMenu.php |
---|
New file |
0,0 → 1,205 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_TreeMenu | |
// +----------------------------------------------------------------------+ |
// | 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: TreeMenu.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
require_once 'HTML/TreeMenu.php'; |
// {{{ DB_NestedSet_TreeMenu:: class |
/** |
* A helper class to translate the data from a nested set table into a HTML_TreeMenu object |
* so that it can be used to create a dynamic tree menu using the PEAR HTML_TreeMenu class. |
* |
* @see docs/TreeMenu_example.php |
* @author Jason Rust <jrust@rustyparts.com> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_TreeMenu extends DB_NestedSet_Output { |
// {{{ properties |
/** |
* @var array The current menu structure |
* @access private |
*/ |
var $_structTreeMenu = false; |
// }}} |
// {{{ DB_NestedSet_TreeMenu |
function &DB_NestedSet_TreeMenu($params) { |
$this->_structTreeMenu =& $this->_createFromStructure($params); |
} |
// }}} |
// {{{ _createFromStructure() |
/** |
* <pre>Creates a HTML_TreeMenu structure based off of the results from getAllNodes() method |
* of the DB_NestedSet class. The needed parameters are: |
* o 'structure' => the result from $nestedSet->getAllNodes(true) |
* o 'textField' => the field in the table that has the text for node |
* o 'linkField' => the field in the table that has the link for the node |
* o 'options' => (optional) an array of any additional options to pass to the node when |
* Additionally these parameters may be added to the individual nodes to control their |
* behavior: |
* o 'ensureVisible' => (optional) whether or not the field should be forced as visible |
* creating it such as 'icon' or 'expandedIcon' |
* o 'events' => (optional) an array of any events to pass to the node when creating it |
* such as 'onclick' or 'onexpand'</pre> |
* </pre> |
* @access public |
* @return object A HTML_TreeMenu object |
*/ |
function &_createFromStructure($params) |
{ |
// Basically we go through the array of nodes checking to see |
// if each node has children and if so recursing. The reason this |
// works is because the data from getAllNodes() is ordered by level |
// so a root node will always be first, and sub children will always |
// be after them. |
if (!isset($params['treeMenu'])) { |
$treeMenu =& new HTML_TreeMenu(); |
} else { |
$treeMenu =& $params['treeMenu']; |
} |
// always start at level 1 |
if (!isset($params['currentLevel'])) { |
$params['currentLevel'] = 1; |
} |
// have to use a while loop here because foreach works on a copy of the array and |
// the child nodes are passed by reference during the recursion so that the parent |
// will know when they have been hit. |
reset($params['structure']); |
while(list($key, $node) = each($params['structure'])) { |
// see if we've already been here before |
if (isset($node['hit'])) { |
continue; |
} |
// mark that we've hit this node |
$params['structure'][$key]['hit'] = $node['hit'] = true; |
$tag = array( |
'text' => $node[$params['textField']], |
'link' => $node[$params['linkField']], |
'ensureVisible' => isset($node['ensureVisible']) ? $node['ensureVisible'] : false, |
); |
$options = isset($params['options']) ? array_merge($params['options'], $tag) : $tag; |
$events = isset($node['events']) ? $node['events'] : array(); |
$parentNode =& $treeMenu->addItem(new HTML_TreeNode($options, $events)); |
// see if it has children |
if (($node['r'] - 1) != $node['l']) { |
$children = array(); |
// harvest all the children |
$tempStructure = $params['structure']; |
foreach ($tempStructure as $childKey => $childNode) { |
if (!isset($childNode['hit']) && |
$childNode['l'] > $node['l'] && |
$childNode['r'] < $node['r'] && |
$childNode['rootid'] == $node['rootid']) { |
// important that we assign it by reference here, so that when the child |
// marks itself 'hit' the parent loops will know |
$children[] =& $params['structure'][$childKey]; |
} |
} |
$recurseParams = $params; |
$recurseParams['structure'] = $children; |
$recurseParams['treeMenu'] =& $parentNode; |
$recurseParams['currentLevel']++; |
$this->_createFromStructure($recurseParams); |
} |
} |
return $treeMenu; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* |
* @access public |
*/ |
function printTree() { |
$options = $this->_getOptions('printTree'); |
$tree =& new HTML_TreeMenu_DHTML($this->_structTreeMenu, $options); |
$tree->printMenu(); |
} |
// }}} |
// {{{ printListbox() |
/** |
* Print's a listbox representing the current tree |
* |
* @access public |
*/ |
function printListbox() { |
$options = $this->_getOptions('printListbox'); |
$listBox =& new HTML_TreeMenu_Listbox($this->_structTreeMenu, $options); |
$listBox->printMenu(); |
} |
// }}} |
// }}} |
// {{{ tree_toHTML() |
/** |
* Returns the HTML for the DHTML-menu. This method can be |
* used instead of printMenu() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the menu |
* @Author Emanuel Zueger |
*/ |
function tree_toHTML() { |
$options = $this->_getOptions('toHTML'); |
$tree =& new HTML_TreeMenu_DHTML($this->_structTreeMenu, $options); |
return $tree->toHTML(); |
} |
// }}} |
// {{{ listbox_toHTML() |
/** |
* Returns the HTML for the listbox. This method can be |
* used instead of printListbox() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the listbox |
* @author Emanuel Zueger |
*/ |
function listbox_toHTML() { |
$options = $this->_getOptions('toHTML'); |
$listBox =& new HTML_TreeMenu_Listbox($this->_structTreeMenu, $options); |
return $listBox->toHTML(); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/DB.php |
---|
New file |
0,0 → 1,135 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_DB | |
// +----------------------------------------------------------------------+ |
// | 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: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: DB.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
require_once 'DB.php'; |
// {{{ DB_NestedSet_DB:: class |
/** |
* Wrapper class for PEAR::DB |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_DB extends DB_NestedSet { |
// {{{ properties |
/** |
* @var object Db object |
*/ |
var $db; |
// }}} |
// {{{ constructor |
/** |
* Constructor |
* |
* @param mixed $dsn DSN as PEAR dsn URI or dsn Array |
* @param array $params Database column fields which should be returned |
* |
*/ |
function DB_NestedSet_DB($dsn, $params = array()) |
{ |
$this->_debugMessage('DB_NestedSet_DB($dsn, $params = array())'); |
$this->DB_NestedSet($params); |
$this->db =& $this->_db_Connect($dsn); |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ destructor |
/** |
* Destructor |
*/ |
function _DB_NestedSet_DB() |
{ |
$this->_debugMessage('_DB_NestedSet_DB()'); |
$this->_DB_NestedSet(); |
$this->_db_Disconnect(); |
} |
// }}} |
// {{{ _db_Connect() |
/** |
* Connects to the db |
* |
* @return object DB The database object |
* @access private |
*/ |
function &_db_Connect($dsn) |
{ |
$this->_debugMessage('_db_Connect($dsn)'); |
if (is_object($this->db)) { |
return $this->db; |
} |
$db =& DB::connect($dsn); |
$this->_testFatalAbort($db, __FILE__, __LINE__); |
return $db; |
} |
// }}} |
function _numRows($res) { |
return $res->numRows(); |
} |
function _isDBError($err) { |
if(!DB::isError($err)) { |
return false; |
} |
return true; |
} |
function _quote($str) { |
return $this->db->quote($str); |
} |
// {{{ _db_Disconnect() |
/** |
* Disconnects from db |
* |
* @return void |
* @access private |
*/ |
function _db_Disconnect() |
{ |
$this->_debugMessage('_db_Disconnect()'); |
if (is_object($this->db)) { |
@$this->db->disconnect(); |
} |
return true; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/NestedSet/TigraMenu.php |
---|
New file |
0,0 → 1,402 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_TigraMenu | |
// +----------------------------------------------------------------------+ |
// | 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: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: TigraMenu.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
// |
// {{{ DB_NestedSet_TigraMenu:: class |
/** |
* This class can be used to generate the data to build javascript popup menu |
* from a DB_NestedSet node array. |
* The Javascript part is done using the free available TigraMenu |
* available at http://www.softcomplex.com/products/tigra_menu/. |
* Currently version 1.0 is supported. |
* Parts of this class where taken ftom the TreemMenu driver by Jason Rust |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.1 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_TigraMenu extends DB_NestedSet_Output { |
// {{{{ properties |
/** |
* @var integer The depth of the current menu. |
* @access private |
*/ |
var $_levels = 1; |
/** |
* @var integer The level we started at |
* @access private |
*/ |
var $_levelOffset = false; |
/** |
* @var array The current menu structure |
* @access private |
*/ |
var $_structTigraMenu = false; |
/** |
* @var array The longest text for each level |
* @access private |
*/ |
var $_strlenByLevel = array(); |
// }}} |
// {{{ DB_NestedSet_TigraMenu |
/** |
* Constructor |
* |
* @param array $params A hash with parameters needed by the class |
* @see _createFromStructure() |
* @return bool |
**/ |
function &DB_NestedSet_TigraMenu($params) { |
$this->_menu_id = $params['menu_id']; |
$this->_structTigraMenu = $this->_createFromStructure($params); |
return true; |
} |
// }}} |
// {{{ _createFromStructure() |
/** |
* Creates the JavaScript array for TigraMenu |
* Initially this method was introduced for the TreeMenu driver by Jason Rust |
* |
* o 'structure' => the result from $nestedSet->getAllNodes(true) |
* o 'textField' => the field in the table that has the text for node |
* o 'linkField' => the field in the table that has the link for the node |
* |
* @access private |
* @return string The TigraMenu JavaScript array |
*/ |
function &_createFromStructure($params) |
{ |
// Basically we go through the array of nodes checking to see |
// if each node has children and if so recursing. The reason this |
// works is because the data from getAllNodes() is ordered by level |
// so a root node will always be first, and sub children will always |
// be after them. |
static $rootlevel; |
// always start at level 1 |
if (!isset($params['currentLevel'])) { |
$params['currentLevel'] = 1; |
} |
if (!isset($rootlevel)) { |
$rootlevel = $params['currentLevel']; |
} |
if (isset($params['tigraMenu'])) { |
$tigraMenu = $tigraMenu.$params['tigraMenu']; |
} |
if(!$this->_levelOffset) { |
$this->_levelOffset = $params['currentLevel']; |
} |
if($this->_levels < ($params['currentLevel']- $this->_levelOffset)) { |
$this->_levels = $params['currentLevel'] - $this->_levelOffset; |
} |
// have to use a while loop here because foreach works on a copy of the array and |
// the child nodes are passed by reference during the recursion so that the parent |
// will know when they have been hit. |
reset($params['structure']); |
while(list($key, $node) = each($params['structure'])) { |
// see if we've already been here before |
if (isset($node['hit']) || $node['level'] < $params['currentLevel']) { |
continue; |
} |
// mark that we've hit this node |
$params['structure'][$key]['hit'] = $node['hit'] = true; |
$tag = array( |
isset($node[$params['textField']]) ? "'".$node[$params['textField']]."'" : 'null', |
isset($node[$params['linkField']]) ? "'".$node[$params['linkField']]."'" : 'null' |
); |
if (!$this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] || |
strlen($node[$params['textField']]) > $this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset]) { |
$this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] = strlen($node[$params['textField']]); |
}; |
$tigraMenu = $tigraMenu.$this->_openSubMenu($tag); |
// see if it has children |
if (($node['r'] - 1) != $node['l']) { |
$children = array(); |
// harvest all the children |
$tempStructure = $params['structure']; |
foreach ($tempStructure as $childKey => $childNode) { |
if (!isset($childNode['hit']) && |
$node['rootid'] == $childNode['rootid'] && |
$node['l'] < $childNode['l'] && |
$node['r'] > $childNode['r'] && |
$childNode['level'] > $params['currentLevel']) { |
// important that we assign it by reference here, so that when the child |
// marks itself 'hit' the parent loops will know |
$children[] =& $params['structure'][$childKey]; |
} |
} |
$recurseParams = $params; |
$recurseParams['structure'] = $children; |
$recurseParams['currentLevel']++; |
$tigraMenu = $tigraMenu.$this->_createFromStructure($recurseParams); |
} |
$tigraMenu = $tigraMenu.$this->_closeSubMenu(); |
} |
return $tigraMenu; |
} |
// }}} |
// {{{ _openMenu() |
/** |
* Returns the string which opens the JavaScript menu |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @return string The JavaScript piece |
*/ |
function _openMenu($menu_id=1) |
{ |
$str = false; |
$str = $str."var MENU_ITEMS".$menu_id." = new Array();\n"; |
$str = $str."MENU_ITEMS".$menu_id." = [\n"; |
return $str; |
} |
// }}} |
// {{{ _openSubMenu() |
/** |
* Returns the string which opens a submenu within the JavaScript menu |
* |
* @access private |
* @param array $tag Contains the content of the current item (name, link) |
* @return string The JavaScript piece |
*/ |
function _openSubMenu($tag) |
{ |
$rtag = implode(', ', $tag); |
return "\n[".$rtag.','; |
} |
// }}} |
// {{{ _closeMenu() |
/** |
* Closes the JavaScript array |
* |
* @access private |
* @return string The JavaScript piece |
*/ |
function _closeMenu() |
{ |
return '];'; |
} |
// }}} |
// {{{ _closeSubMenu() |
/** |
* Closes the JavaScript array of a submenu |
* |
* @access private |
* @return string The JavaScript piece |
*/ |
function _closeSubMenu() |
{ |
return "\n],"; |
} |
// }}} |
// {{{ _addStyles() |
/** |
* Creates the JavaScript code which sets the styles for each level |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @param array $rootStyles Array of style attributes for the top items |
* @param array $childStyles Array of style attributes for the sub items |
* @return string The JavaScript piece |
*/ |
function _addStyles($menu_id, $rootStyles, $childStyles = false) |
{ |
if (!$childStyles) { |
$childStyles = $rootStyles; |
} |
$styles = array(); |
foreach ($rootStyles as $key => $val) { |
foreach ($val as $skey => $sval) { |
$styles["'$key'"][$skey][] = "'$sval'"; |
} |
} |
foreach ($childStyles as $key => $val) { |
foreach ($val as $skey => $sval) { |
for ($i = 1; $i <= $this->_levels; $i++) { |
$styles["'$key'"][$skey][] = "'$sval'"; |
} |
} |
} |
$menustyles = false; |
$menustyles = $menustyles . 'var MENU_STYLES'.$menu_id." = new Array();\n"; |
foreach ($styles as $key => $val) { |
$menustyles = $menustyles.'MENU_STYLES'.$menu_id."[$key] = [\n"; |
foreach ($val as $skey => $sval) { |
$menustyles = $menustyles . "'$skey', [".implode(', ', $sval)."],\n"; |
} |
$menustyles = $menustyles."];\n"; |
} |
return $menustyles; |
} |
// }}} |
// {{{ _addGeometry() |
/** |
* Creates the JavaScript code which sets the position and geometry of the menu |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @param array $rootGeometry Array of geometry attributes for the top items |
* @param array $childGeometry Array of geometry attributes for the sub items |
* @return string The JavaScript piece |
*/ |
function _addGeometry($menu_id, $rootGeometry, $childGeometry = false) |
{ |
if (!$childGeometry) { |
$childGeometry = $rootGeometry; |
} |
$params = array(); |
$geometry = array(); |
foreach ($rootGeometry as $key => $val) { |
$geometry["'$key'"][] = $val; |
$incr = false; |
if (strpos($val, ',') !== false) { |
list($start, $interval) = explode(',',$val); |
$incr = true; |
} |
$ratio = false; |
if ($key == 'width' && strpos($val, '*') !== false) { |
$ratio = trim(str_replace('*','', $val)); |
} |
if ($incr) { |
$val = trim($interval); |
if ($key == 'left' && preg_match('/[+-]/', $interval)) { |
$val = $params[0]['width'] + trim($val); |
} |
} elseif ($incr) { |
$val = trim($start); |
} elseif ($ratio) { |
$val = $ratio * $this->_strlenByLevel[0]; |
} |
$geometry["'$key'"][0] = $val; |
$params[0][$key] = $val; |
} |
foreach($childGeometry as $key => $val) { |
$incr = false; |
if (strpos($val, ',') !== false) { |
list($start, $interval) = explode(',', $val); |
$incr = true; |
} |
$ratio = false; |
if ($key == 'width' && strpos($val, '*') !== false) { |
$ratio = trim(str_replace('*', '', $val)); |
} |
for ($i = 1; $i <= $this->_levels; $i++) { |
if ($incr && isset($lastval[$key])) { |
$val = trim($interval); |
if($key == 'block_left' && preg_match('/[+-]/', $interval)) { |
$val = $params[$i - 1]['width'] + trim($val); |
} |
} elseif($incr) { |
$val = trim($start); |
} elseif ($ratio) { |
$val = $ratio * $this->_strlenByLevel[$i]; |
if($val < $params[0]['width']) { |
$val = $params[0]['width']; |
} |
} |
$lastval[$key] = $val; |
$geometry["'$key'"][] = $val; |
$params[$i][$key] = $val; |
} |
} |
$pos = false; |
$pos = $pos . 'var MENU_POS'.$menu_id." = new Array();\n"; |
foreach ($geometry as $key => $val) { |
$pos = $pos . 'MENU_POS' . $menu_id . "[$key] = [" . implode(', ', $val) . "];\n"; |
} |
return $pos; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* |
* @access public |
*/ |
function printTree() |
{ |
if (!$options = $this->_getOptions('printTree')) { |
return PEAR::raiseError("TigraMenu::printTree() needs options. See TigraMenu::setOptions()", NESEO_ERROR_NO_OPTIONS, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
echo $this->_openMenu($options['menu_id']) . $this->_structTigraMenu .$this->_closeMenu(); |
echo "\n\n"; |
echo $this->_addStyles($options['menu_id'], $options['rootStyles'], $options['childStyles']); |
echo "\n\n"; |
echo $this->_addGeometry($options['menu_id'], $options['rootGeometry'], $options['childGeometry']); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/DataObject/Generator.php |
---|
New file |
0,0 → 1,929 |
<?php |
/** |
* Generation tools for DB_DataObject |
* |
* 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_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Generator.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
/** |
* |
* Config _$ptions |
* [DB_DataObject_Generator] |
* ; optional default = DB/DataObject.php |
* extends_location = |
* ; optional default = DB_DataObject |
* extends = |
* ; alter the extends field when updating a class (defaults to only replacing DB_DataObject) |
* generator_class_rewrite = ANY|specific_name // default is DB_DataObject |
* |
*/ |
/** |
* Needed classes |
*/ |
require_once 'DB/DataObject.php'; |
//require_once('Config.php'); |
/** |
* Generator class |
* |
* @package DB_DataObject |
*/ |
class DB_DataObject_Generator extends DB_DataObject |
{ |
/* =========================================================== */ |
/* Utility functions - for building db config files */ |
/* =========================================================== */ |
/** |
* Array of table names |
* |
* @var array |
* @access private |
*/ |
var $tables; |
/** |
* associative array table -> array of table row objects |
* |
* @var array |
* @access private |
*/ |
var $_definitions; |
/** |
* active table being output |
* |
* @var string |
* @access private |
*/ |
var $table; // active tablename |
/** |
* The 'starter' = call this to start the process |
* |
* @access public |
* @return none |
*/ |
function start() |
{ |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$databases = array(); |
foreach($options as $k=>$v) { |
if (substr($k,0,9) == 'database_') { |
$databases[substr($k,9)] = $v; |
} |
} |
if (@$options['database']) { |
require_once 'DB.php'; |
$dsn = DB::parseDSN($options['database']); |
if (!isset($database[$dsn['database']])) { |
$databases[$dsn['database']] = $options['database']; |
} |
} |
foreach($databases as $databasename => $database) { |
if (!$database) { |
continue; |
} |
$this->debug("CREATING FOR $databasename\n"); |
$class = get_class($this); |
$t = new $class; |
$t->_database_dsn = $database; |
$t->_database = $databasename; |
$dsn = DB::parseDSN($database); |
if (($dsn['phptype'] == 'sqlite') && is_file($databasename)) { |
$t->_database = basename($t->_database); |
} |
$t->_createTableList(); |
foreach(get_class_methods($class) as $method) { |
if (substr($method,0,8 ) != 'generate') { |
continue; |
} |
$this->debug("calling $method"); |
$t->$method(); |
} |
} |
$this->debug("DONE\n\n"); |
} |
/** |
* Output File was config object, now just string |
* Used to generate the Tables |
* |
* @var string outputbuffer for table definitions |
* @access private |
*/ |
var $_newConfig; |
/** |
* Build a list of tables; |
* Currently this is very Mysql Specific - ideas for more generic stiff welcome |
* |
* @access private |
* @return none |
*/ |
function _createTableList() |
{ |
$this->_connect(); |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5]; |
// try getting a list of schema tables first. (postgres) |
$__DB->expectError(DB_ERROR_UNSUPPORTED); |
$this->tables = $__DB->getListOf('schema.tables'); |
$__DB->popExpect(); |
if (empty($this->tables) || is_a($this->tables , 'PEAR_Error')) { |
//if that fails fall back to clasic tables list. |
$this->tables = $__DB->getListOf('tables'); |
} |
if (is_a($this->tables , 'PEAR_Error')) { |
return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE); |
} |
// build views as well if asked to. |
if (!empty($options['build_views'])) { |
$views = $__DB->getListOf('views'); |
if (is_a($views,'PEAR_Error')) { |
return PEAR::raiseError( |
'Error getting Views (check the PEAR bug database for the fix to DB), ' . |
$views->toString(), |
null, |
PEAR_ERROR_DIE |
); |
} |
$this->tables = array_merge ($this->tables, $views); |
} |
// declare a temporary table to be filled with matching tables names |
$tmp_table = array(); |
foreach($this->tables as $table) { |
if (isset($options['generator_include_regex']) && |
!preg_match($options['generator_include_regex'],$table)) { |
continue; |
} else if (isset($options['generator_exclude_regex']) && |
preg_match($options['generator_exclude_regex'],$table)) { |
continue; |
} |
// postgres strip the schema bit from the |
if (!empty($options['generator_strip_schema'])) { |
$bits = explode('.', $table,2); |
$table = $bits[0]; |
if (count($bits) > 1) { |
$table = $bits[1]; |
} |
} |
$defs = $__DB->tableInfo($table); |
if (is_a($defs,'PEAR_Error')) { |
echo $defs->toString(); |
exit; |
} |
// cast all definitions to objects - as we deal with that better. |
foreach($defs as $def) { |
if (!is_array($def)) { |
continue; |
} |
$this->_definitions[$table][] = (object) $def; |
} |
// we find a matching table, just store it into a temporary array |
$tmp_table[] = $table; |
} |
// the temporary table array is now the right one (tables names matching |
// with regex expressions have been removed) |
$this->tables = $tmp_table; |
//print_r($this->_definitions); |
} |
/** |
* Auto generation of table data. |
* |
* it will output to db_oo_{database} the table definitions |
* |
* @access private |
* @return none |
*/ |
function generateDefinitions() |
{ |
$this->debug("Generating Definitions file: "); |
if (!$this->tables) { |
$this->debug("-- NO TABLES -- \n"); |
return; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
//$this->_newConfig = new Config('IniFile'); |
$this->_newConfig = ''; |
foreach($this->tables as $this->table) { |
$this->_generateDefinitionsTable(); |
} |
$this->_connect(); |
// dont generate a schema if location is not set |
// it's created on the fly! |
if (!@$options['schema_location'] && @!$options["ini_{$this->_database}"] ) { |
return; |
} |
$base = @$options['schema_location']; |
if (isset($options["ini_{$this->_database}"])) { |
$file = $options["ini_{$this->_database}"]; |
} else { |
$file = "{$base}/{$this->_database}.ini"; |
} |
if (!file_exists(dirname($file))) { |
require_once 'System.php'; |
System::mkdir(array('-p','-m',0755,dirname($file))); |
} |
$this->debug("Writing ini as {$file}\n"); |
touch($file); |
//print_r($this->_newConfig); |
$fh = fopen($file,'w'); |
fwrite($fh,$this->_newConfig); |
fclose($fh); |
//$ret = $this->_newConfig->writeInput($file,false); |
//if (PEAR::isError($ret) ) { |
// return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE); |
// } |
} |
/** |
* The table geneation part |
* |
* @access private |
* @return tabledef and keys array. |
*/ |
function _generateDefinitionsTable() |
{ |
global $_DB_DATAOBJECT; |
$defs = $this->_definitions[$this->table]; |
$this->_newConfig .= "\n[{$this->table}]\n"; |
$keys_out = "\n[{$this->table}__keys]\n"; |
$keys_out_primary = ''; |
$keys_out_secondary = ''; |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
echo "TABLE STRUCTURE FOR {$this->table}\n"; |
print_r($defs); |
} |
$DB = $this->getDatabaseConnection(); |
$dbtype = $DB->phptype; |
$ret = array( |
'table' => array(), |
'keys' => array(), |
); |
$ret_keys_primary = array(); |
$ret_keys_secondary = array(); |
foreach($defs as $t) { |
$n=0; |
switch (strtoupper($t->type)) { |
case 'INT': |
case 'INT2': // postgres |
case 'INT4': // postgres |
case 'INT8': // postgres |
case 'SERIAL4': // postgres |
case 'SERIAL8': // postgres |
case 'INTEGER': |
case 'TINYINT': |
case 'SMALLINT': |
case 'MEDIUMINT': |
case 'BIGINT': |
$type = DB_DATAOBJECT_INT; |
if ($t->len == 1) { |
$type += DB_DATAOBJECT_BOOL; |
} |
break; |
case 'REAL': |
case 'DOUBLE': |
case 'FLOAT': |
case 'FLOAT8': // double precision (postgres) |
case 'DECIMAL': |
case 'NUMERIC': |
case 'NUMBER': // oci8 |
$type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY... |
break; |
case 'YEAR': |
$type = DB_DATAOBJECT_INT; |
break; |
case 'BIT': |
case 'BOOL': |
case 'BOOLEAN': |
$type = DB_DATAOBJECT_BOOL; |
// postgres needs to quote '0' |
if ($dbtype == 'pgsql') { |
$type += DB_DATAOBJECT_STR; |
} |
break; |
case 'STRING': |
case 'CHAR': |
case 'VARCHAR': |
case 'VARCHAR2': |
case 'TINYTEXT': |
case 'ENUM': |
case 'SET': // not really but oh well |
case 'TIMESTAMPTZ': // postgres |
case 'BPCHAR': // postgres |
case 'INTERVAL': // postgres (eg. '12 days') |
case 'CIDR': // postgres IP net spec |
case 'INET': // postgres IP |
case 'MACADDR': // postgress network Mac address. |
$type = DB_DATAOBJECT_STR; |
break; |
case 'TEXT': |
case 'MEDIUMTEXT': |
case 'LONGTEXT': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT; |
break; |
case 'DATE': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE; |
break; |
case 'TIME': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME; |
break; |
case 'DATETIME': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; |
break; |
case 'TIMESTAMP': // do other databases use this??? |
$type = ($dbtype == 'mysql') ? |
DB_DATAOBJECT_MYSQLTIMESTAMP : |
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; |
break; |
case 'TINYBLOB': |
case 'BLOB': /// these should really be ignored!!!??? |
case 'MEDIUMBLOB': |
case 'LONGBLOB': |
case 'BYTEA': // postgres blob support.. |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB; |
break; |
} |
if (!strlen(trim($t->name))) { |
continue; |
} |
if (preg_match('/not_null/i',$t->flags)) { |
$type += DB_DATAOBJECT_NOTNULL; |
} |
$write_ini = true; |
if (in_array($t->name,array('null','yes','no','true','false'))) { |
echo "*****************************************************************\n". |
"** WARNING **\n". |
"** Found column '{$t->name}', which is invalid in an .ini file **\n". |
"** This line will not be writen to the file - you will have **\n". |
"** define the keys()/method manually. **\n". |
"*****************************************************************\n"; |
$write_ini = false; |
} else { |
$this->_newConfig .= "{$t->name} = $type\n"; |
} |
$ret['table'][$t->name] = $type; |
// i've no idea if this will work well on other databases? |
// only use primary key or nextval(), cause the setFrom blocks you setting all key items... |
// if no keys exist fall back to using unique |
//echo "\n{$t->name} => {$t->flags}\n"; |
if (preg_match("/(auto_increment|nextval\()/i",rawurldecode($t->flags))) { |
// native sequences = 2 |
if ($write_ini) { |
$keys_out_primary .= "{$t->name} = N\n"; |
} |
$ret_keys_primary[$t->name] = 'N'; |
} else if (preg_match("/(primary|unique)/i",$t->flags)) { |
// keys.. = 1 |
if ($write_ini) { |
$keys_out_secondary .= "{$t->name} = K\n"; |
} |
$ret_keys_secondary[$t->name] = 'K'; |
} |
} |
$this->_newConfig .= $keys_out . (empty($keys_out_primary) ? $keys_out_secondary : $keys_out_primary); |
$ret['keys'] = empty($keys_out_primary) ? $ret_keys_secondary : $ret_keys_primary; |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
print_r(array("dump for {$this->table}", $ret)); |
} |
return $ret; |
} |
/* |
* building the class files |
* for each of the tables output a file! |
*/ |
function generateClasses() |
{ |
//echo "Generating Class files: \n"; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$base = $options['class_location']; |
if (strpos($base,'%s') !== false) { |
$base = dirname($base); |
} |
if (!file_exists($base)) { |
require_once 'System.php'; |
System::mkdir(array('-p',$base)); |
} |
$class_prefix = $options['class_prefix']; |
if ($extends = @$options['extends']) { |
$this->_extends = $extends; |
$this->_extendsFile = $options['extends_location']; |
} |
foreach($this->tables as $this->table) { |
$this->table = trim($this->table); |
$this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)); |
$i = ''; |
if (strpos($options['class_location'],'%s') !== false) { |
$outfilename = sprintf($options['class_location'], preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table))); |
} else { |
$outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)).".php"; |
} |
$oldcontents = ''; |
if (file_exists($outfilename)) { |
// file_get_contents??? |
$oldcontents = implode('',file($outfilename)); |
} |
$out = $this->_generateClassTable($oldcontents); |
$this->debug( "writing $this->classname\n"); |
$fh = fopen($outfilename, "w"); |
fputs($fh,$out); |
fclose($fh); |
} |
//echo $out; |
} |
/** |
* class being extended (can be overridden by [DB_DataObject_Generator] extends=xxxx |
* |
* @var string |
* @access private |
*/ |
var $_extends = 'DB_DataObject'; |
/** |
* line to use for require('DB/DataObject.php'); |
* |
* @var string |
* @access private |
*/ |
var $_extendsFile = "DB/DataObject.php"; |
/** |
* class being generated |
* |
* @var string |
* @access private |
*/ |
var $_className; |
/** |
* The table class geneation part - single file. |
* |
* @access private |
* @return none |
*/ |
function _generateClassTable($input = '') |
{ |
// title = expand me! |
$foot = ""; |
$head = "<?php\n/**\n * Table Definition for {$this->table}\n */\n"; |
// requires |
$head .= "require_once '{$this->_extendsFile}';\n\n"; |
// add dummy class header in... |
// class |
$head .= "class {$this->classname} extends {$this->_extends} \n{"; |
$body = "\n ###START_AUTOCODE\n"; |
$body .= " /* the code below is auto generated do not remove the above tag */\n\n"; |
// table |
$padding = (30 - strlen($this->table)); |
if ($padding < 2) $padding =2; |
$p = str_repeat(' ',$padding) ; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var'; |
$body .= " {$var} \$__table = '{$this->table}'; {$p}// table name\n"; |
// if we are using the option database_{databasename} = dsn |
// then we should add var $_database = here |
// as database names may not always match.. |
if (isset($options["database_{$this->_database}"])) { |
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n"; |
} |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var'; |
if (!empty($options['generator_novars'])) { |
$var = '//'.$var; |
} |
$defs = $this->_definitions[$this->table]; |
// show nice information! |
$connections = array(); |
$sets = array(); |
foreach($defs as $t) { |
if (!strlen(trim($t->name))) { |
continue; |
} |
$padding = (30 - strlen($t->name)); |
if ($padding < 2) $padding =2; |
$p = str_repeat(' ',$padding) ; |
$body .=" {$var} \${$t->name}; {$p}// {$t->type}({$t->len}) {$t->flags}\n"; |
// can not do set as PEAR::DB table info doesnt support it. |
//if (substr($t->Type,0,3) == "set") |
// $sets[$t->Field] = "array".substr($t->Type,3); |
$body .= $this->derivedHookVar($t,$padding); |
} |
// THIS IS TOTALLY BORKED old FC creation |
// IT WILL BE REMOVED!!!!! in DataObjects 1.6 |
// grep -r __clone * to find all it's uses |
// and replace them with $x = clone($y); |
// due to the change in the PHP5 clone design. |
if ( substr(phpversion(),0,1) < 5) { |
$body .= "\n"; |
$body .= " /* ZE2 compatibility trick*/\n"; |
$body .= " function __clone() { return \$this;}\n"; |
} |
// simple creation tools ! (static stuff!) |
$body .= "\n"; |
$body .= " /* Static get */\n"; |
$body .= " function staticGet(\$k,\$v=NULL) { return DB_DataObject::staticGet('{$this->classname}',\$k,\$v); }\n"; |
// generate getter and setter methods |
$body .= $this->_generateGetters($input); |
$body .= $this->_generateSetters($input); |
/* |
theoretically there is scope here to introduce 'list' methods |
based up 'xxxx_up' column!!! for heiracitcal trees.. |
*/ |
// set methods |
//foreach ($sets as $k=>$v) { |
// $kk = strtoupper($k); |
// $body .=" function getSets{$k}() { return {$v}; }\n"; |
//} |
$body .= $this->derivedHookFunctions(); |
$body .= "\n /* the code above is auto generated do not remove the tag below */"; |
$body .= "\n ###END_AUTOCODE\n"; |
// stubs.. |
if (!empty($options['generator_add_validate_stubs'])) { |
foreach($defs as $t) { |
if (!strlen(trim($t->name))) { |
continue; |
} |
$validate_fname = 'validate' . ucfirst(strtolower($t->name)); |
// dont re-add it.. |
if (preg_match('/\s+function\s+' . $validate_fname . '\s*\(/i', $input)) { |
continue; |
} |
$body .= "\n function {$validate_fname}()\n {\n return false;\n }\n"; |
} |
} |
$foot .= "}\n"; |
$full = $head . $body . $foot; |
if (!$input) { |
return $full; |
} |
if (!preg_match('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n)/s',$input)) { |
return $full; |
} |
if (!preg_match('/(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',$input)) { |
return $full; |
} |
/* this will only replace extends DB_DataObject by default, |
unless use set generator_class_rewrite to ANY or a name*/ |
$class_rewrite = 'DB_DataObject'; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
if (!($class_rewrite = @$options['generator_class_rewrite'])) { |
$class_rewrite = 'DB_DataObject'; |
} |
if ($class_rewrite == 'ANY') { |
$class_rewrite = '[a-z_]+'; |
} |
$input = preg_replace( |
'/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' .$class_rewrite . '\s*\{(\n|\r\n)/si', |
"\nclass {$this->classname} extends {$this->_extends} \n{\n", |
$input); |
return preg_replace( |
'/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', |
$body,$input); |
} |
/** |
* hook to add extra methods to all classes |
* |
* called once for each class, use with $this->table and |
* $this->_definitions[$this->table], to get data out of the current table, |
* use it to add extra methods to the default classes. |
* |
* @access public |
* @return string added to class eg. functions. |
*/ |
function derivedHookFunctions() |
{ |
// This is so derived generator classes can generate functions |
// It MUST NOT be changed here!!! |
return ""; |
} |
/** |
* hook for var lines |
* called each time a var line is generated, override to add extra var |
* lines |
* |
* @param object t containing type,len,flags etc. from tableInfo call |
* @param int padding number of spaces |
* @access public |
* @return string added to class eg. functions. |
*/ |
function derivedHookVar(&$t,$padding) |
{ |
// This is so derived generator classes can generate variabels |
// It MUST NOT be changed here!!! |
return ""; |
} |
/** |
* getProxyFull - create a class definition on the fly and instantate it.. |
* |
* similar to generated files - but also evals the class definitoin code. |
* |
* |
* @param string database name |
* @param string table name of table to create proxy for. |
* |
* |
* @return object Instance of class. or PEAR Error |
* @access public |
*/ |
function getProxyFull($database,$table) { |
if ($err = $this->fillTableSchema($database,$table)) { |
return $err; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$class_prefix = $options['class_prefix']; |
if ($extends = @$options['extends']) { |
$this->_extends = $extends; |
$this->_extendsFile = $options['extends_location']; |
} |
$classname = $this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst(trim($this->table))); |
$out = $this->_generateClassTable(); |
//echo $out; |
eval('?>'.$out); |
return new $classname; |
} |
/** |
* fillTableSchema - set the database schema on the fly |
* |
* |
* |
* @param string database name |
* @param string table name of table to create schema info for |
* |
* @return none | PEAR::error() |
* @access public |
*/ |
function fillTableSchema($database,$table) { |
global $_DB_DATAOBJECT; |
$this->_database = $database; |
$this->_connect(); |
$table = trim($table); |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5]; |
$defs = $__DB->tableInfo($table); |
if (PEAR::isError($defs)) { |
return $defs; |
} |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
$this->debug("getting def for $database/$table",'fillTable'); |
$this->debug(print_r($defs,true),'defs'); |
} |
// cast all definitions to objects - as we deal with that better. |
foreach($defs as $def) { |
if (is_array($def)) { |
$this->_definitions[$table][] = (object) $def; |
} |
} |
$this->table = trim($table); |
$ret = $this->_generateDefinitionsTable(); |
$_DB_DATAOBJECT['INI'][$database][$table] = $ret['table']; |
$_DB_DATAOBJECT['INI'][$database][$table.'__keys'] = $ret['keys']; |
return false; |
} |
/** |
* Generate getter methods for class definition |
* |
* @param string $input Existing class contents |
* @return string |
* @access public |
*/ |
function _generateGetters($input) { |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$getters = ''; |
// only generate if option is set to true |
if (empty($options['generate_getters'])) { |
return ''; |
} |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input); |
$getters .= "\n\n"; |
$defs = $this->_definitions[$this->table]; |
// loop through properties and create getter methods |
foreach ($defs = $defs as $t) { |
// build mehtod name |
$methodName = 'get' . ucfirst($t->name); |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) { |
continue; |
} |
$getters .= " /**\n"; |
$getters .= " * Getter for \${$t->name}\n"; |
$getters .= " *\n"; |
$getters .= (stristr($t->flags, 'multiple_key')) ? " * @return object\n" |
: " * @return {$t->type}\n"; |
$getters .= " * @access public\n"; |
$getters .= " */\n"; |
$getters .= (substr(phpversion(),0,1) > 4) ? ' public ' |
: ' '; |
$getters .= "function $methodName() {\n"; |
$getters .= " return \$this->{$t->name};\n"; |
$getters .= " }\n\n"; |
} |
return $getters; |
} |
/** |
* Generate setter methods for class definition |
* |
* @param string Existing class contents |
* @return string |
* @access public |
*/ |
function _generateSetters($input) { |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$setters = ''; |
// only generate if option is set to true |
if (empty($options['generate_setters'])) { |
return ''; |
} |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input); |
$setters .= "\n"; |
$defs = $this->_definitions[$this->table]; |
// loop through properties and create setter methods |
foreach ($defs = $defs as $t) { |
// build mehtod name |
$methodName = 'set' . ucfirst($t->name); |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) { |
continue; |
} |
$setters .= " /**\n"; |
$setters .= " * Setter for \${$t->name}\n"; |
$setters .= " *\n"; |
$setters .= " * @param mixed input value\n"; |
$setters .= " * @access public\n"; |
$setters .= " */\n"; |
$setters .= (substr(phpversion(),0,1) > 4) ? ' public ' |
: ' '; |
$setters .= "function $methodName(\$value) {\n"; |
$setters .= " \$this->{$t->name} = \$value;\n"; |
$setters .= " }\n\n"; |
} |
return $setters; |
} |
} |
/tags/v2.0-narmer/api/pear/DB/DataObject/Error.php |
---|
New file |
0,0 → 1,53 |
<?php |
/** |
* DataObjects error handler, loaded on demand... |
* |
* DB_DataObject_Error is a quick wrapper around pear error, so you can distinguish the |
* error code source. |
* |
* 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_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Error.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
class DB_DataObject_Error extends PEAR_Error |
{ |
/** |
* DB_DataObject_Error constructor. |
* |
* @param mixed $code DB error code, or string with error message. |
* @param integer $mode what "error mode" to operate in |
* @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER |
* @param mixed $debuginfo additional debug info, such as the last query |
* |
* @access public |
* |
* @see PEAR_Error |
*/ |
function DB_DataObject_Error($message = '', $code = DB_ERROR, $mode = PEAR_ERROR_RETURN, |
$level = E_USER_NOTICE) |
{ |
$this->PEAR_Error('DB_DataObject Error: ' . $message, $code, $mode, $level); |
} |
// todo : - support code -> message handling, and translated error messages... |
} |
/tags/v2.0-narmer/api/pear/DB/DataObject/Cast.php |
---|
New file |
0,0 → 1,546 |
<?php |
/** |
* Prototype Castable Object.. for DataObject queries |
* |
* Storage for Data that may be cast into a variety of formats. |
* |
* 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_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Cast.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
/** |
* |
* Common usages: |
* // blobs |
* $data = DB_DataObject_Cast::blob($somefile); |
* $data = DB_DataObject_Cast::string($somefile); |
* $dataObject->someblobfield = $data |
* |
* // dates? |
* $d1 = new DB_DataObject_Cast::date('12/12/2000'); |
* $d2 = new DB_DataObject_Cast::date(2000,12,30); |
* $d3 = new DB_DataObject_Cast::date($d1->year, $d1->month+30, $d1->day+30); |
* |
* // time, datetime.. ????????? |
* |
* // raw sql???? |
* $data = DB_DataObject_Cast::sql('cast("123123",datetime)'); |
* $data = DB_DataObject_Cast::sql('NULL'); |
* |
* // int's/string etc. are proably pretty pointless..!!!! |
* |
* |
* inside DB_DataObject, |
* if (is_a($v,'db_dataobject_class')) { |
* $value .= $v->toString(DB_DATAOBJECT_INT,'mysql'); |
* } |
* |
* |
* |
* |
*/ |
class DB_DataObject_Cast { |
/** |
* Type of data Stored in the object.. |
* |
* @var string (date|blob|.....?) |
* @access public |
*/ |
var $type; |
/** |
* Data For date representation |
* |
* @var int day/month/year |
* @access public |
*/ |
var $day; |
var $month; |
var $year; |
/** |
* Generic Data.. |
* |
* @var string |
* @access public |
*/ |
var $value; |
/** |
* Blob consructor |
* |
* create a Cast object from some raw data.. (binary) |
* |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function blob($value) { |
$r = new DB_DataObject_Cast; |
$r->type = 'blob'; |
$r->value = $value; |
return $r; |
} |
/** |
* String consructor (actually use if for ints and everything else!!! |
* |
* create a Cast object from some string (not binary) |
* |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function string($value) { |
$r = new DB_DataObject_Cast; |
$r->type = 'string'; |
$r->value = $value; |
return $r; |
} |
/** |
* SQL constructor (for raw SQL insert) |
* |
* create a Cast object from some sql |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function sql($value) |
{ |
$r = new DB_DataObject_Cast; |
$r->type = 'sql'; |
$r->value = $value; |
return $r; |
} |
/** |
* Date Constructor |
* |
* create a Cast object from some string (not binary) |
* NO VALIDATION DONE, although some crappy re-calcing done! |
* |
* @param vargs... accepts |
* dd/mm |
* dd/mm/yyyy |
* yyyy-mm |
* yyyy-mm-dd |
* array(yyyy,dd) |
* array(yyyy,dd,mm) |
* |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function date() |
{ |
$args = func_get_args(); |
switch(count($args)) { |
case 0: // no args = today! |
$bits = explode('-',date('Y-m-d')); |
break; |
case 1: // one arg = a string |
if (strpos($args[0],'/') !== false) { |
$bits = array_reverse(explode('/',$args[0])); |
} else { |
$bits = explode('-',$args[0]); |
} |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) == 1) { // if YYYY set day = 1st.. |
$bits[] = 1; |
} |
if (count($bits) == 2) { // if YYYY-DD set day = 1st.. |
$bits[] = 1; |
} |
// if year < 1970 we cant use system tools to check it... |
// so we make a few best gueses.... |
// basically do date calculations for the year 2000!!! |
// fix me if anyone has more time... |
if (($bits[0] < 1975) || ($bits[0] > 2030)) { |
$oldyear = $bits[0]; |
$bits = explode('-',date('Y-m-d',mktime(1,1,1,$bits[1],$bits[2],2000))); |
$bits[0] = ($bits[0] - 2000) + $oldyear; |
} else { |
// now mktime |
$bits = explode('-',date('Y-m-d',mktime(1,1,1,$bits[1],$bits[2],$bits[0]))); |
} |
$r = new DB_DataObject_Cast; |
$r->type = 'date'; |
list($r->year,$r->month,$r->day) = $bits; |
return $r; |
} |
/** |
* Data For time representation ** does not handle timezones!! |
* |
* @var int hour/minute/second |
* @access public |
*/ |
var $hour; |
var $minute; |
var $second; |
/** |
* DateTime Constructor |
* |
* create a Cast object from a Date/Time |
* Maybe should accept a Date object.! |
* NO VALIDATION DONE, although some crappy re-calcing done! |
* |
* @param vargs... accepts |
* noargs (now) |
* yyyy-mm-dd HH:MM:SS (Iso) |
* array(yyyy,mm,dd,HH,MM,SS) |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
* @author therion 5 at hotmail |
*/ |
function dateTime() |
{ |
$args = func_get_args(); |
switch(count($args)) { |
case 0: // no args = now! |
$datetime = date('Y-m-d G:i:s', mktime()); |
case 1: |
// continue on from 0 args. |
if (!isset($datetime)) { |
$datetime = $args[0]; |
} |
$parts = explode(' ', $datetime); |
$bits = explode('-', $parts[0]); |
$bits = array_merge($bits, explode(':', $parts[1])); |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) != 6) { |
// PEAR ERROR? |
return false; |
} |
$r = DB_DataObject_Cast::date($bits[0], $bits[1], $bits[2]); |
if (!$r) { |
return $r; // pass thru error (False) - doesnt happen at present! |
} |
// change the type! |
$r->type = 'datetime'; |
// should we mathematically sort this out.. |
// (or just assume that no-one's dumb enough to enter 26:90:90 as a time! |
$r->hour = $bits[3]; |
$r->minute = $bits[4]; |
$r->second = $bits[5]; |
return $r; |
} |
/** |
* time Constructor |
* |
* create a Cast object from a Date/Time |
* Maybe should accept a Date object.! |
* NO VALIDATION DONE, and no-recalcing done! |
* |
* @param vargs... accepts |
* noargs (now) |
* HH:MM:SS (Iso) |
* array(HH,MM,SS) |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
* @author therion 5 at hotmail |
*/ |
function time() |
{ |
$args = func_get_args(); |
switch (count($args)) { |
case 0: // no args = now! |
$time = date('G:i:s', mktime()); |
case 1: |
// continue on from 0 args. |
if (!isset($time)) { |
$time = $args[0]; |
} |
$bits = explode(':', $time); |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) != 3) { |
return false; |
} |
// now take data from bits into object fields |
$r = new DB_DataObject_Cast; |
$r->type = 'time'; |
$r->hour = $bits[0]; |
$r->minute = $bits[1]; |
$r->second = $bits[2]; |
return $r; |
} |
/** |
* get the string to use in the SQL statement for this... |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toString($to=false,$db) |
{ |
// if $this->type is not set, we are in serious trouble!!!! |
// values for to: |
$method = 'toStringFrom'.$this->type; |
return $this->$method($to,$db); |
} |
/** |
* get the string to use in the SQL statement from a blob of binary data |
* ** Suppots only blob->postgres::bytea |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromBlob($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (!($to & DB_DATAOBJECT_BLOB)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::blob to something other than a blob!'); |
} |
switch ($db->dsn["phptype"]) { |
case 'pgsql': |
return "'".pg_escape_bytea($this->value)."'::bytea"; |
case 'mysql': |
return "'".mysql_real_escape_string($this->value,$db->connection)."'"; |
case 'mysqli': |
// this is funny - the parameter order is reversed ;) |
return "'".mysqli_real_escape_string($db->connection, $this->value)."'"; |
default: |
return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet"); |
} |
} |
/** |
* get the string to use in the SQL statement for a blob from a string! |
* ** Suppots only string->postgres::bytea |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromString($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
// |
if (!($to & DB_DATAOBJECT_BLOB)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a blob!'. |
' (why not just use native features)'); |
} |
switch ($db->dsn['phptype']) { |
case 'pgsql': |
return "'".pg_escape_string($this->value)."'::bytea"; |
case 'mysql': |
return "'".mysql_real_escape_string($this->value,$db->connection)."'"; |
case 'mysqli': |
return "'".mysqli_real_escape_string($db->connection, $this->value)."'"; |
default: |
return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet"); |
} |
} |
/** |
* get the string to use in the SQL statement for a date |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromDate($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
// |
if (($to !== false) && !($to & DB_DATAOBJECT_DATE)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a date!'. |
' (why not just use native features)'); |
} |
return "'{$this->year}-{$this->month}-{$this->day}'"; |
} |
/** |
* get the string to use in the SQL statement for a datetime |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
* @author therion 5 at hotmail |
*/ |
function toStringFromDateTime($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (($to !== false) && |
!($to & (DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME))) { |
return PEAR::raiseError('Invalid Cast from a ' . |
' DB_DataObject_Cast::dateTime to something other than a datetime!' . |
' (try using native features)'); |
} |
return "'{$this->year}-{$this->month}-{$this->day} {$this->hour}:{$this->minute}:{$this->second}'"; |
} |
/** |
* get the string to use in the SQL statement for a time |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
* @author therion 5 at hotmail |
*/ |
function toStringFromTime($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (($to !== false) && !($to & DB_DATAOBJECT_TIME)) { |
return PEAR::raiseError('Invalid Cast from a' . |
' DB_DataObject_Cast::time to something other than a time!'. |
' (try using native features)'); |
} |
return "'{$this->hour}:{$this->minute}:{$this->second}'"; |
} |
/** |
* get the string to use in the SQL statement for a raw sql statement. |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromSql($to,$db) |
{ |
return $this->value; |
} |
} |
/tags/v2.0-narmer/api/pear/DB/DataObject/createTables.php |
---|
New file |
0,0 → 1,55 |
#!/usr/bin/php -q |
<?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: Alan Knowles <alan@akbkhome.com> |
// +----------------------------------------------------------------------+ |
// |
// $Id: createTables.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
// |
// since this version doesnt use overload, |
// and I assume anyone using custom generators should add this.. |
define('DB_DATAOBJECT_NO_OVERLOAD',1); |
require_once 'DB/DataObject/Generator.php'; |
if (!ini_get('register_argc_argv')) { |
PEAR::raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
if (!@$_SERVER['argv'][1]) { |
PEAR::raiseError("\nERROR: createTable.php usage:\n\nC:\php\pear\DB\DataObjects\createTable.php example.ini\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
$config = parse_ini_file($_SERVER['argv'][1], true); |
foreach($config as $class=>$values) { |
$options = &PEAR::getStaticProperty($class,'options'); |
$options = $values; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
if (empty($options)) { |
PEAR::raiseError("\nERROR: could not read ini file\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
set_time_limit(0); |
DB_DataObject::debugLevel(1); |
$generator = new DB_DataObject_Generator; |
$generator->start(); |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's msql extension |
* for interacting with Mini SQL databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* PHP's mSQL extension did weird things with NULL values prior to PHP |
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds |
* those versions. |
* |
* @category Database |
* @package DB |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/QueryTool/Result/Object.php |
---|
New file |
0,0 → 1,89 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Result_Row and DB_QueryTool_Result_Object classes |
* |
* 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_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Object.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* Include parent class |
*/ |
require_once 'DB/QueryTool/Result.php'; |
/** |
* DB_QueryTool_Result_Row class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result_Row |
{ |
/** |
* create object properties from the array |
* @param array |
*/ |
function DB_QueryTool_Result_Row($arr) |
{ |
foreach ($arr as $key => $value) { |
$this->$key = $value; |
} |
} |
} |
// ----------------------------------------------------------------------------- |
/** |
* DB_QueryTool_Result_Object class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result_Object extends DB_QueryTool_Result |
{ |
// {{{ fetchRow |
/** |
* This function emulates PEAR::DB fetchRow() method |
* With this function DB_QueryTool can transparently replace PEAR::DB |
* |
* @todo implement fetchmode support? |
* @access public |
* @return void |
*/ |
function fetchRow() |
{ |
$arr = $this->getNext(); |
if (!PEAR::isError($arr)) { |
$row = new DB_QueryTool_Result_Row($arr); |
return $row; |
} |
return false; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/QueryTool/Result.php |
---|
New file |
0,0 → 1,261 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Result 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_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Result.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* DB_QueryTool_Result class |
* |
* This result actually contains the 'data' itself, the number of rows |
* returned and some additional info |
* using ZE2 you can also get retrieve data from the result doing the following: |
* <DB_QueryTool_Common-instance>->getAll()->getCount() |
* or |
* <DB_QueryTool_Common-instance>->getAll()->getData() |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result |
{ |
// {{{ class vars |
/** |
* @var array |
*/ |
var $_data = array(); |
/** |
* @var array |
*/ |
var $_dataKeys = array(); |
/** |
* @var integer |
*/ |
var $_count = 0; |
/** |
* the counter for the methods getFirst, getNext |
* @var array |
*/ |
var $_counter = null; |
// }}} |
// {{{ DB_QueryTool_Result() |
/** |
* create a new instance of result with the data returned by the query |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @param array the data returned by the result |
*/ |
function DB_QueryTool_Result($data) |
{ |
if (!count($data)) { |
$this->_count = 0; |
} else { |
list($firstElement) = $data; |
if (is_array($firstElement)) { // is the array a collection of rows? |
$this->_count = sizeof($data); |
} else { |
if (sizeof($data) > 0) { |
$this->_count = 1; |
} else { |
$this->_count = 0; |
} |
} |
} |
$this->_data = $data; |
} |
// }}} |
// {{{ numRows |
/** |
* return the number of rows returned. This is an alias for getCount(). |
* |
* @access public |
* @return integer |
*/ |
function numRows() |
{ |
return $this->_count; |
} |
// }}} |
// {{{ getCount() |
/** |
* return the number of rows returned |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @return integer the number of rows returned |
*/ |
function getCount() |
{ |
return $this->_count; |
} |
// }}} |
// {{{ getData() |
/** |
* get all the data returned |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @param string $key |
* @return mixed array or PEAR_Error |
*/ |
function getData($key=null) |
{ |
if (is_null($key)) { |
return $this->_data; |
} |
if ($this->_data[$key]) { |
return $this->_data[$key]; |
} |
return new PEAR_Error("there is no element with the key '$key'!"); |
} |
// }}} |
// {{{ getFirst() |
/** |
* get the first result set |
* we are not using next, current, and reset, since those ignore keys |
* which are empty or 0 |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @return mixed |
*/ |
function getFirst() |
{ |
if ($this->getCount() > 0) { |
$this->_dataKeys = array_keys($this->_data); |
$this->_counter = 0; |
return $this->_data[$this->_dataKeys[$this->_counter]]; |
} |
return new PEAR_Error('There are no elements!'); |
} |
// }}} |
// {{{ getNext() |
/** |
* Get next result set. If getFirst() has never been called before, |
* it calls that method. |
* @return mixed |
* @access public |
*/ |
function getNext() |
{ |
if (!$this->initDone()) { |
return $this->getFirst(); |
} |
if ($this->hasMore()) { |
$this->_counter++; |
return $this->_data[$this->_dataKeys[$this->_counter]]; |
} |
return new PEAR_Error('there are no more elements!'); |
} |
// }}} |
// {{{ hasMore() |
/** |
* check if there are other rows |
* |
* @return boolean |
* @access public |
*/ |
function hasMore() |
{ |
if ($this->_counter+1 < $this->getCount()) { |
return true; |
} |
return false; |
} |
// }}} |
// {{{ fetchRow |
/** |
* This function emulates PEAR::DB fetchRow() method. |
* With this method, DB_QueryTool can transparently replace PEAR_DB |
* |
* @todo implement fetchmode support? |
* @access public |
* @return void |
*/ |
function fetchRow() |
{ |
if ($this->hasMore()) { |
$arr = $this->getNext(); |
if (!PEAR::isError($arr)) { |
return $arr; |
} |
} |
return false; |
} |
// }}} |
// {{{ initDone |
/** |
* Helper method. Check if $this->_dataKeys has been initialized |
* |
* @return boolean |
* @access private |
*/ |
function initDone() |
{ |
return ( |
isset($this->_dataKeys) && |
is_array($this->_dataKeys) && |
count($this->_dataKeys) |
); |
} |
// }}} |
#TODO |
#function getPrevious() |
#function getLast() |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/QueryTool/EasyJoin.php |
---|
New file |
0,0 → 1,135 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_EasyJoin 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_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: EasyJoin.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* require the DB_QueryTool_Query class |
*/ |
require_once 'DB/QueryTool/Query.php'; |
/** |
* DB_QueryTool_EasyJoin class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_EasyJoin extends DB_QueryTool_Query |
{ |
// {{{ class vars |
/** |
* This is the regular expression that shall be used to find a table's shortName |
* in a column name, the string found by using this regular expression will be removed |
* from the column name and it will be checked if it is a table name |
* i.e. the default '/_id$/' would find the table name 'user' from the column name 'user_id' |
* |
* @var string regexp |
*/ |
var $_tableNamePreg = '/_id$/'; |
/** |
* This is to find the column name that is referred by it, so the default find |
* from 'user_id' the column 'id' which will be used to refer to the 'user' table |
* |
* @var string regexp |
*/ |
var $_columnNamePreg = '/^.*_/'; |
// }}} |
// {{{ __construct() |
/** |
* call parent constructor |
* @param mixed $dsn DSN string, DSN array or DB object |
* @param array $options |
*/ |
function __construct($dsn=false, $options=array()) |
{ |
parent::DB_QueryTool_Query($dsn, $options); |
} |
// }}} |
// {{{ autoJoin() |
/** |
* Join the given tables, using the column names, to find out how to join the tables; |
* i.e., if table1 has a column named "table2_id", this method will join |
* "WHERE table1.table2_id=table2.id". |
* All joins made here are only concatenated via AND. |
* @param array $tables |
*/ |
function autoJoin($tables) |
{ |
// FIXXME if $tables is empty autoJoin all available tables that have a relation |
// to $this->table, starting to search in $this->table |
settype($tables, 'array'); |
// add this->table to the tables array, so we go thru the current table first |
$tables = array_merge(array($this->table), $tables); |
$shortNameIndexed = $this->getTableSpec(true, $tables); |
$nameIndexed = $this->getTableSpec(false, $tables); |
//print_r($shortNameIndexed); |
//print_r($tables); print '<br><br>'; |
if (sizeof($shortNameIndexed) != sizeof($tables)) { |
$this->_errorLog("autoJoin-ERROR: not all the tables are in the tableSpec!<br />"); |
} |
$joinTables = array(); |
$joinConditions = array(); |
foreach ($tables as $aTable) { // go through $this->table and all the given tables |
if ($metadata = $this->metadata($aTable)) |
foreach ($metadata as $aCol => $x) { // go through each row to check which might be related to $aTable |
$possibleTableShortName = preg_replace($this->_tableNamePreg, '' , $aCol); |
$possibleColumnName = preg_replace($this->_columnNamePreg, '' , $aCol); |
//print "$aTable.$aCol .... possibleTableShortName=$possibleTableShortName .... possibleColumnName=$possibleColumnName<br />"; |
if (isset($shortNameIndexed[$possibleTableShortName])) { |
// are the tables given in the tableSpec? |
if (!$shortNameIndexed[$possibleTableShortName]['name'] || |
!$nameIndexed[$aTable]['name']) { |
// its an error of the developer, so log the error, dont show it to the end user |
$this->_errorLog("autoJoin-ERROR: '$aTable' is not given in the tableSpec!<br />"); |
} else { |
// do only join different table.col combination, |
// we should not join stuff like 'question.question=question.question' |
// this would be quite stupid, but it used to be :-( |
if ($shortNameIndexed[$possibleTableShortName]['name'] != $aTable || |
$possibleColumnName != $aCol |
) { |
$where = $shortNameIndexed[$possibleTableShortName]['name'].".$possibleColumnName=$aTable.$aCol"; |
$this->addJoin($nameIndexed[$aTable]['name'], $where); |
$this->addJoin($shortNameIndexed[$possibleTableShortName]['name'], $where); |
} |
} |
} |
} |
} |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/api/pear/DB/QueryTool/Query.php |
---|
New file |
0,0 → 1,2395 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Query 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_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Query.php,v 1.1 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* require the PEAR and DB classes |
*/ |
require_once 'PEAR.php'; |
require_once 'DB.php'; |
/** |
* DB_QueryTool_Query class |
* |
* This class should be extended |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Query |
{ |
// {{{ class vars |
/** |
* @var string the name of the primary column |
*/ |
var $primaryCol = 'id'; |
/** |
* @var string the current table the class works on |
*/ |
var $table = ''; |
/** |
* @var string the name of the sequence for this table |
*/ |
var $sequenceName = null; |
/** |
* @var object the db-object, a PEAR::DB instance |
*/ |
var $db = null; |
/** |
* @var string the where condition |
* @access private |
*/ |
var $_where = ''; |
/** |
* @var string the order condition |
* @access private |
*/ |
var $_order = ''; |
/** |
* @var string the having definition |
* @access private |
*/ |
var $_having = ''; |
/** |
* @var array contains the join content |
* the key is the join type, for now we have 'default' and 'left' |
* inside each key 'table' contains the table |
* key 'where' contains the where clause for the join |
* @access private |
*/ |
var $_join = array(); |
/** |
* @var string which column to index the result by |
* @access private |
*/ |
var $_index = null; |
/** |
* @var string the group-by clause |
* @access private |
*/ |
var $_group = ''; |
/** |
* @var array the limit |
* @access private |
*/ |
var $_limit = array(); |
/** |
* @var string type of result to return |
* @access private |
*/ |
var $_resultType = 'none'; |
/** |
* @var array the metadata temporary saved |
* @access private |
*/ |
var $_metadata = array(); |
/** |
* @var string |
* @access private |
*/ |
var $_lastQuery = null; |
/** |
* @var string the rows that shall be selected |
* @access private |
*/ |
var $_select = '*'; |
/** |
* @var string the rows that shall not be selected |
* @access private |
*/ |
var $_dontSelect = ''; |
/** |
* @var array this array saves different modes in which this class works |
* i.e. 'raw' means no quoting before saving/updating data |
* @access private |
*/ |
var $options = array( |
'raw' => false, |
'verbose' => true, // set this to false in a productive environment |
// it will produce error-logs if set to true |
'useCache' => false, |
'logFile' => false, |
); |
/** |
* this array contains information about the tables |
* those are |
* - 'name' => the real table name |
* - 'shortName' => the short name used, so that when moving the table i.e. |
* onto a provider's db and u have to rename the tables to |
* longer names this name will be relevant, i.e. when |
* autoJoining, i.e. a table name on your local machine is: |
* 'user' but online it has to be 'applName_user' then the |
* shortName will be used to determine if a column refers to |
* another table, if the colName is 'user_id', it knows the |
* shortName 'user' refers to the table 'applName_user' |
*/ |
var $tableSpec = array(); |
/** |
* this is the regular expression that shall be used to find a table's shortName |
* in a column name, the string found by using this regular expression will be removed |
* from the column name and it will be checked if it is a table name |
* i.e. the default '/_id$/' would find the table name 'user' from the column name 'user_id' |
*/ |
var $_tableNameToShortNamePreg = '/^.*_/'; |
/** |
* @var array this array caches queries that have already been built once |
* to reduce the execution time |
*/ |
var $_queryCache = array(); |
/** |
* The object that contains the log-instance |
*/ |
var $_logObject = null; |
/** |
* Some internal data the logging needs |
*/ |
var $_logData = array(); |
// }}} |
// {{{ __construct() |
/** |
* this is the constructor, as it will be implemented in ZE2 (php5) |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param object db-object |
*/ |
/* |
function __construct($dsn=false, $options=array()) |
{ |
if (!isset($options['autoConnect'])) { |
$autoConnect = true; |
} else { |
$autoConnect = $options['autoConnect']; |
} |
if (isset($options['errorCallback'])) { |
$this->setErrorCallback($options['errorCallback']); |
} |
if (isset($options['errorSetCallback'])) { |
$this->setErrorSetCallback($options['errorSetCallback']); |
} |
if (isset($options['errorLogCallback'])) { |
$this->setErrorLogCallback($options['errorLogCallback']); |
} |
if ($autoConnect && $dsn) { |
$this->connect($dsn, $options); |
} |
//we would need to parse the dsn first ... i dont feel like now :-) |
// oracle has all column names in upper case |
//FIXXXME make the class work only with upper case when we work with oracle |
//if ($this->db->phptype=='oci8' && !$this->primaryCol) { |
// $this->primaryCol = 'ID'; |
//} |
if ($this->sequenceName == null) { |
$this->sequenceName = $this->table; |
} |
} |
*/ |
// }}} |
// {{{ DB_QueryTool_Query() |
/** |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed $dsn DSN string, DSN array or DB object |
* @param array $options |
*/ |
function DB_QueryTool_Query($dsn=false, $options=array()) |
{ |
//$this->__construct($dsn, $options); |
if (!isset($options['autoConnect'])) { |
$autoConnect = true; |
} else { |
$autoConnect = $options['autoConnect']; |
unset($options['autoConnect']); |
} |
if (isset($options['errorCallback'])) { |
$this->setErrorCallback($options['errorCallback']); |
unset($options['errorCallback']); |
} |
if (isset($options['errorSetCallback'])) { |
$this->setErrorSetCallback($options['errorSetCallback']); |
unset($options['errorSetCallback']); |
} |
if (isset($options['errorLogCallback'])) { |
$this->setErrorLogCallback($options['errorLogCallback']); |
unset($options['errorLogCallback']); |
} |
if ($autoConnect && $dsn) { |
$this->connect($dsn, $options); |
} |
if (is_null($this->sequenceName)) { |
$this->sequenceName = $this->table; |
} |
} |
// }}} |
// {{{ connect() |
/** |
* use this method if you want to connect manually |
* @param mixed $dsn DSN string, DSN array or MDB object |
* @param array $options |
*/ |
function connect($dsn, $options=array()) |
{ |
if (is_object($dsn)) { |
$res = $this->db =& $dsn; |
} else { |
$res = $this->db = DB::connect($dsn, $options); |
} |
if (DB::isError($res)) { |
// FIXXME what shall we do here? |
$this->_errorLog($res->getUserInfo()); |
} else { |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
} |
// }}} |
// {{{ getDbInstance() |
/** |
* @return reference to current DB instance |
*/ |
function &getDbInstance() |
{ |
return $this->db; |
} |
// }}} |
// {{{ setDbInstance() |
/** |
* Setup using an existing connection. |
* this also sets the DB_FETCHMODE_ASSOC since this class |
* needs this to be set! |
* |
* @param object a reference to an existing DB-object |
* @return void |
*/ |
function setDbInstance(&$dbh) |
{ |
$this->db =& $dbh; |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ get() |
/** |
* get the data of a single entry |
* if the second parameter is only one column the result will be returned |
* directly not as an array! |
* |
* @version 2002/03/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param integer the id of the element to retrieve |
* @param string if this is given only one row shall be returned, directly, not an array |
* @return mixed (1) an array of the retrieved data |
* (2) if the second parameter is given and its only one column, |
* only this column's data will be returned |
* (3) false in case of failure |
*/ |
function get($id, $column='') |
{ |
$table = $this->table; |
$getMethod = 'getRow'; |
if ($column && !strpos($column, ',')) { // if only one column shall be selected |
$getMethod = 'getOne'; |
} |
// we dont use 'setSelect' here, since this changes the setup of the class, we |
// build the query directly |
// if $column is '' then _buildSelect selects '*' anyway, so that's the same behaviour as before |
$query['select'] = $this->_buildSelect($column); |
$query['where'] = $this->_buildWhere($this->table.'.'.$this->primaryCol.'='.$id); |
$queryString = $this->_buildSelectQuery($query); |
return $this->returnResult($this->execute($queryString,$getMethod)); |
} |
// }}} |
// {{{ getMultiple() |
/** |
* gets the data of the given ids |
* |
* @version 2002/04/23 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array this is an array of ids to retreive |
* @param string the column to search in for |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getMultiple($ids, $column='') |
{ |
$col = $this->primaryCol; |
if ($column) { |
$col = $column; |
} |
// FIXXME if $ids has no table.col syntax and we are using joins, the table better be put in front!!! |
$ids = $this->_quoteArray($ids); |
$query['where'] = $this->_buildWhere($col.' IN ('.implode(',', $ids).')'); |
$queryString = $this->_buildSelectQuery($query); |
return $this->returnResult($this->execute($queryString)); |
} |
// }}} |
// {{{ getAll() |
/** |
* get all entries from the DB |
* for sorting use setOrder!!!, the last 2 parameters are deprecated |
* |
* @version 2002/03/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param int to start from |
* @param int the number of rows to show |
* @param string the DB-method to use, i dont know if we should leave this param here ... |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getAll($from=0,$count=0,$method='getAll') |
{ |
$query = array(); |
if ($count) { |
$query = array('limit' => array($from, $count)); |
} |
return $this->returnResult($this->execute($this->_buildSelectQuery($query), $method)); |
} |
// }}} |
// {{{ getCol() |
/** |
* this method only returns one column, so the result will be a one dimensional array |
* this does also mean that using setSelect() should be set to *one* column, the one you want to |
* have returned a most common use case for this could be: |
* $table->setSelect('id'); |
* $ids = $table->getCol(); |
* OR |
* $ids = $table->getCol('id'); |
* so ids will be an array with all the id's |
* |
* @version 2003/02/25 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the column that shall be retreived |
* @param int to start from |
* @param int the number of rows to show |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getCol($column=null, $from=0, $count=0) |
{ |
$query = array(); |
if (!is_null($column)) { |
// by using _buildSelect() i can be sure that the table name will not be ambigious |
// i.e. in a join, where all the joined tables have a col 'id' |
// _buildSelect() will put the proper table name in front in case there is none |
$query['select'] = $this->_buildSelect($column); |
} |
if ($count) { |
$query['limit'] = array($from,$count); |
} |
return $this->returnResult($this->execute($this->_buildSelectQuery($query), 'getCol')); |
} |
// }}} |
// {{{ getCount() |
/** |
* get the number of entries |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getCount() |
{ |
/* the following query works on mysql |
SELECT count(DISTINCT image.id) FROM image2tree |
RIGHT JOIN image ON image.id = image2tree.image_id |
the reason why this is needed - i just wanted to get the number of rows that do exist if the result is grouped by image.id |
the following query is what i tried first, but that returns the number of rows that have been grouped together |
for each image.id |
SELECT count(*) FROM image2tree |
RIGHT JOIN image ON image.id = image2tree.image_id GROUP BY image.id |
so that's why we do the following, i am not sure if that is standard SQL and absolutley correct!!! |
*/ |
//FIXXME see comment above if this is absolutely correct!!! |
if ($group = $this->_buildGroup()) { |
$query['select'] = 'COUNT(DISTINCT '.$group.')'; |
$query['group'] = ''; |
} else { |
$query['select'] = 'COUNT(*)'; |
} |
$query['order'] = ''; // order is not of importance and might freak up the special group-handling up there, since the order-col is not be known |
/*# FIXXME use the following line, but watch out, then it has to be used in every method, or this |
# value will be used always, simply try calling getCount and getAll afterwards, getAll will return the count :-) |
# if getAll doesn't use setSelect!!! |
*/ |
//$this->setSelect('count(*)'); |
$queryString = $this->_buildSelectQuery($query, true); |
return ($res = $this->execute($queryString, 'getOne')) ? $res : 0; |
} |
// }}} |
// {{{ getDefaultValues() |
/** |
* return an empty element where all the array elements do already exist |
* corresponding to the columns in the DB |
* |
* @version 2002/04/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return array an empty, or pre-initialized element |
*/ |
function getDefaultValues() |
{ |
$ret = array(); |
// here we read all the columns from the DB and initialize them |
// with '' to prevent PHP-warnings in case we use error_reporting=E_ALL |
foreach ($this->metadata() as $aCol=>$x) { |
$ret[$aCol] = ''; |
} |
return $ret; |
} |
// }}} |
// {{{ getEmptyElement() |
/** |
* this is just for BC |
* @deprecated |
*/ |
function getEmptyElement() |
{ |
$this->getDefaultValues(); |
} |
// }}} |
// {{{ getQueryString() |
/** |
* Render the current query and return it as a string. |
* |
* @return string the current query |
*/ |
function getQueryString() |
{ |
$ret = $this->_buildSelectQuery(); |
if (is_string($ret)) { |
$ret = trim($ret); |
} |
return $ret; |
} |
// }}} |
// {{{ save() |
/** |
* save data, calls either update or add |
* if the primaryCol is given in the data this method knows that the |
* data passed to it are meant to be updated (call 'update'), otherwise it will |
* call the method 'add'. |
* If you dont like this behaviour simply stick with the methods 'add' |
* and 'update' and ignore this one here. |
* This method is very useful when you have validation checks that have to |
* be done for both adding and updating, then you can simply overwrite this |
* method and do the checks in here, and both cases will be validated first. |
* |
* @version 2002/03/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* @return mixed the data returned by either add or update-method |
*/ |
function save($data) |
{ |
if (!empty($data[$this->primaryCol])) { |
return $this->update($data); |
} |
return $this->add($data); |
} |
// }}} |
// {{{ update() |
/** |
* update the member data of a data set |
* |
* @version 2002/03/06 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* the id has to be given in the field with the key 'ID' |
* @return mixed true on success, or false otherwise |
*/ |
function update($newData) |
{ |
$query = array(); |
// do only set the 'where' part in $query, if a primary column is given |
// if not the default 'where' clause is used |
if (isset($newData[$this->primaryCol])) { |
$query['where'] = $this->primaryCol.'='.$newData[$this->primaryCol]; |
} |
$newData = $this->_checkColumns($newData, 'update'); |
$values = array(); |
$raw = $this->getOption('raw'); |
foreach ($newData as $key => $aData) { // quote the data |
//$values[] = "{$this->table}.$key=". ($raw ? $aData : $this->db->quote($aData)); |
$values[] = "$key=". ($raw ? $aData : $this->db->quote($aData)); |
} |
$query['set'] = implode(',', $values); |
//FIXXXME _buildUpdateQuery() seems to take joins into account, whcih is bullshit here |
$updateString = $this->_buildUpdateQuery($query); |
#print '$updateString = '.$updateString; |
return $this->execute($updateString, 'query') ? true : false; |
} |
// }}} |
// {{{ add() |
/** |
* add a new member in the DB |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* @return mixed the inserted id on success, or false otherwise |
*/ |
function add($newData) |
{ |
// if no primary col is given, get next sequence value |
if (empty($newData[$this->primaryCol])) { |
if ($this->primaryCol) { // do only use the sequence if a primary column is given |
// otherwise the data are written as given |
$id = $this->db->nextId($this->sequenceName); |
$newData[$this->primaryCol] = (int)$id; |
} else { |
// if no primary col is given return true on success |
$id = true; |
} |
} else { |
$id = $newData[$this->primaryCol]; |
} |
//unset($newData[$this->primaryCol]); |
$newData = $this->_checkColumns($newData, 'add'); |
$newData = $this->_quoteArray($newData); |
$query = sprintf( 'INSERT INTO %s (%s) VALUES (%s)', |
$this->table, |
implode(', ', array_keys($newData)), |
implode(', ', $newData) |
); |
return $this->execute($query, 'query') ? $id : false; |
} |
// }}} |
// {{{ addMultiple() |
/** |
* adds multiple new members in the DB |
* |
* @version 2002/07/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains an array of new data that shall be saved in the DB |
* the key-value pairs have to be the same for all the data!!! |
* @return mixed the inserted ids on success, or false otherwise |
*/ |
function addMultiple($data) |
{ |
if (!sizeof($data)) { |
return false; |
} |
// the inserted ids which will be returned or if no primaryCol is given |
// we return true by default |
$retIds = $this->primaryCol ? array() : true; |
$allData = array(); // each row that will be inserted |
foreach ($data as $key => $aData) { |
$aData = $this->_checkColumns($aData, 'add'); |
$aData = $this->_quoteArray($aData); |
if (empty($aData[$this->primaryCol])) { |
if ($this->primaryCol) { // do only use the sequence if a primary column is given |
// otherwise the data are written as given |
$retIds[] = $id = (int)$this->db->nextId($this->sequenceName); |
$aData[$this->primaryCol] = $id; |
} |
} else { |
$retIds[] = $aData[$this->primaryCol]; |
} |
$allData[] = '('.implode(', ', $aData).')'; |
} |
$query = sprintf( 'INSERT INTO %s (%s) VALUES %s', |
$this->table, |
implode(', ', array_keys($aData)), // use the keys of the last element built |
implode(', ', $allData) |
); |
return $this->execute($query, 'query') ? $retIds : false; |
} |
// }}} |
// {{{ remove() |
/** |
* removes a member from the DB |
* |
* @version 2002/04/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed integer/string - the value of the column that shall be removed |
* array - multiple columns that shall be matched, the second parameter will be ignored |
* @param string the column to match the data against, only if $data is not an array |
* @return boolean |
*/ |
function remove($data, $whereCol='') |
{ |
$raw = $this->getOption('raw'); |
if (is_array($data)) { |
//FIXXME check $data if it only contains columns that really exist in the table |
$wheres = array(); |
foreach ($data as $key => $val) { |
$wheres[] = $key.'='. ($raw ? $val : $this->db->quote($val)); |
} |
$whereClause = implode(' AND ',$wheres); |
} else { |
if (empty($whereCol)) { |
$whereCol = $this->primaryCol; |
} |
$whereClause = $whereCol.'='. ($raw ? $data : $this->db->quote($data)); |
} |
$query = sprintf( 'DELETE FROM %s WHERE %s', |
$this->table, |
$whereClause |
); |
return $this->execute($query, 'query') ? true : false; |
// i think this method should return the ID's that it removed, this way we could simply use the result |
// for further actions that depend on those id ... or? make stuff easier, see ignaz::imail::remove |
} |
// }}} |
// {{{ removeAll() |
/** |
* empty a table |
* |
* @version 2002/06/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return |
*/ |
function removeAll() |
{ |
$query = 'DELETE FROM '.$this->table; |
return $this->execute($query, 'query') ? true : false; |
} |
// }}} |
// {{{ removeMultiple() |
/** |
* remove the datasets with the given ids |
* |
* @version 2002/04/24 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array the ids to remove |
* @return |
*/ |
function removeMultiple($ids, $colName='') |
{ |
if (empty($colName)) { |
$colName = $this->primaryCol; |
} |
$ids = $this->_quoteArray($ids); |
$query = sprintf( 'DELETE FROM %s WHERE %s IN (%s)', |
$this->table, |
$colName, |
implode(',', $ids) |
); |
return $this->execute($query, 'query') ? true : false; |
} |
// }}} |
// {{{ removePrimary() |
/** |
* removes a member from the DB and calls the remove methods of the given objects |
* so all rows in another table that refer to this table are erased too |
* |
* @version 2002/04/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param integer the value of the primary key |
* @param string the column name of the tables with the foreign keys |
* @param object just for convinience, so nobody forgets to call this method |
* with at least one object as a parameter |
* @return boolean |
*/ |
function removePrimary($id, $colName, $atLeastOneObject) |
{ |
$argCounter = 2; // we have 2 parameters that need to be given at least |
// func_get_arg returns false and a warning if there are no more parameters, so |
// we suppress the warning and check for false |
while ($object = @func_get_arg($argCounter++)) { |
//FIXXXME let $object also simply be a table name |
if (!$object->remove($id, $colName)) { |
//FIXXXME do this better |
$this->_errorSet("Error removing '$colName=$id' from table {$object->table}."); |
return false; |
} |
} |
return ($this->remove($id) ? true : false); |
} |
// }}} |
// {{{ setLimit() |
/** |
* @param integer $from |
* @param integer $count |
*/ |
function setLimit($from=0, $count=0) |
{ |
if ($from==0 && $count==0) { |
$this->_limit = array(); |
} else { |
$this->_limit = array($from, $count); |
} |
} |
// }}} |
// {{{ getLimit() |
/** |
* @return array |
*/ |
function getLimit() |
{ |
return $this->_limit; |
} |
// }}} |
// {{{ setWhere() |
/** |
* sets the where condition which is used for the current instance |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
*/ |
function setWhere($whereCondition='') |
{ |
$this->_where = $whereCondition; |
//FIXXME parse the where condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'" |
// then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix'); |
} |
// }}} |
// {{{ getWhere() |
/** |
* gets the where condition which is used for the current instance |
* |
* @version 2002/04/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the where condition, this can be complete like 'X=7 AND Y=8' |
*/ |
function getWhere() |
{ |
return $this->_where; |
} |
// }}} |
// {{{ addWhere() |
/** |
* only adds a string to the where clause |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where clause to add to the existing one |
* @param string the condition for how to concatenate the new where clause |
* to the existing one |
*/ |
function addWhere($where, $condition='AND') |
{ |
if ($this->getWhere()) { |
$where = $this->getWhere().' '.$condition.' '.$where; |
} |
$this->setWhere($where); |
} |
// }}} |
// {{{ addWhereSearch() |
/** |
* add a where-like clause which works like a search for the given string |
* i.e. calling it like this: |
* $this->addWhereSearch('name', 'otto hans') |
* produces a where clause like this one |
* LOWER(name) LIKE "%otto%hans%" |
* so the search finds the given string |
* |
* @version 2002/08/14 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the column to search in for |
* @param string the string to search for |
*/ |
function addWhereSearch($column, $string, $condition='AND') |
{ |
// if the column doesn't contain a tablename use the current table name |
// in case it is a defined column to prevent ambiguous rows |
if (strpos($column, '.') === false) { |
$meta = $this->metadata(); |
if (isset($meta[$column])) { |
$column = $this->table.".$column"; |
} |
} |
$string = $this->db->quote('%'.str_replace(' ', '%', strtolower($string)).'%'); |
$this->addWhere("LOWER($column) LIKE $string", $condition); |
} |
// }}} |
// {{{ setOrder() |
/** |
* sets the order condition which is used for the current instance |
* |
* @version 2002/05/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
* @param boolean sorting order (TRUE => ASC, FALSE => DESC) |
*/ |
function setOrder($orderCondition='', $desc=false) |
{ |
$this->_order = $orderCondition .($desc ? ' DESC' : ''); |
} |
// }}} |
// {{{ addOrder() |
/** |
* Add a order parameter to the query. |
* |
* @version 2003/05/28 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
* @param boolean sorting order (TRUE => ASC, FALSE => DESC) |
*/ |
function addOrder($orderCondition='', $desc=false) |
{ |
$order = $orderCondition .($desc ? ' DESC' : ''); |
if ($this->_order) { |
$this->_order = $this->_order.','.$order; |
} else { |
$this->_order = $order; |
} |
} |
// }}} |
// {{{ getOrder() |
/** |
* gets the order condition which is used for the current instance |
* |
* @version 2002/05/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the order condition, this can be complete like 'ID,TIMESTAMP DESC' |
*/ |
function getOrder() |
{ |
return $this->_order; |
} |
// }}} |
// {{{ setHaving() |
/** |
* sets the having definition |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @param string the having definition |
*/ |
function setHaving($having='') |
{ |
$this->_having = $having; |
} |
// }}} |
// {{{ getHaving() |
/** |
* gets the having definition which is used for the current instance |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @return string the having definition |
*/ |
function getHaving() |
{ |
return $this->_having; |
} |
// }}} |
// {{{ addHaving() |
/** |
* Extend the current having clause. This is very useful, when you are building |
* this clause from different places and don't want to overwrite the currently |
* set having clause, but extend it. |
* |
* @param string this is a having clause, i.e. 'column' or 'table.column' or 'MAX(column)' |
* @param string the connection string, which usually stays the default, which is ',' (a comma) |
*/ |
function addHaving($what='*', $connectString=' AND ') |
{ |
if ($this->_having) { |
$this->_having = $this->_having.$connectString.$what; |
} else { |
$this->_having = $what; |
} |
} |
// }}} |
// {{{ setJoin() |
/** |
* sets a join-condition |
* |
* @version 2002/06/10 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed either a string or an array that contains |
* the table(s) to join on the current table |
* @param string the where clause for the join |
*/ |
function setJoin($table=null, $where=null, $joinType='default') |
{ |
//FIXXME make it possible to pass a table name as a string like this too 'user u' |
// where u is the string that can be used to refer to this table in a where/order |
// or whatever condition |
// this way it will be possible to join tables with itself, like setJoin(array('user u','user u1')) |
// this wouldnt work yet, but for doing so we would need to change the _build methods too!!! |
// because they use getJoin('tables') and this simply returns all the tables in use |
// but don't take care of the mentioned syntax |
if (is_null($table) || is_null($where)) { // remove the join if not sufficient parameters are given |
$this->_join[$joinType] = array(); |
return; |
} |
/* this causes problems if we use the order-by, since it doenst know the name to order it by ... :-) |
// replace the table names with the internal name used for the join |
// this way we can also join one table multiple times if it will be implemented one day |
$this->_join[$table] = preg_replace('/'.$table.'/','j1',$where); |
*/ |
$this->_join[$joinType][$table] = $where; |
} |
// }}} |
// {{{ setJoin() |
/** |
* if you do a left join on $this->table you will get all entries |
* from $this->table, also if there are no entries for them in the joined table |
* if both parameters are not given the left-join will be removed |
* NOTE: be sure to only use either a right or a left join |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table(s) to be left-joined |
* @param string the where clause for the join |
*/ |
function setLeftJoin($table=null, $where=null) |
{ |
$this->setJoin($table, $where, 'left'); |
} |
// }}} |
// {{{ addLeftJoin() |
/** |
* @param string the table to be left-joined |
* @param string the where clause for the join |
* @param string the join type |
*/ |
function addLeftJoin($table, $where, $type='left') |
{ |
// init value, to prevent E_ALL-warning |
if (!isset($this->_join[$type]) || !$this->_join[$type]) { |
$this->_join[$type] = array(); |
} |
$this->_join[$type][$table] = $where; |
} |
// }}} |
// {{{ setRightJoin() |
/** |
* see setLeftJoin for further explaination on what a left/right join is |
* NOTE: be sure to only use either a right or a left join |
//FIXXME check if the above sentence is necessary and if sql doesnt allow the use of both |
* |
* @see setLeftJoin() |
* @version 2002/09/04 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table(s) to be right-joined |
* @param string the where clause for the join |
*/ |
function setRightJoin($table=null, $where=null) |
{ |
$this->setJoin($table, $where, 'right'); |
} |
// }}} |
// {{{ getJoin() |
/** |
* gets the join-condition |
* |
* @access public |
* @param string [null|''|'table'|'tables'|'right'|'left'] |
* @return array gets the join parameters |
*/ |
function getJoin($what=null) |
{ |
// if the user requests all the join data or if the join is empty, return it |
if (is_null($what) || empty($this->_join)) { |
return $this->_join; |
} |
$ret = array(); |
switch (strtolower($what)) { |
case 'table': |
case 'tables': |
foreach ($this->_join as $aJoin) { |
if (count($aJoin)) { |
$ret = array_merge($ret, array_keys($aJoin)); |
} |
} |
break; |
case 'right': // return right-join data only |
case 'left': // return left join data only |
if (count($this->_join[$what])) { |
$ret = array_merge($ret, $this->_join[$what]); |
} |
break; |
} |
return $ret; |
} |
// }}} |
// {{{ addJoin() |
/** |
* adds a table and a where clause that shall be used for the join |
* instead of calling |
* setJoin(array(table1,table2),'<where clause1> AND <where clause2>') |
* you can also call |
* setJoin(table1,'<where clause1>') |
* addJoin(table2,'<where clause2>') |
* or where it makes more sense is to build a query which is made out of a |
* left join and a standard join |
* setLeftJoin(table1,'<where clause1>') |
* // results in ... FROM $this->table LEFT JOIN table ON <where clause1> |
* addJoin(table2,'<where clause2>') |
* // results in ... FROM $this->table,table2 LEFT JOIN table ON <where clause1> WHERE <where clause2> |
* |
* @access public |
* @param string the table to be joined |
* @param string the where clause for the join |
* @param string the join type |
*/ |
function addJoin($table, $where, $type='default') |
{ |
if ($table == $this->table) { |
return; //skip. Self joins are not supported. |
} |
// init value, to prevent E_ALL-warning |
if (!isset($this->_join[$type]) || !$this->_join[$type]) { |
$this->_join[$type] = array(); |
} |
$this->_join[$type][$table] = $where; |
} |
// }}} |
// {{{ setTable() |
/** |
* sets the table this class is currently working on |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table name |
*/ |
function setTable($table) |
{ |
$this->table = $table; |
} |
// }}} |
// {{{ getTable() |
/** |
* gets the table this class is currently working on |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the table name |
*/ |
function getTable() |
{ |
return $this->table; |
} |
// }}} |
// {{{ setGroup() |
/** |
* sets the group-by condition |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the group condition |
*/ |
function setGroup($group='') |
{ |
$this->_group = $group; |
//FIXXME parse the condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'" |
// then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix'); |
} |
// }}} |
// {{{ getGroup() |
/** |
* gets the group condition which is used for the current instance |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the group condition |
*/ |
function getGroup() |
{ |
return $this->_group; |
} |
// }}} |
// {{{ setSelect() |
/** |
* limit the result to return only the columns given in $what |
* @param string fields that shall be selected |
*/ |
function setSelect($what='*') |
{ |
$this->_select = $what; |
} |
// }}} |
// {{{ addSelect() |
/** |
* add a string to the select part of the query |
* |
* add a string to the select-part of the query and connects it to an existing |
* string using the $connectString, which by default is a comma. |
* (SELECT xxx FROM - xxx is the select-part of a query) |
* |
* @version 2003/01/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the string that shall be added to the select-part |
* @param string the string to connect the new string with the existing one |
* @return void |
*/ |
function addSelect($what='*', $connectString=',') |
{ |
// if the select string is not empty add the string, otherwise simply set it |
if ($this->_select) { |
$this->_select = $this->_select.$connectString.$what; |
} else { |
$this->_select = $what; |
} |
} |
// }}} |
// {{{ getSelect() |
/** |
* @return string |
*/ |
function getSelect() |
{ |
return $this->_select; |
} |
// }}} |
// {{{ setDontSelect() |
/** |
* @param string |
*/ |
function setDontSelect($what='') |
{ |
$this->_dontSelect = $what; |
} |
// }}} |
// {{{ getDontSelect() |
/** |
* @return string |
*/ |
function getDontSelect() |
{ |
return $this->_dontSelect; |
} |
// }}} |
// {{{ reset() |
/** |
* reset all the set* settings; with no parameter given, it resets them all |
* |
* @version 2002/09/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return void |
*/ |
function reset($what=array()) |
{ |
if (!sizeof($what)) { |
$what = array( |
'select', |
'dontSelect', |
'group', |
'having', |
'limit', |
'where', |
'index', |
'order', |
'join', |
'leftJoin', |
'rightJoin' |
); |
} |
foreach ($what as $aReset) { |
$this->{'set'.ucfirst($aReset)}(); |
} |
} |
// }}} |
// {{{ setOption() |
/** |
* set mode the class shall work in |
* currently we have the modes: |
* 'raw' does not quote the data before building the query |
* |
* @version 2002/09/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the mode to be set |
* @param mixed the value of the mode |
* @return void |
*/ |
function setOption($option, $value) |
{ |
$this->options[strtolower($option)] = $value; |
} |
// }}} |
// {{{ getOption() |
/** |
* @return string |
*/ |
function getOption($option) |
{ |
return $this->options[strtolower($option)]; |
} |
// }}} |
// {{{ _quoteArray() |
/** |
* quotes all the data in this array if we are not in raw mode! |
* @param array |
*/ |
function _quoteArray($data) |
{ |
if (!$this->getOption('raw')) { |
foreach ($data as $key => $val) { |
$data[$key] = $this->db->quote($val); |
} |
} |
return $data; |
} |
// }}} |
// {{{ _checkColumns() |
/** |
* checks if the columns which are given as the array's indexes really exist |
* if not it will be unset anyway |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the actual message, first word should always be the method name, |
* to build the message like this: className::methodname |
* @param integer the line number |
*/ |
function _checkColumns($newData, $method='unknown') |
{ |
if (!$meta = $this->metadata()) { // if no metadata available, return data as given |
return $newData; |
} |
foreach ($newData as $colName => $x) { |
if (!isset($meta[$colName])) { |
$this->_errorLog("$method, column {$this->table}.$colName doesnt exist, value was removed before '$method'",__LINE__); |
unset($newData[$colName]); |
} else { |
// if the current column exists, check the length too, not to write content that is too long |
// prevent DB-errors here |
// do only check the data length if this field is given |
if (isset($meta[$colName]['len']) && ($meta[$colName]['len'] != -1) && |
($oldLength=strlen($newData[$colName])) > $meta[$colName]['len'] |
) { |
$this->_errorLog("_checkColumns, had to trim column '$colName' from $oldLength to ". |
$meta[$colName]['DATA_LENGTH'].' characters.', __LINE__); |
$newData[$colName] = substr($newData[$colName], 0, $meta[$colName]['len']); |
} |
} |
} |
return $newData; |
} |
// }}} |
// {{{ debug() |
/** |
* overwrite this method and i.e. print the query $string |
* to see the final query |
* |
* @param string the query mostly |
*/ |
function debug($string){} |
// |
// |
// ONLY ORACLE SPECIFIC, not very nice since it is DB dependent, but we need it!!! |
// |
// |
// }}} |
// {{{ metadata() |
/** |
* !!!! query COPIED FROM db_oci8.inc - from PHPLIB !!!! |
* |
* @access public |
* @see |
* @version 2001/09 |
* @author PHPLIB |
* @param |
* @return |
*/ |
function metadata($table='') |
{ |
// is there an alias in the table name, then we have something like this: 'user ua' |
// cut of the alias and return the table name |
if (strpos($table, ' ') !== false) { |
$split = explode(' ', trim($table)); |
$table = $split[0]; |
} |
$full = false; |
if (empty($table)) { |
$table = $this->table; |
} |
// to prevent multiple selects for the same metadata |
if (isset($this->_metadata[$table])) { |
return $this->_metadata[$table]; |
} |
// FIXXXME use oci8 implementation of newer PEAR::DB-version |
if ($this->db->phptype == 'oci8') { |
$count = 0; |
$id = 0; |
$res = array(); |
//# This is a RIGHT OUTER JOIN: "(+)", if you want to see, what |
//# this query results try the following: |
//// $table = new Table; $this->db = new my_DB_Sql; // you have to make |
//// // your own class |
//// $table->show_results($this->db->query(see query vvvvvv)) |
//// |
$res = $this->db->getAll("SELECT T.column_name,T.table_name,T.data_type,". |
"T.data_length,T.data_precision,T.data_scale,T.nullable,". |
"T.char_col_decl_length,I.index_name". |
" FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I". |
" WHERE T.column_name=I.column_name (+)". |
" AND T.table_name=I.table_name (+)". |
" AND T.table_name=UPPER('$table') ORDER BY T.column_id"); |
if (DB::isError($res)) { |
//$this->_errorSet($res->getMessage()); |
// i think we only need to log here, since this method is never used |
// directly for the user's functionality, which means if it fails it |
// is most probably an appl error |
$this->_errorLog($res->getUserInfo()); |
return false; |
} |
foreach ($res as $key=>$val) { |
$res[$key]['name'] = $val['COLUMN_NAME']; |
} |
} else { |
if (!is_object($this->db)) { |
return false; |
} |
$res = $this->db->tableinfo($table); |
if (DB::isError($res)) { |
$this->_errorSet($res->getUserInfo()); |
return false; |
} |
} |
$ret = array(); |
foreach ($res as $key => $val) { |
$ret[$val['name']] = $val; |
} |
$this->_metadata[$table] = $ret; |
return $ret; |
} |
// |
// methods for building the query |
// |
// }}} |
// {{{ _buildFrom() |
/** |
* build the from string |
* |
* @access private |
* @return string the string added after FROM |
*/ |
function _buildFrom() |
{ |
$from = $this->table; |
$join = $this->getJoin(); |
if (!$join) { // no join set |
return $from; |
} |
// handle the standard join thingy |
if (isset($join['default']) && count($join['default'])) { |
$from .= ','.implode(',',array_keys($join['default'])); |
} |
// handle left/right joins |
foreach (array('left', 'right') as $joinType) { |
if (isset($join[$joinType]) && count($join[$joinType])) { |
foreach($join[$joinType] as $table => $condition) { |
// replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME |
// since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange |
// FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column' |
$regExp = '/_('.$table.')_([^\s]+)/'; |
$where = preg_replace($regExp, '$1.$2', $condition); |
// add the table name before any column that has no table prefix |
// since this might cause "unambiguous column" errors |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol=>$x) { |
// this covers the LIKE,IN stuff: 'name LIKE "%you%"' 'id IN (2,3,4,5)' |
$condition = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $condition); |
// replace also the column names which are behind a '=' |
// and do this also if the aCol is at the end of the where clause |
// that's what the $ is for |
$condition = preg_replace('/=\s*'.$aCol.'(\s|$)/', "={$this->table}.$aCol ", $condition); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$condition = preg_replace('/(^\s*|\s+)'.$aCol.'\s*=/', "$1{$this->table}.$aCol=", $condition); |
} |
} |
$from .= ' '.strtoupper($joinType).' JOIN '.$table.' ON '.$condition; |
} |
} |
} |
return $from; |
} |
// }}} |
// {{{ getTableShortName() |
/** |
* this method gets the short name for a table |
* |
* get the short name for a table, this is needed to properly build the |
* 'AS' parts in the select query |
* @param string the real table name |
* @return string the table's short name |
*/ |
function getTableShortName($table) |
{ |
$tableSpec = $this->getTableSpec(false); |
if (isset($tableSpec[$table]['shortName']) && $tableSpec[$table]['shortName']) { |
//print "$table ... ".$tableSpec[$table]['shortName'].'<br>'; |
return $tableSpec[$table]['shortName']; |
} |
$possibleTableShortName = preg_replace($this->_tableNameToShortNamePreg, '', $table); |
//print "$table ... $possibleTableShortName<br>"; |
return $possibleTableShortName; |
} |
// }}} |
// {{{ getTableSpec() |
/** |
* gets the tableSpec either indexed by the short name or the name |
* returns the array for the tables given as parameter or if no |
* parameter given for all tables that exist in the tableSpec |
* |
* @param array table names (not the short names!) |
* @param boolean if true the table is returned indexed by the shortName |
* otherwise indexed by the name |
* @return array the tableSpec indexed |
*/ |
function getTableSpec($shortNameIndexed=true, $tables=array()) |
{ |
$newSpec = array(); |
foreach ($this->tableSpec as $aSpec) { |
if (sizeof($tables)==0 || in_array($aSpec['name'],$tables)) { |
if ($shortNameIndexed) { |
$newSpec[$aSpec['shortName']] = $aSpec; |
} else { |
$newSpec[$aSpec['name']] = $aSpec; |
} |
} |
} |
return $newSpec; |
} |
// }}} |
// {{{ _buildSelect() |
/** |
* build the 'SELECT <what> FROM ... 'for a select |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string if given use this string |
* @return string the what-clause |
*/ |
function _buildSelect($what=null) |
{ |
// what has preference, that means if what is set it is used |
// this is only because the methods like 'get' pass an individually built value, which |
// is supposed to be used, but usually it's generically build using the 'getSelect' values |
if (empty($what) && $this->getSelect()) { |
$what = $this->getSelect(); |
} |
// |
// replace all the '*' by the real column names, and take care of the dontSelect-columns! |
// |
$dontSelect = $this->getDontSelect(); |
$dontSelect = $dontSelect ? explode(',', $dontSelect) : array(); // make sure dontSelect is an array |
// here we will replace all the '*' and 'table.*' by all the columns that this table |
// contains. we do this so we can easily apply the 'dontSelect' values. |
// and so we can also handle queries like: 'SELECT *,count() FROM ' and 'SELECT table.*,x FROM ' too |
if (strpos($what, '*') !== false) { |
// subpattern 1 get all the table names, that are written like this: 'table.*' including '*' |
// for '*' the tablename will be '' |
preg_match_all('/([^,]*)(\.)?\*\s*(,|$)/U', $what, $res); |
//print "$what ... ";print_r($res);print "<br>"; |
$selectAllFromTables = array_unique($res[1]); // make the table names unique, so we do it all just once for each table |
$tables = array(); |
if (in_array('', $selectAllFromTables)) { // was there a '*' ? |
// get all the tables that we need to process, depending on if joined or not |
$tables = $this->getJoin() ? |
array_merge($this->getJoin('tables'), array($this->table)) : // get the joined tables and this->table |
array($this->table); // create an array with only this->table |
} else { |
$tables = $selectAllFromTables; |
} |
$cols = array(); |
foreach ($tables as $aTable) { // go thru all the tables and get all columns for each, and handle 'dontSelect' |
if ($meta = $this->metadata($aTable)) { |
foreach ($meta as $colName => $x) { |
// handle the dontSelect's |
if (in_array($colName, $dontSelect) || in_array("$aTable.$colName", $dontSelect)) { |
continue; |
} |
// build the AS clauses |
// put " around them to enable use of reserved words, i.e. SELECT table.option as option FROM... |
// and 'option' actually is a reserved word, at least in mysql |
// put double quotes around them, since pgsql doesnt work with single quotes |
// but don't do this for ibase because it doesn't work! |
if ($aTable == $this->table) { |
if ($this->db->phptype == 'ibase') { |
$cols[$aTable][] = $this->table. '.' .$colName . ' AS '. $colName; |
} else { |
$cols[$aTable][] = $this->table. '.' .$colName . ' AS "'. $colName .'"'; |
} |
} else { |
$cols[$aTable][] = "$aTable.$colName AS \"_".$this->getTableShortName($aTable)."_$colName\""; |
} |
} |
} |
} |
// put the extracted select back in the $what |
// that means replace 'table.*' by the i.e. 'table.id AS _table_id' |
// or if it is the table of this class replace 'table.id AS id' |
if (in_array('', $selectAllFromTables)) { |
$allCols = array(); |
foreach ($cols as $aTable) { |
$allCols[] = implode(',', $aTable); |
} |
$what = preg_replace('/(^|,)\*($|,)/', '$1'.implode(',',$allCols).'$2', $what); |
// remove all the 'table.*' since we have selected all anyway (because there was a '*' in the select) |
$what = preg_replace('/[^,]*(\.)?\*\s*(,|$)/U', '', $what); |
} else { |
foreach ($cols as $tableName => $aTable) { |
if (is_array($aTable) && sizeof($aTable)) { |
// replace all the 'table.*' by their select of each column |
$what = preg_replace('/(^|,)\s*'.$tableName.'\.\*\s*($|,)/', '$1'.implode(',',$aTable).'$2', $what); |
} |
} |
} |
} |
if ($this->getJoin()) { |
// replace all 'column' by '$this->table.column' to prevent ambigious errors |
$metadata = $this->metadata(); |
if (is_array($metadata)) { |
foreach ($metadata as $aCol => $x) { |
// handle ',id as xid,MAX(id),id' etc. |
// FIXXME do this better!!! |
$what = preg_replace( "/(^|,|\()(\s*)$aCol(\)|\s|,|as|$)/i", |
// $2 is actually just to keep the spaces, is not really |
// necessary, but this way the test works independent of this functionality here |
"$1$2{$this->table}.$aCol$3", |
$what); |
} |
} |
// replace all 'joinedTable.columnName' by '_joinedTable_columnName' |
// this actually only has an effect if there was no 'table.*' for 'table' |
// if that was there, then it has already been done before |
foreach ($this->getJoin('tables') as $aTable) { |
if ($meta = $this->metadata($aTable)) { |
foreach ($meta as $aCol=>$x) { |
// dont put the 'AS' behind it if there is already one |
if (preg_match("/$aTable.$aCol\s*as/i",$what)) { |
continue; |
} |
// this covers a ' table.colName ' surrounded by spaces, and replaces it by ' table.colName AS _table_colName' |
$what = preg_replace('/\s'.$aTable.'.'.$aCol.'\s/', " $aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol ", $what); |
// replace also the column names which are behind a ',' |
// and do this also if the aCol is at the end that's what the $ is for |
$what = preg_replace('/,\s*'.$aTable.'.'.$aCol.'(,|\s|$)/', ",$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol$1", $what); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$what = preg_replace('/(^\s*|\s+)'.$aTable.'.'.$aCol.'\s*,/', "$1$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol,", $what); |
} |
} |
} |
} |
return $what; |
} |
// }}} |
// {{{ _buildWhere() |
/** |
* Build WHERE clause |
* |
* @param string $where WHERE clause |
* @return string $where WHERE clause after processing |
* @access private |
*/ |
function _buildWhere($where='') |
{ |
$where = trim($where); |
$originalWhere = $this->getWhere(); |
if ($originalWhere) { |
if (!empty($where)) { |
$where = $originalWhere.' AND '.$where; |
} else { |
$where = $originalWhere; |
} |
} |
$where = trim($where); |
if ($join = $this->getJoin()) { // is join set? |
// only those where conditions in the default-join have to be added here |
// left-join conditions are added behind 'ON', the '_buildJoin()' does that |
if (isset($join['default']) && count($join['default'])) { |
// we have to add this join-where clause here |
// since at least in mysql a query like: select * from tableX JOIN tableY ON ... |
// doesnt work, may be that's even SQL-standard... |
if (!empty($where)) { |
$where = implode(' AND ', $join['default']).' AND '.$where; |
} else { |
$where = implode(' AND ', $join['default']); |
} |
} |
// replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME |
// since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange |
// FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column' |
$regExp = '/_('.implode('|', $this->getJoin('tables')).')_([^\s]+)/'; |
$where = preg_replace($regExp, '$1.$2', $where); |
// add the table name before any column that has no table prefix |
// since this might cause "unambigious column" errors |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
// this covers the LIKE,IN stuff: 'name LIKE "%you%"' 'id IN (2,3,4,5)' |
$where = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $where); |
// replace also the column names which are behind a '=' |
// and do this also if the aCol is at the end of the where clause |
// that's what the $ is for |
$where = preg_replace('/([=<>])\s*'.$aCol.'(\s|$)/', "$1{$this->table}.$aCol ", $where); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$where = preg_replace('/(^\s*|\s+)'.$aCol.'\s*([=<>])/', "$1{$this->table}.$aCol$2", $where); |
} |
} |
} |
return $where; |
} |
// }}} |
// {{{ _buildOrder() |
/** |
* |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function _buildOrder() |
{ |
$order = $this->getOrder(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol=>$x) { |
$order = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $order); |
} |
} |
return $order; |
} |
// }}} |
// {{{ _buildGroup() |
/** |
* Build the group-clause, replace 'column' by 'table.column'. |
* |
* @access public |
* @param void |
* @return string the rendered group clause |
*/ |
function _buildGroup() |
{ |
$group = $this->getGroup(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$group = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $group); |
} |
} |
return $group; |
} |
// }}} |
// {{{ _buildHaving() |
/** |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @param |
* @return string the having clause |
*/ |
function _buildHaving() |
{ |
$having = $this->getHaving(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$having = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U',"$1{$this->table}.$aCol$2",$having); |
} |
} |
return $having; |
} |
// }}} |
// {{{ _buildHaving() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array this array contains the elements of the query, |
* indexed by their key, which are: 'select','from','where', etc. |
* @param boolean whether this method is called via getCount() or not. |
* @return |
*/ |
function _buildSelectQuery($query=array(), $isCalledViaGetCount = false) |
{ |
/*FIXXXME finish this |
$cacheKey = md5(serialize(????)); |
if (isset($this->_queryCache[$cacheKey])) { |
$this->_errorLog('using cached query',__LINE__); |
return $this->_queryCache[$cacheKey]; |
} |
*/ |
$where = isset($query['where']) ? $query['where'] : $this->_buildWhere(); |
if ($where) { |
$where = 'WHERE '.$where; |
} |
$order = isset($query['order']) ? $query['order'] : $this->_buildOrder(); |
if ($order) { |
$order = 'ORDER BY '.$order; |
} |
$group = isset($query['group']) ? $query['group'] : $this->_buildGroup(); |
if ($group) { |
$group = 'GROUP BY '.$group; |
} |
$having = isset($query['having']) ? $query['having'] : $this->_buildHaving(); |
if ($having) { |
$having = 'HAVING '.$having; |
} |
$queryString = sprintf( 'SELECT %s FROM %s %s %s %s %s', |
isset($query['select']) ? $query['select'] : $this->_buildSelect(), |
isset($query['from']) ? $query['from'] : $this->_buildFrom(), |
$where, |
$group, |
$having, |
$order |
); |
// $query['limit'] has preference! |
$limit = isset($query['limit']) ? $query['limit'] : $this->_limit; |
if (!$isCalledViaGetCount && @$limit[1]) { // is there a count set? |
$queryString=$this->db->modifyLimitQuery($queryString,$limit[0],$limit[1]); |
if (DB::isError($queryString)) { |
$this->_errorSet('DB_QueryTool::db::modifyLimitQuery failed '.$queryString->getMessage()); |
$this->_errorLog($queryString->getUserInfo()); |
return false; |
} |
} |
// $this->_queryCache[$cacheKey] = $queryString; |
return $queryString; |
} |
// }}} |
// {{{ _buildUpdateQuery() |
/** |
* this simply builds an update query. |
* |
* @param array the parameter array might contain the following indexes |
* 'where' the where clause to be added, i.e. |
* UPDATE table SET x=1 WHERE y=0 |
* here the 'where' part simply would be 'y=0' |
* 'set' the actual data to be updated |
* in the example above, that would be 'x=1' |
* @return string the resulting query |
*/ |
function _buildUpdateQuery($query=array()) |
{ |
$where = isset($query['where']) ? $query['where'] : $this->_buildWhere(); |
if ($where) { |
$where = 'WHERE '.$where; |
} |
$updateString = sprintf('UPDATE %s SET %s %s', |
$this->table, |
$query['set'], |
$where |
); |
return $updateString; |
} |
// }}} |
// {{{ execute() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @param string query method |
* @return boolean |
*/ |
function execute($query=null, $method='getAll') |
{ |
$this->writeLog(); |
if (is_null($query)) { |
$query = $this->_buildSelectQuery(); |
} |
$this->writeLog('query built: '.$query); |
// FIXXME on ORACLE this doesnt work, since we return joined columns as _TABLE_COLNAME and the _ in front |
// doesnt work on oracle, add a letter before it!!! |
$this->_lastQuery = $query; |
$this->debug($query); |
$this->writeLog('start query'); |
if (DB::isError($res = $this->db->$method($query))) { |
$this->writeLog('end query (failed)'); |
if ($this->getOption('verbose')) { |
$this->_errorSet($res->getMessage()); |
} else { |
$this->_errorLog($res->getMessage()); |
} |
$this->_errorLog($res->getUserInfo(), __LINE__); |
return false; |
} else { |
$this->writeLog('end query'); |
} |
$res = $this->_makeIndexed($res); |
return $res; |
} |
// }}} |
// {{{ writeLog() |
/** |
* Write events to the logfile. |
* |
* It does some additional work, like time measuring etc. to |
* see some additional info |
* |
*/ |
function writeLog($text='START') |
{ |
//its still really a quicky.... 'refactor' (nice word) that |
if (!isset($this->options['logfile'])) { |
return; |
} |
include_once 'Log.php'; |
if (!class_exists('Log')) { |
return; |
} |
if (!$this->_logObject) { |
$this->_logObject =& Log::factory('file', $this->options['logfile']); |
} |
if ($text==='start query' || $text==='end query') { |
$bytesSent = $this->db->getAll("SHOW STATUS like 'Bytes_sent'"); |
$bytesSent = $bytesSent[0]['Value']; |
} |
if ($text==='START') { |
$startTime = split(' ', microtime()); |
$this->_logData['startTime'] = $startTime[1] + $startTime[0]; |
} |
if ($text==='start query') { |
$this->_logData['startBytesSent'] = $bytesSent; |
$startTime = split(' ', microtime()); |
$this->_logData['startQueryTime'] = $startTime[1] + $startTime[0]; |
return; |
} |
if ($text==='end query') { |
$text .= ' result size: '.((int)$bytesSent-(int)$this->_logData['startBytesSent']).' bytes'; |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$text .= ', took: '.(($endTime - $this->_logData['startQueryTime'])).' seconds'; |
} |
if (strpos($text, 'query built')===0) { |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$this->writeLog('query building took: '.(($endTime - $this->_logData['startTime'])).' seconds'); |
} |
$this->_logObject->log($text); |
if (strpos($text, 'end query')===0) { |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$text = 'time over all: '.(($endTime - $this->_logData['startTime'])).' seconds'; |
$this->_logObject->log($text); |
} |
} |
// }}} |
// {{{ returnResult() |
/** |
* Return the chosen result type |
* |
* @version 2004/04/28 |
* @access public |
* @param object reference |
* @return mixed |
*/ |
function returnResult(&$result) |
{ |
if ($this->_resultType == 'none') { |
return $result; |
} |
if ($result === false) { |
return false; |
} |
//what about allowing other (custom) result types? |
switch (strtolower($this->_resultType)) { |
case 'object': return new DB_QueryTool_Result_Object($result); |
case 'array': |
default: return new DB_QueryTool_Result($result); |
} |
} |
// }}} |
// {{{ _makeIndexed() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed |
* @return mixed |
*/ |
function &_makeIndexed(&$data) |
{ |
// we can only return an indexed result if the result has a number of columns |
if (is_array($data) && sizeof($data) && $key = $this->getIndex()) { |
// build the string to evaluate which might be made up out of multiple indexes of a result-row |
$evalString = '$val[\''.implode('\'].\',\'.$val[\'',explode(',',$key)).'\']'; //" |
$indexedData = array(); |
//FIXXME actually we also need to check ONCE if $val is an array, so to say if $data is 2-dimensional |
foreach ($data as $val) { |
eval("\$keyValue = $evalString;"); // get the actual real (string-)key (string if multiple cols are used as index) |
$indexedData[$keyValue] = $val; |
} |
unset($data); |
return $indexedData; |
} |
return $data; |
} |
// }}} |
// {{{ setIndex() |
/** |
* format the result to be indexed by $key |
* NOTE: be careful, when using this you should be aware, that if you |
* use an index which's value appears multiple times you may loose data |
* since a key cant exist multiple times!! |
* the result for a result to be indexed by a key(=columnName) |
* (i.e. 'relationtoMe') which's values are 'brother' and 'sister' |
* or alike normally returns this: |
* $res['brother'] = array('name'=>'xxx') |
* $res['sister'] = array('name'=>'xxx') |
* but if the column 'relationtoMe' contains multiple entries for 'brother' |
* then the returned dataset will only contain one brother, since the |
* value from the column 'relationtoMe' is used |
* and which 'brother' you get depends on a lot of things, like the sortorder, |
* how the db saves the data, and whatever else |
* |
* you can also set indexes which depend on 2 columns, simply pass the parameters like |
* 'table1.id,table2.id' it will be used as a string for indexing the result |
* and the index will be built using the 2 values given, so a possible |
* index might be '1,2' or '2108,29389' this way you can access data which |
* have 2 primary keys. Be sure to remember that the index is a string! |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function setIndex($key=null) |
{ |
if ($this->getJoin()) { // is join set? |
// replace TABLENAME.COLUMNNAME by _TABLENAME_COLUMNNAME |
// since this is only the result-keys can be used for indexing :-) |
$regExp = '/('.implode('|', $this->getJoin('tables')).')\.([^\s]+)/'; |
$key = preg_replace($regExp, '_$1_$2', $key); |
// remove the table name if it is in front of '<$this->table>.columnname' |
// since the key doesnt contain it neither |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$key = preg_replace('/'.$this->table.'\.'.$aCol.'/', $aCol, $key); |
} |
} |
} |
$this->_index = $key; |
} |
// }}} |
// {{{ getIndex() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function getIndex() |
{ |
return $this->_index; |
} |
// }}} |
// {{{ useResult() |
/** |
* Choose the type of the returned result |
* |
* @version 2004/04/28 |
* @access public |
* @param string $type ['array' | 'object' | 'none'] |
* For BC reasons, $type=true is equal to 'array', |
* $type=false is equal to 'none' |
*/ |
function useResult($type='array') |
{ |
if ($type === true) { |
$type = 'array'; |
} elseif ($type === false) { |
$type = 'none'; |
} |
switch (strtolower($type)) { |
case 'array': |
$this->_resultType = 'array'; |
require_once 'DB/QueryTool/Result.php'; |
break; |
case 'object': |
$this->_resultType = 'object'; |
require_once 'DB/QueryTool/Result/Object.php'; |
break; |
default: |
$this->_resultType = 'none'; |
} |
} |
// }}} |
// {{{ setErrorCallback() |
/** |
* set both callbacks |
* @param string |
*/ |
function setErrorCallback($param='') |
{ |
$this->setErrorLogCallback($param); |
$this->setErrorSetCallback($param); |
} |
// }}} |
// {{{ setErrorLogCallback() |
/** |
* @param string |
*/ |
function setErrorLogCallback($param='') |
{ |
$errorLogCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorLogCallback'); |
$errorLogCallback = $param; |
} |
// }}} |
// {{{ setErrorSetCallback() |
/** |
* @param string |
*/ |
function setErrorSetCallback($param='') |
{ |
$errorSetCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorSetCallback'); |
$errorSetCallback = $param; |
} |
// }}} |
// {{{ _errorLog() |
/** |
* sets error log and adds additional info |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the actual message, first word should always be the method name, |
* to build the message like this: className::methodname |
* @param integer the line number |
*/ |
function _errorLog($msg, $line='unknown') |
{ |
$this->_errorHandler('log', $msg, $line); |
/* |
if ($this->getOption('verbose') == true) |
{ |
$this->_errorLog(get_class($this)."::$msg ($line)"); |
return; |
} |
if ($this->_errorLogCallback) |
call_user_func($this->_errorLogCallback, $msg); |
*/ |
} |
// }}} |
// {{{ _errorSet() |
/** |
* @param string |
* @param string |
*/ |
function _errorSet($msg, $line='unknown') |
{ |
$this->_errorHandler('set', $msg, $line); |
} |
// }}} |
// {{{ _errorHandler() |
/** |
* @param |
* @param string |
* @param string |
*/ |
function _errorHandler($logOrSet, $msg, $line='unknown') |
{ |
/* what did i do this for? |
if ($this->getOption('verbose') == true) |
{ |
$this->_errorHandler($logOrSet, get_class($this)."::$msg ($line)"); |
return; |
} |
*/ |
$msg = get_class($this)."::$msg ($line)"; |
$logOrSet = ucfirst($logOrSet); |
$callback = &PEAR::getStaticProperty('DB_QueryTool','_error'.$logOrSet.'Callback'); |
//var_dump($callback); |
//if ($callback) |
// call_user_func($callback, $msg); |
// else |
// ????? |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's dbase extension |
* for interacting with dBase databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/DB/ldap.php |
---|
New file |
0,0 → 1,994 |
<?php |
// |
// Pear DB LDAP - Database independent query interface definition |
// for PHP's LDAP extension. |
// |
// Copyright (c) 2002-2003 Ludovico Magnocavallo <ludo@sumatrasolutions.com> |
// |
// This library is free software; you can redistribute it and/or |
// modify it under the terms of the GNU Lesser General Public |
// License as published by the Free Software Foundation; either |
// version 2.1 of the License, or (at your option) any later version. |
// |
// This library is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
// Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public |
// License along with this library; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// |
// Contributors |
// - Piotr Roszatycki <dexter@debian.org> |
// DB_ldap::base() method, support for LDAP sequences, various fixes |
// - Aaron Spencer Hawley <aaron dot hawley at uvm dot edu> |
// fix to use port number if present in DB_ldap->connect() |
// |
// $Id: ldap.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $ |
// |
require_once 'DB.php'; |
require_once 'DB/common.php'; |
define("DB_ERROR_BIND_FAILED", -26); |
define("DB_ERROR_UNKNOWN_LDAP_ACTION", -27); |
/** |
* LDAP result class |
* |
* LDAP_result extends DB_result to provide specific LDAP |
* result methods. |
* |
* @version 1.0 |
* @author Ludovico Magnocavallo <ludo@sumatrasolutions.com> |
* @package DB |
*/ |
class LDAP_result extends DB_result |
{ |
// {{{ properties |
/** |
* data returned from ldap_entries() |
* @access private |
*/ |
var $_entries = null; |
/** |
* result rows as hash of records |
* @access private |
*/ |
var $_recordset = null; |
/** |
* current record as hash |
* @access private |
*/ |
var $_record = null; |
// }}} |
// {{{ constructor |
/** |
* class constructor, calls DB_result constructor |
* @param ref $dbh reference to the db instance |
* @param resource $result ldap command result |
*/ |
function LDAP_result(&$dbh, $result) |
{ |
$this->DB_result($dbh, $result); |
} |
/** |
* fetch rows of data into $this->_recordset |
* |
* called once as soon as something needs to be returned |
* @access private |
* @param resource $result ldap command result |
* @return boolean true |
*/ |
function getRows() { |
if ($this->_recordset === null) { |
// begin processing result into recordset |
$this->_entries = ldap_get_entries($this->dbh->connection, $this->result); |
$this->row_counter = $this->_entries['count']; |
$i = 1; |
$rs_template = array(); |
if (count($this->dbh->attributes) > 0) { |
reset($this->dbh->attributes); |
while (list($a_index, $a_name) = each($this->dbh->attributes)) $rs_template[$a_name] = ''; |
} |
while (list($entry_idx, $entry) = each($this->_entries)) { |
// begin first loop, iterate through entries |
if (!empty($this->dbh->limit_from) && ($i < $this->dbh->limit_from)) continue; |
if (!empty($this->dbh->limit_count) && ($i > $this->dbh->limit_count)) break; |
$rs = $rs_template; |
if (!is_array($entry)) continue; |
while (list($attr, $attr_values) = each($entry)) { |
// begin second loop, iterate through attributes |
if (is_int($attr) || $attr == 'count') continue; |
if (is_string($attr_values)) $rs[$attr] = $attr_values; |
else { |
$value = ''; |
while (list($value_idx, $attr_value) = each($attr_values)) { |
// begin third loop, iterate through attribute values |
if (!is_int($value_idx)) continue; |
if (empty($value)) $value = $attr_value; |
else { |
if (is_array($value)) $value[] = $attr_value; |
else $value = array($value, $attr_value); |
} |
// else $value .= "\n$attr_value"; |
// end third loop |
} |
$rs[$attr] = $value; |
} |
// end second loop |
} |
reset($rs); |
$this->_recordset[$entry_idx] = $rs; |
$i++; |
// end first loop |
} |
$this->_entries = null; |
if (!is_array($this->_recordset)) |
$this->_recordset = array(); |
if (!empty($this->dbh->sorting)) { |
$sorting_method = (!empty($this->dbh->sorting_method) ? $this->dbh->sorting_method : 'cmp'); |
uksort($this->_recordset, array(&$this, $sorting_method)); |
} |
reset($this->_recordset); |
// end processing result into recordset |
} |
return DB_OK; |
} |
/** |
* Fetch and return a row of data (it uses driver->fetchInto for that) |
* @param int $fetchmode format of fetched row |
* @param int $rownum the row number to fetch |
* |
* @return array a row of data, NULL on no more rows or PEAR_Error on error |
* |
* @access public |
*/ |
function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null) |
{ |
$this->getRows(); |
if (count($this->_recordset) == 0) return null; |
if ($this->_record !== null) $this->_record = next($this->_recordset); |
else $this->_record = current($this->_recordset); |
$row = $this->_record; |
return $row; |
} |
/** |
* Fetch a row of data into an existing variable. |
* |
* @param mixed $arr reference to data containing the row |
* @param integer $fetchmode format of fetched row |
* @param integer $rownum the row number to fetch |
* |
* @return mixed DB_OK on success, NULL on no more rows or |
* a DB_Error object on error |
* |
* @access public |
*/ |
function fetchInto(&$ar, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) |
{ |
$this->getRows(); |
if ($this->_record !== null) $this->_record = next($this->_recordset); |
else $this->_record = current($this->_recordset); |
$ar = $this->_record; |
if (!$ar) { |
return null; |
} |
return DB_OK; |
} |
/** |
* return all records |
* |
* returns a hash of all records, basically returning |
* a copy of $this->_recordset |
* @param integer $fetchmode format of fetched row |
* @param integer $rownum the row number to fetch (not used, here for interface compatibility) |
* |
* @return mixed DB_OK on success, NULL on no more rows or |
* a DB_Error object on error |
* |
* @access public |
*/ |
function fetchAll($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) |
{ |
$this->getRows(); |
return($this->_recordset); |
} |
/** |
* Get the the number of columns in a result set. |
* |
* @return int the number of columns, or a DB error |
* |
* @access public |
*/ |
function numCols($result) |
{ |
$this->getRows(); |
return(count(array_keys($this->_record))); |
} |
function cmp($a, $b) |
{ |
return(strcmp(strtolower($this->_recordset[$a][$this->dbh->sorting]), strtolower($this->_recordset[$b][$this->dbh->sorting]))); |
} |
/** |
* Get the number of rows in a result set. |
* |
* @return int the number of rows, or a DB error |
* |
* @access public |
*/ |
function numRows() |
{ |
$this->getRows(); |
return $this->row_counter; |
} |
/** |
* Get the next result if a batch of queries was executed. |
* |
* @return bool true if a new result is available or false if not. |
* |
* @access public |
*/ |
function nextResult() |
{ |
return $this->dbh->nextResult($this->result); |
} |
/** |
* Frees the resources allocated for this result set. |
* @return int error code |
* |
* @access public |
*/ |
function free() |
{ |
$this->_recordset = null; |
$this->_record = null; |
ldap_free_result($this->result); |
$this->result = null; |
return true; |
} |
/** |
* @deprecated |
*/ |
function tableInfo($mode = null) |
{ |
return $this->dbh->tableInfo($this->result, $mode); |
} |
/** |
* returns the actual rows number |
* @return integer |
*/ |
function getRowCounter() |
{ |
$this->getRows(); |
return $this->row_counter; |
} |
} |
/** |
* LDAP DB interface class |
* |
* LDAP extends DB_common to provide DB compliant |
* access to LDAP servers |
* |
* @version 1.0 |
* @author Ludovico Magnocavallo <ludo@sumatrasolutions.com> |
* @package DB |
*/ |
class DB_ldap extends DB_common |
{ |
// {{{ properties |
/** |
* LDAP connection |
* @access private |
*/ |
var $connection; |
/** |
* base dn |
* @access private |
*/ |
var $base = ''; |
/** |
* default base dn |
* @access private |
*/ |
var $d_base = ''; |
/** |
* query base dn |
* @access private |
*/ |
var $q_base = ''; |
/** |
* array of LDAP actions that only manipulate data |
* returning a true/false value |
* @access private |
*/ |
var $manip = array('add', 'compare', 'delete', 'modify', 'mod_add', 'mod_del', 'mod_replace', 'rename'); |
/** |
* store the default real LDAP action to perform |
* @access private |
*/ |
var $action = 'search'; |
/** |
* store the real LDAP action to perform |
* (ie PHP ldap function to call) for a query |
* @access private |
*/ |
var $q_action = ''; |
/** |
* store optional parameters passed |
* to the real LDAP action |
* @access private |
*/ |
var $q_params = array(); |
// }}} |
/** |
* Constructor, calls DB_common constructor |
* |
* @see DB_common::DB_common() |
*/ |
function DB_ldap() |
{ |
$this->DB_common(); |
$this->phptype = 'ldap'; |
$this->dbsyntax = 'ldap'; |
$this->features = array( |
'prepare' => false, |
'pconnect' => false, |
'transactions' => false, |
'limit' => false |
); |
$this->errorcode_map = array( |
0x10 => DB_ERROR_NOSUCHFIELD, // LDAP_NO_SUCH_ATTRIBUTE |
0x11 => DB_ERROR_INVALID, // LDAP_UNDEFINED_TYPE |
0x12 => DB_ERROR_INVALID, // LDAP_INAPPROPRIATE_MATCHING |
0x13 => DB_ERROR_INVALID, // LDAP_CONSTRAINT_VIOLATION |
0x14 => DB_ERROR_ALREADY_EXISTS, // LDAP_TYPE_OR_VALUE_EXISTS |
0x15 => DB_ERROR_INVALID, // LDAP_INVALID_SYNTAX |
0x20 => DB_ERROR_NOT_FOUND, // LDAP_NO_SUCH_OBJECT |
0x21 => DB_ERROR_NOT_FOUND, // LDAP_ALIAS_PROBLEM |
0x22 => DB_ERROR_INVALID, // LDAP_INVALID_DN_SYNTAX |
0x23 => DB_ERROR_INVALID, // LDAP_IS_LEAF |
0x24 => DB_ERROR_INVALID, // LDAP_ALIAS_DEREF_PROBLEM |
0x30 => DB_ERROR_ACCESS_VIOLATION, // LDAP_INAPPROPRIATE_AUTH |
0x31 => DB_ERROR_ACCESS_VIOLATION, // LDAP_INVALID_CREDENTIALS |
0x32 => DB_ERROR_ACCESS_VIOLATION, // LDAP_INSUFFICIENT_ACCESS |
0x40 => DB_ERROR_MISMATCH, // LDAP_NAMING_VIOLATION |
0x41 => DB_ERROR_MISMATCH, // LDAP_OBJECT_CLASS_VIOLATION |
0x44 => DB_ERROR_ALREADY_EXISTS, // LDAP_ALREADY_EXISTS |
0x51 => DB_ERROR_CONNECT_FAILED, // LDAP_SERVER_DOWN |
0x57 => DB_ERROR_SYNTAX // LDAP_FILTER_ERROR |
); |
} |
/** |
* Connect and bind to LDAP server with either anonymous or authenticated bind depending on dsn info |
* |
* @param array $dsninfo dsn info as passed by DB::connect() |
* @param boolean $persistent kept for interface compatibility |
* @return DB_OK if successfully connected. A DB error code is returned on failure. |
*/ |
function connect($dsninfo, $persistent = false) |
{ |
if (!PEAR::loadExtension('ldap')) |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
$this->dsn = $dsninfo; |
$user = $dsninfo['username']; |
$pw = $dsninfo['password']; |
$host = $dsninfo['hostspec']; |
$port = $dsninfo['port']; |
$this->base = $dsninfo['database']; |
$this->d_base = $this->base; |
if (empty($host)) { |
return $this->raiseError("no host specified $host"); |
} // else ... |
if (isset($port)) { |
$conn = ldap_connect($host, $port); |
} else { |
$conn = ldap_connect($host); |
} |
if (!$conn) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED); |
} |
if ($user && $pw) { |
$bind = @ldap_bind($conn, $user, $pw); |
} else { |
$bind = @ldap_bind($conn); |
} |
if (!$bind) { |
return $this->raiseError(DB_ERROR_BIND_FAILED); |
} |
$this->connection = $conn; |
return DB_OK; |
} |
/** |
* Unbinds from LDAP server |
* |
* @return int ldap_unbind() return value |
*/ |
function disconnect() |
{ |
$ret = @ldap_unbind($this->connection); |
$this->connection = null; |
return $ret; |
} |
/** |
* Performs a request against the LDAP server |
* |
* The type of request (and the corresponding PHP ldap function called) |
* depend on two additional parameters, added in respect to the |
* DB_common interface. |
* |
* @param string $filter text of the request to send to the LDAP server |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return result from ldap function or DB Error object if no result |
*/ |
function simpleQuery($filter, $action = null, $params = null) |
{ |
if ($action === null) { |
$action = (!empty($this->q_action) ? $this->q_action : $this->action); |
} |
if ($params === null) { |
$params = (count($this->q_params) > 0 ? $this->q_params : array()); |
} |
if (!$this->isManip($action)) { |
$base = $this->q_base ? $this->q_base : $this->base; |
$attributes = array(); |
$attrsonly = 0; |
$sizelimit = 0; |
$timelimit = 0; |
$deref = LDAP_DEREF_NEVER; |
$sorting = ''; |
$sorting_method = ''; |
reset($params); |
while (list($k, $v) = each($params)) { |
if (isset(${$k})) ${$k} = $v; |
} |
$this->sorting = $sorting; |
$this->sorting_method = $sorting_method; |
$this->attributes = $attributes; |
# double escape char for filter: '(o=Przedsi\C4\99biorstwo)' => '(o=Przedsi\\C4\\99biorstwo)' |
$filter = str_replace('\\', '\\\\', $filter); |
$this->last_query = $filter; |
if ($action == 'search') |
$result = @ldap_search($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref); |
else if ($action == 'list') |
$result = @ldap_list($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref); |
else if ($action == 'read') |
$result = @ldap_read($this->connection, $base, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref); |
else |
return $this->ldapRaiseError(DB_ERROR_UNKNOWN_LDAP_ACTION); |
if (!$result) { |
return $this->ldapRaiseError(); |
} |
} else { |
# If first argument is an array, it contains the entry with DN. |
if (is_array($filter)) { |
$entry = $filter; |
$filter = $entry["dn"]; |
} else { |
$entry = array(); |
} |
unset($entry["dn"]); |
$attribute = ''; |
$value = ''; |
$newrdn = ''; |
$newparent = ''; |
$deleteoldrdn = false; |
reset($params); |
while (list($k, $v) = each($params)) { |
if (isset(${$k})) ${$k} = $v; |
} |
$this->last_query = $filter; |
if ($action == 'add') |
$result = @ldap_add($this->connection, $filter, $entry); |
else if ($action == 'compare') |
$result = @ldap_add($this->connection, $filter, $attribute, $value); |
else if ($action == 'delete') |
$result = @ldap_delete($this->connection, $filter); |
else if ($action == 'modify') |
$result = @ldap_modify($this->connection, $filter, $entry); |
else if ($action == 'mod_add') |
$result = @ldap_mod_add($this->connection, $filter, $entry); |
else if ($action == 'mod_del') |
$result = @ldap_mod_del($this->connection, $filter, $entry); |
else if ($action == 'mod_replace') |
$result = @ldap_mod_replace($this->connection, $filter, $entry); |
else if ($action == 'rename') |
$result = @ldap_rename($this->connection, $filter, $newrdn, $newparent, $deleteoldrdn); |
else |
return $this->ldapRaiseError(DB_ERROR_UNKNOWN_LDAP_ACTION); |
if (!$result) { |
return $this->ldapRaiseError(); |
} |
} |
$this->freeQuery(); |
return $result; |
} |
/** |
* Executes a query performing variables substitution in the query text |
* |
* @param string $stmt text of the request to send to the LDAP server |
* @param array $data query variables values to substitute |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return LDAP_result object or DB Error object if no result |
* @see DB_common::executeEmulateQuery $this->simpleQuery() |
*/ |
function execute($stmt, $data = false, $action = null, $params = array()) |
{ |
$this->q_params = $params; |
$realquery = $this->executeEmulateQuery($stmt, $data); |
if (DB::isError($realquery)) { |
return $realquery; |
} |
$result = $this->simpleQuery($realquery); |
if (DB::isError($result) || $result === DB_OK) { |
return $result; |
} else { |
return new LDAP_result($this, $result); |
} |
} |
/** |
* Executes multiple queries performing variables substitution for each query |
* |
* @param string $stmt text of the request to send to the LDAP server |
* @param array $data query variables values to substitute |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return LDAP_result object or DB Error object if no result |
* @see DB_common::executeMultiple |
*/ |
function executeMultiple($stmt, &$data, $action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::executeMultiple($stmt, $data)); |
} |
/** |
* Executes a query substituting variables if any are present |
* |
* @param string $query text of the request to send to the LDAP server |
* @param array $data query variables values to substitute |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return LDAP_result object or DB Error object if no result |
* @see DB_common::prepare() $this->execute()$this->simpleQuery() |
*/ |
function &query($query, $data = array(), $action = null, $params = array()) { |
// $this->q_action = $action ? $action : $this->action; |
// $this->q_params = $params; |
if (sizeof($data) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
return $this->execute($sth, $data); |
} else { |
$result = $this->simpleQuery($query); |
if (DB::isError($result) || $result === DB_OK) { |
return $result; |
} else { |
return new LDAP_result($this, $result); |
} |
} |
} |
/** |
* Modifies a query to return only a set of rows, stores $from and $count for LDAP_result |
* |
* @param string $query text of the request to send to the LDAP server |
* @param int $from record position from which to start returning data |
* @param int $count number of records to return |
* @return modified query text (no modifications are made, see above) |
*/ |
function modifyLimitQuery($query, $from, $count) |
{ |
$this->limit_from = $from; |
$this->limit_count = $count; |
return $query; |
} |
/** |
* Executes a query returning only a specified number of rows |
* |
* This method only saves the $from and $count parameters for LDAP_result |
* where the actual records processing takes place |
* |
* @param string $query text of the request to send to the LDAP server |
* @param int $from record position from which to start returning data |
* @param int $count number of records to return |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return LDAP_result object or DB Error object if no result |
*/ |
function limitQuery($query, $from, $count, $action = null, $params = array()) |
{ |
$query = $this->modifyLimitQuery($query, $from, $count); |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return $this->query($query, $action, $params); |
} |
/** |
* Fetch the first column of the first row of data returned from |
* a query. Takes care of doing the query and freeing the results |
* when finished. |
* |
* @param $query the SQL query |
* @param $data if supplied, prepare/execute will be used |
* with this array as execute parameters |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @return array |
* @see DB_common::getOne() |
* @access public |
*/ |
function &getOne($query, $data = array(), $action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::getOne($query, $data)); |
} |
/** |
* Fetch the first row of data returned from a query. Takes care |
* of doing the query and freeing the results when finished. |
* |
* @param $query the SQL query |
* @param $fetchmode the fetch mode to use |
* @param $data array if supplied, prepare/execute will be used |
* with this array as execute parameters |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @access public |
* @return array the first row of results as an array indexed from |
* 0, or a DB error code. |
* @see DB_common::getRow() |
* @access public |
*/ |
function &getRow($query, |
$data = null, |
$fetchmode = DB_FETCHMODE_DEFAULT, |
$action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::getRow($query, $data, $fetchmode)); |
} |
/** |
* Fetch the first column of data returned from a query. Takes care |
* of doing the query and freeing the results when finished. |
* |
* @param $query the SQL query |
* @param $col which column to return (integer [column number, |
* starting at 0] or string [column name]) |
* @param $data array if supplied, prepare/execute will be used |
* with this array as execute parameters |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @access public |
* @return array an indexed array with the data from the first |
* row at index 0, or a DB error code. |
* @see DB_common::getCol() |
* @access public |
*/ |
function &getCol($query, $col = 0, $data = array(), $action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::getCol($query, $col, $data)); |
} |
/** |
* Calls DB_common::getAssoc() |
* |
* @param $query the SQL query |
* @param $force_array (optional) 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. |
* starting at 0] or string [column name]) |
* @param array $data if supplied, prepare/execute will be used |
* with this array as execute parameters |
* @param $fetchmode the fetch mode to use |
* @param boolean $group see DB_Common::getAssoc() |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @access public |
* @return array an indexed array with the data from the first |
* row at index 0, or a DB error code. |
* @see DB_common::getAssoc() |
* @access public |
*/ |
function &getAssoc($query, $force_array = false, $data = array(), |
$fetchmode = DB_FETCHMODE_ORDERED, $group = false, |
$action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::getAssoc($query, $force_array, $data, $fetchmode, $group)); |
} |
/** |
* Fetch all the rows returned from a query. |
* |
* @param $query the SQL query |
* @param array $data if supplied, prepare/execute will be used |
* with this array as execute parameters |
* @param $fetchmode the fetch mode to use |
* @param string $action type of request to perform, defaults to search (ldap_search()) |
* @param array $params array of additional parameters to pass to the PHP ldap function requested |
* @access public |
* @return array an nested array, or a DB error |
* @see DB_common::getAll() |
*/ |
function &getAll($query, |
$data = null, |
$fetchmode = DB_FETCHMODE_DEFAULT, |
$action = null, $params = array()) |
{ |
$this->q_action = $action ? $action : $this->action; |
$this->q_params = $params; |
return(parent::getAll($query, $data, $fetchmode)); |
} |
function numRows($result) |
{ |
return $result->numRows(); |
} |
function getTables() |
{ |
return $this->ldapRaiseError(DB_ERROR_NOT_CAPABLE); |
} |
function getListOf($type) |
{ |
return $this->ldapRaiseError(DB_ERROR_NOT_CAPABLE); |
} |
function isManip($action) |
{ |
return(in_array($action, $this->manip)); |
} |
function freeResult() |
{ |
return true; |
} |
function freeQuery($query = '') |
{ |
$this->q_action = ''; |
$this->q_base = ''; |
$this->q_params = array(); |
$this->attributes = null; |
$this->sorting = ''; |
return true; |
} |
// Deprecated, will be removed in future releases. |
function base($base = null) |
{ |
$this->q_base = ($base !== null) ? $base : null; |
return true; |
} |
function ldapSetBase($base = null) |
{ |
$this->base = ($base !== null) ? $base : $this->d_base; |
$this->q_base = ''; |
return true; |
} |
function ldapSetAction($action = 'search') |
{ |
if ($action != 'search' && $action != 'list' && $action != 'read') { |
return $this->ldapRaiseError(DB_ERROR_UNKNOWN_LDAP_ACTION); |
} |
$this->action = $action; |
$this->q_action = ''; |
return true; |
} |
/** |
* Get the next value in a sequence. |
* |
* LDAP provides transactions for only one entry and we need to |
* prevent race condition. If unique value before and after modify |
* aren't equal then wait and try again. |
* |
* The name of sequence is LDAP DN of entry. |
* |
* @access public |
* @param string $seq_name the DN of the sequence |
* @param bool $ondemand whether to create the sequence on demand |
* @return a sequence integer, or a DB error |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$repeat = 0; |
do { |
// Get the sequence entry |
$this->base($seq_name); |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$data = $this->getRow("objectClass=*"); |
$this->popErrorHandling(); |
if (DB::isError($data)) { |
// DB_ldap doesn't use DB_ERROR_NOT_FOUND |
if ($ondemand && $repeat == 0 |
&& $data->getCode() == DB_ERROR) { |
// Try to create sequence and repeat |
$repeat = 1; |
$data = $this->createSequence($seq_name); |
if (DB::isError($data)) { |
return $this->ldapRaiseError($data); |
} |
} else { |
// Other error |
return $this->ldapRaiseError($data); |
} |
} else { |
// Increment sequence value |
$data["cn"]++; |
// Unique identificator of transaction |
$seq_unique = mt_rand(); |
$data["uid"] = $seq_unique; |
// Modify the LDAP entry |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$data = $this->simpleQuery($data, 'modify'); |
$this->popErrorHandling(); |
if (DB::isError($data)) { |
return $this->ldapRaiseError($data); |
} |
// Get the entry and check if it contains our unique value |
$this->base($seq_name); |
$data = $this->getRow("objectClass=*"); |
if (DB::isError($data)) { |
return $this->ldapRaiseError($data); |
} |
if ($data["uid"] != $seq_unique) { |
// It is not our entry. Wait a little time and repeat |
sleep(1); |
$repeat = 1; |
} else { |
$repeat = 0; |
} |
} |
} while ($repeat); |
if (DB::isError($data)) { |
return $data; |
} |
return $data["cn"]; |
} |
/** |
* Create the sequence |
* |
* The sequence entry is based on core schema with extensibleObject, |
* so it should work with any LDAP server which doesn't check schema |
* or supports extensibleObject object class. |
* |
* Sequence name have to be DN started with "sn=$seq_id,", i.e.: |
* |
* $seq_name = "sn=uidNumber,ou=sequences,dc=php,dc=net"; |
* |
* dn: $seq_name |
* objectClass: top |
* objectClass: extensibleObject |
* sn: $seq_id |
* cn: $seq_value |
* uid: $seq_uniq |
* |
* @param string $seq_name the DN of the sequence |
* @return mixed DB_OK on success or DB error on error |
* @access public |
*/ |
function createSequence($seq_name) |
{ |
// Extract $seq_id from DN |
ereg("^([^,]*),", $seq_name, $regs); |
$seq_id = $regs[1]; |
// Create the sequence entry |
$data = array( |
dn => $seq_name, |
objectclass => array("top", "extensibleObject"), |
sn => $seq_id, |
cn => 0, |
uid => 0 |
); |
// Add the LDAP entry |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$data = $this->simpleQuery($data, 'add'); |
$this->popErrorHandling(); |
return $data; |
} |
/** |
* Drop a sequence |
* |
* @param string $seq_name the DN of the sequence |
* @return mixed DB_OK on success or DB error on error |
* @access public |
*/ |
function dropSequence($seq_name) |
{ |
// Delete the sequence entry |
$data = array( |
dn => $seq_name, |
); |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$data = $this->simpleQuery($data, 'delete'); |
$this->popErrorHandling(); |
return $data; |
} |
// {{{ ldapRaiseError() |
function ldapRaiseError($errno = null) |
{ |
if ($errno === null) { |
$errno = $this->errorCode(ldap_errno($this->connection)); |
} |
if ($this->q_action !== null) { |
return $this->raiseError($errno, null, null, |
sprintf('%s base="%s" filter="%s"', |
$this->q_action, $this->q_base, $this->last_query |
), |
$errno == DB_ERROR_UNKNOWN_LDAP_ACTION ? null : @ldap_error($this->connection)); |
} else { |
return $this->raiseError($errno, null, null, "???", |
@ldap_error($this->connection)); |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Auth.php |
---|
New file |
0,0 → 1,1118 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ |
/** |
* The main include file for Auth package |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.01 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_01.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 Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version CVS: $Id: Auth.php,v 1.2 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/Auth |
*/ |
/** |
* Returned if session exceeds idle time |
*/ |
define('AUTH_IDLED', -1); |
/** |
* Returned if session has expired |
*/ |
define('AUTH_EXPIRED', -2); |
/** |
* Returned if container is unable to authenticate user/password pair |
*/ |
define('AUTH_WRONG_LOGIN', -3); |
/** |
* Returned if a container method is not supported. |
*/ |
define('AUTH_METHOD_NOT_SUPPORTED', -4); |
/** |
* Returned if new Advanced security system detects a breach |
*/ |
define('AUTH_SECURITY_BREACH', -5); |
/** |
* Returned if checkAuthCallback says session should not continue. |
*/ |
define('AUTH_CALLBACK_ABORT', -6); |
/** |
* PEAR::Auth |
* |
* The PEAR::Auth class provides methods for creating an |
* authentication system using PHP. |
* |
* @category Authentication |
* @package Auth |
* @author Martin Jansen <mj@php.net> |
* @author Adam Ashley <aashley@php.net> |
* @copyright 2001-2006 The PHP Group |
* @license http://www.php.net/license/3_01.txt PHP License 3.01 |
* @version Release: 1.4.3 File: $Revision: 1.2 $ |
* @link http://pear.php.net/package/Auth |
*/ |
class Auth { |
// {{{ properties |
/** |
* 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() |
*/ |
var $expired = false; |
/** |
* Maximum idletime in seconds |
* |
* The difference to $expire is, that the idletime gets |
* refreshed each time checkAuth() is called. If this |
* variable is set to 0, idletime is never checked. |
* |
* @var integer |
* @see setIdle(), checkAuth() |
*/ |
var $idle = 0; |
/** |
* Is the maximum idletime over? |
* |
* @var boolean |
* @see checkAuth() |
*/ |
var $idled = false; |
/** |
* Storage object |
* |
* @var object |
* @see Auth(), validateLogin() |
*/ |
var $storage = ''; |
/** |
* User-defined function that creates the login screen |
* |
* @var string |
*/ |
var $loginFunction = ''; |
/** |
* Should the login form be displayed |
* |
* @var bool |
* @see setShowlogin() |
*/ |
var $showLogin = true; |
/** |
* Is Login Allowed from this page |
* |
* @var bool |
* @see setAllowLogin |
*/ |
var $allowLogin = true; |
/** |
* Current authentication status |
* |
* @var string |
*/ |
var $status = ''; |
/** |
* Username |
* |
* @var string |
*/ |
var $username = ''; |
/** |
* Password |
* |
* @var string |
*/ |
var $password = ''; |
/** |
* checkAuth callback function name |
* |
* @var string |
* @see setCheckAuthCallback() |
*/ |
var $checkAuthCallback = ''; |
/** |
* Login callback function name |
* |
* @var string |
* @see setLoginCallback() |
*/ |
var $loginCallback = ''; |
/** |
* Failed Login callback function name |
* |
* @var string |
* @see setFailedLoginCallback() |
*/ |
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 = "@version@"; |
/** |
* Flag to use advanced security |
* When set extra checks will be made to see if the |
* user's IP or useragent have changed across requests. |
* Turned off by default to preserve BC. |
* |
* @var boolean |
*/ |
var $advancedsecurity = false; |
/** |
* Username key in POST array |
* |
* @var string |
*/ |
var $_postUsername = 'username'; |
/** |
* Password key in POST array |
* |
* @var string |
*/ |
var $_postPassword = 'password'; |
/** |
* Holds a reference to the session auth variable |
* @var array |
*/ |
var $session; |
/** |
* Holds a reference to the global server variable |
* @var array |
*/ |
var $server; |
/** |
* Holds a reference to the global post variable |
* @var array |
*/ |
var $post; |
/** |
* Holds a reference to the global cookie variable |
* @var array |
*/ |
var $cookie; |
/** |
* A hash to hold various superglobals as reference |
* @var array |
*/ |
var $authdata; |
/** |
* How many times has checkAuth been called |
* var int |
*/ |
var $authChecks = 0; |
// }}} |
// {{{ Auth() [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) |
{ |
$this->applyAuthOptions($options); |
// Start the session suppress error if already started |
if(!session_id()){ |
@session_start(); |
if(!session_id()) { |
// Throw error |
include_once 'PEAR.php'; |
PEAR::throwError('Session could not be started by Auth, ' |
.'possibly headers are already sent, try putting ' |
.'ob_start in the beginning of your script'); |
} |
} |
// Make Sure Auth session variable is there |
if(!isset($_SESSION[$this->_sessionName])) { |
$_SESSION[$this->_sessionName] = array(); |
} |
// Assign Some globals to internal references, this will replace _importGlobalVariable |
$this->session =& $_SESSION[$this->_sessionName]; |
$this->server =& $_SERVER; |
$this->post =& $_POST; |
$this->cookie =& $_COOKIE; |
if ($loginFunction != '' && is_callable($loginFunction)) { |
$this->loginFunction = $loginFunction; |
} |
if (is_bool($showLogin)) { |
$this->showLogin = $showLogin; |
} |
if (is_object($storageDriver)) { |
$this->storage =& $storageDriver; |
// 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; |
} else { |
// $this->storage = $this->_factory($storageDriver, $options); |
// |
$this->storage_driver = $storageDriver; |
$this->storage_options =& $options; |
} |
} |
// }}} |
// {{{ applyAuthOptions() |
/** |
* Set the Auth options |
* |
* Some options which are Auth specific will be applied |
* the rest will be left for usage by the container |
* |
* @param array An array of Auth options |
* @return array The options which were not applied |
* @access private |
*/ |
function &applyAuthOptions(&$options) |
{ |
if(is_array($options)){ |
if (!empty($options['sessionName'])) { |
$this->_sessionName = $options['sessionName']; |
unset($options['sessionName']); |
} |
if (isset($options['allowLogin'])) { |
$this->allowLogin = $options['allowLogin']; |
unset($options['allowLogin']); |
} |
if (!empty($options['postUsername'])) { |
$this->_postUsername = $options['postUsername']; |
unset($options['postUsername']); |
} |
if (!empty($options['postPassword'])) { |
$this->_postPassword = $options['postPassword']; |
unset($options['postPassword']); |
} |
if (isset($options['advancedsecurity'])) { |
$this->advancedsecurity = $options['advancedsecurity']; |
unset($options['advancedsecurity']); |
} |
} |
return($options); |
} |
// }}} |
// {{{ _loadStorage() |
/** |
* Load Storage Driver if not already loaded |
* |
* Suspend storage instantiation to make Auth lighter to use |
* for calls which do not require login |
* |
* @return bool True if the conainer is loaded, false if the container |
* is already loaded |
* @access private |
*/ |
function _loadStorage() |
{ |
if(!is_object($this->storage)) { |
$this->storage =& $this->_factory($this->storage_driver, |
$this->storage_options); |
$this->storage->_auth_obj =& $this; |
return(true); |
} |
return(false); |
} |
// }}} |
// {{{ _factory() |
/** |
* Return a storage driver based on $driver and $options |
* |
* @static |
* @param string $driver Type of storage class to return |
* @param string $options Optional parameters for the storage class |
* @return object Object Storage object |
* @access private |
*/ |
function &_factory($driver, $options = '') |
{ |
$storage_class = 'Auth_Container_' . $driver; |
include_once 'Auth/Container/' . $driver . '.php'; |
$obj =& new $storage_class($options); |
return $obj; |
} |
// }}} |
// {{{ assignData() |
/** |
* Assign data from login form to internal values |
* |
* This function takes the values for username and password |
* from $HTTP_POST_VARS/$_POST and assigns them to internal variables. |
* If you wish to use another source apart from $HTTP_POST_VARS/$_POST, |
* you have to derive this function. |
* |
* @global $HTTP_POST_VARS, $_POST |
* @see Auth |
* @return void |
* @access private |
*/ |
function assignData() |
{ |
if ( isset($this->post[$this->_postUsername]) |
&& $this->post[$this->_postUsername] != '') { |
$this->username = (get_magic_quotes_gpc() == 1 |
? stripslashes($this->post[$this->_postUsername]) |
: $this->post[$this->_postUsername]); |
} |
if ( isset($this->post[$this->_postPassword]) |
&& $this->post[$this->_postPassword] != '') { |
$this->password = (get_magic_quotes_gpc() == 1 |
? stripslashes($this->post[$this->_postPassword]) |
: $this->post[$this->_postPassword] ); |
} |
} |
// }}} |
// {{{ start() |
/** |
* Start new auth session |
* |
* @return void |
* @access public |
*/ |
function start() |
{ |
$this->assignData(); |
if (!$this->checkAuth() && $this->allowLogin) { |
$this->login(); |
} |
} |
// }}} |
// {{{ login() |
/** |
* Login function |
* |
* @return void |
* @access private |
*/ |
function login() |
{ |
$login_ok = false; |
$this->_loadStorage(); |
// Check if using challenge response |
(isset($this->post['authsecret']) && $this->post['authsecret'] == 1) |
? $usingChap = true |
: $usingChap = 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, $usingChap)) { |
$this->session['challengekey'] = md5($this->username.$this->password); |
$login_ok = true; |
} |
} |
if (!empty($this->username) && $login_ok) { |
$this->setAuth($this->username); |
if (is_callable($this->loginCallback)) { |
call_user_func_array($this->loginCallback, array($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 (is_callable($this->loginFailedCallback)) { |
call_user_func_array($this->loginFailedCallback, array($this->username, &$this)); |
} |
} |
if ((empty($this->username) || !$login_ok) && $this->showLogin) { |
if (is_callable($this->loginFunction)) { |
call_user_func_array($this->loginFunction, array($this->username, $this->status, &$this)); |
} else { |
// BC fix Auth used to use drawLogin for this |
// call is sub classes implement this |
if (is_callable(array($this, 'drawLogin'))) { |
return $this->drawLogin($this->username, $this); |
} |
// New Login form |
include_once 'Auth/Frontend/Html.php'; |
return Auth_Frontend_Html::render($this, $this->username); |
} |
} else { |
return; |
} |
} |
// }}} |
// {{{ setExpire() |
/** |
* Set the maximum expire time |
* |
* @param integer time in seconds |
* @param bool add time to current expire time or not |
* @return void |
* @access public |
*/ |
function setExpire($time, $add = false) |
{ |
$add ? $this->expire += $time : $this->expire = $time; |
} |
// }}} |
// {{{ setIdle() |
/** |
* Set the maximum idle time |
* |
* @param integer time in seconds |
* @param bool add time to current maximum idle time or not |
* @return void |
* @access public |
*/ |
function setIdle($time, $add = false) |
{ |
$add ? $this->idle += $time : $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. |
* This will chnage the name of the session variable |
* auth uses to store it's data in the session |
* |
* @param string New name for the session |
* @return void |
* @access public |
*/ |
function setSessionName($name = 'session') |
{ |
$this->_sessionName = '_auth_'.$name; |
$this->session =& $_SESSION[$this->_sessionName]; |
} |
// }}} |
// {{{ setShowLogin() |
/** |
* Should the login form be displayed if neccessary? |
* |
* @param bool show login form or not |
* @return void |
* @access public |
*/ |
function setShowLogin($showLogin = true) |
{ |
$this->showLogin = $showLogin; |
} |
// }}} |
// {{{ setAllowLogin() |
/** |
* Should the login form be displayed if neccessary? |
* |
* @param bool show login form or not |
* @return void |
* @access public |
*/ |
function setAllowLogin($allowLogin = true) |
{ |
$this->allowLogin = $allowLogin; |
} |
// }}} |
// {{{ setCheckAuthCallback() |
/** |
* Register a callback function to be called whenever the validity of the login is checked |
* The function will receive two parameters, the username and a reference to the auth object. |
* |
* @param string callback function name |
* @return void |
* @access public |
* @since Method available since Release 1.4.3 |
*/ |
function setCheckAuthCallback($checkAuthCallback) |
{ |
$this->checkAuthCallback = $checkAuthCallback; |
} |
// }}} |
// {{{ setLoginCallback() |
/** |
* 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. |
* |
* @param string callback function name |
* @return void |
* @see setLogoutCallback() |
* @access public |
*/ |
function setLoginCallback($loginCallback) |
{ |
$this->loginCallback = $loginCallback; |
} |
// }}} |
// {{{ setFailedLoginCallback() |
/** |
* Register a callback function to be called on failed user login. |
* The function will receive two parameters, the username and a reference to the auth object. |
* |
* @param string callback function name |
* @return void |
* @access public |
*/ |
function setFailedLoginCallback($loginFailedCallback) |
{ |
$this->loginFailedCallback = $loginFailedCallback; |
} |
// }}} |
// {{{ setLogoutCallback() |
/** |
* 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. |
* |
* @param string callback function name |
* @return void |
* @see setLoginCallback() |
* @access public |
*/ |
function setLogoutCallback($logoutCallback) |
{ |
$this->logoutCallback = $logoutCallback; |
} |
// }}} |
// {{{ setAuthData() |
/** |
* Register additional information that is to be stored |
* in the session. |
* |
* @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 |
* @access public |
*/ |
function setAuthData($name, $value, $overwrite = true) |
{ |
if (!empty($this->session['data'][$name]) && $overwrite == false) { |
return; |
} |
$this->session['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. |
* |
* @param string Name of the data field |
* @return mixed Value of the data field. |
* @access public |
*/ |
function getAuthData($name = null) |
{ |
if (!isset($this->session['data'])) { |
return null; |
} |
if(!isset($name)) { |
return $this->session['data']; |
} |
if (isset($name) && isset($this->session['data'][$name])) { |
return $this->session['data'][$name]; |
} |
return null; |
} |
// }}} |
// {{{ setAuth() |
/** |
* Register variable in a session telling that the user |
* has logged in successfully |
* |
* @param string Username |
* @return void |
* @access public |
*/ |
function setAuth($username) |
{ |
// #2021 - Change the session id to avoid session fixation attacks php 4.3.3 > |
session_regenerate_id(true); |
if (!isset($this->session) || !is_array($this->session)) { |
$this->session = array(); |
} |
if (!isset($this->session['data'])) { |
$this->session['data'] = array(); |
} |
$this->session['sessionip'] = isset($this->server['REMOTE_ADDR']) |
? $this->server['REMOTE_ADDR'] |
: ''; |
$this->session['sessionuseragent'] = isset($this->server['HTTP_USER_AGENT']) |
? $this->server['HTTP_USER_AGENT'] |
: ''; |
// This should be set by the container to something more safe |
// Like md5(passwd.microtime) |
if(empty($this->session['challengekey'])) { |
$this->session['challengekey'] = md5($username.microtime()); |
} |
$this->session['challengecookie'] = md5($this->session['challengekey'].microtime()); |
setcookie('authchallenge', $this->session['challengecookie']); |
$this->session['registered'] = true; |
$this->session['username'] = $username; |
$this->session['timestamp'] = time(); |
$this->session['idle'] = time(); |
} |
// }}} |
// {{{ setAdvancedSecurity() |
/** |
* Enables advanced security checks |
* |
* Currently only ip change and useragent change |
* are detected |
* @todo Add challenge cookies - Create a cookie which changes every time |
* and contains some challenge key which the server can verify with |
* a session var cookie might need to be crypted (user pass) |
* @param bool Enable or disable |
* @return void |
* @access public |
*/ |
function setAdvancedSecurity($flag=true) |
{ |
$this->advancedsecurity = $flag; |
} |
// }}} |
// {{{ checkAuth() |
/** |
* Checks if there is a session with valid auth information. |
* |
* @access public |
* @return boolean Whether or not the user is authenticated. |
*/ |
function checkAuth() |
{ |
$this->authChecks++; |
if (isset($this->session)) { |
// Check if authentication session is expired |
if ( $this->expire > 0 |
&& isset($this->session['timestamp']) |
&& ($this->session['timestamp'] + $this->expire) < time()) { |
$this->expired = true; |
$this->status = AUTH_EXPIRED; |
$this->logout(); |
return false; |
} |
// Check if maximum idle time is reached |
if ( $this->idle > 0 |
&& isset($this->session['idle']) |
&& ($this->session['idle'] + $this->idle) < time()) { |
$this->idled = true; |
$this->status = AUTH_IDLED; |
$this->logout(); |
return false; |
} |
if ( isset($this->session['registered']) |
&& isset($this->session['username']) |
&& $this->session['registered'] == true |
&& $this->session['username'] != '') { |
Auth::updateIdle(); |
if ($this->advancedsecurity) { |
// Only Generate the challenge once |
if($this->authChecks == 1) { |
$this->session['challengecookieold'] = $this->session['challengecookie']; |
$this->session['challengecookie'] = md5($this->session['challengekey'].microtime()); |
setcookie('authchallenge', $this->session['challengecookie']); |
} |
// Check for ip change |
if ( isset($this->server['REMOTE_ADDR']) |
&& $this->session['sessionip'] != $this->server['REMOTE_ADDR']) { |
// Check if the IP of the user has changed, if so we |
// assume a man in the middle attack and log him out |
$this->expired = true; |
$this->status = AUTH_SECURITY_BREACH; |
$this->logout(); |
return false; |
} |
// Check for useragent change |
if ( isset($this->server['HTTP_USER_AGENT']) |
&& $this->session['sessionuseragent'] != $this->server['HTTP_USER_AGENT']) { |
// Check if the User-Agent of the user has changed, if |
// so we assume a man in the middle attack and log him out |
$this->expired = true; |
$this->status = AUTH_SECURITY_BREACH; |
$this->logout(); |
return false; |
} |
// Check challenge cookie here, if challengecookieold is not set |
// this is the first time and check is skipped |
// TODO when user open two pages similtaneuly (open in new window,open |
// in tab) auth breach is caused find out a way around that if possible |
if ( isset($this->session['challengecookieold']) |
&& $this->session['challengecookieold'] != $this->cookie['authchallenge']) { |
$this->expired = true; |
$this->status = AUTH_SECURITY_BREACH; |
$this->logout(); |
$this->login(); |
return false; |
} |
} |
if (is_callable($this->checkAuthCallback)) { |
$checkCallback = call_user_func_array($this->checkAuthCallback, array($this->username, &$this)); |
if ($checkCallback == false) { |
$this->expired = true; |
$this->status = AUTH_CALLBACK_ABORT; |
$this->logout(); |
return false; |
} |
} |
return true; |
} |
} |
return false; |
} |
// }}} |
// {{{ staticCheckAuth() [static] |
/** |
* Statically checks if there is a session with valid auth information. |
* |
* @access public |
* @see checkAuth |
* @return boolean Whether or not the user is authenticated. |
* @static |
*/ |
function staticCheckAuth($options = null) |
{ |
static $staticAuth; |
if(!isset($staticAuth)) { |
$staticAuth = new Auth('null', $options); |
} |
return $staticAuth->checkAuth(); |
} |
// }}} |
// {{{ getAuth() |
/** |
* Has the user been authenticated? |
* |
* @access public |
* @return bool True if the user is logged in, otherwise false. |
*/ |
function getAuth() |
{ |
return $this->checkAuth(); |
} |
// }}} |
// {{{ 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() |
{ |
if (is_callable($this->logoutCallback)) { |
call_user_func_array($this->logoutCallback, array($this->session['username'], &$this)); |
} |
$this->username = ''; |
$this->password = ''; |
$this->session = null; |
} |
// }}} |
// {{{ updateIdle() |
/** |
* Update the idletime |
* |
* @access private |
* @return void |
*/ |
function updateIdle() |
{ |
$this->session['idle'] = time(); |
} |
// }}} |
// {{{ getUsername() |
/** |
* Get the username |
* |
* @return string |
* @access public |
*/ |
function getUsername() |
{ |
if (isset($this->session['username'])) { |
return($this->session['username']); |
} |
return(''); |
} |
// }}} |
// {{{ getStatus() |
/** |
* Get the current status |
* |
* @return string |
* @access public |
*/ |
function getStatus() |
{ |
return $this->status; |
} |
// }}} |
// {{{ getPostUsernameField() |
/** |
* Gets the post varible used for the username |
* |
* @return string |
* @access public |
*/ |
function getPostUsernameField() |
{ |
return($this->_postUsername); |
} |
// }}} |
// {{{ getPostPasswordField() |
/** |
* Gets the post varible used for the username |
* |
* @return string |
* @access public |
*/ |
function getPostPasswordField() |
{ |
return($this->_postPassword); |
} |
// }}} |
// {{{ sessionValidThru() |
/** |
* Returns the time up to the session is valid |
* |
* @access public |
* @return integer |
*/ |
function sessionValidThru() |
{ |
if (!isset($this->session['idle'])) { |
return 0; |
} |
if ($this->idle == 0) { |
return 0; |
} |
return ($this->session['idle'] + $this->idle); |
} |
// }}} |
// {{{ listUsers() |
/** |
* List all users that are currently available in the storage |
* container |
* |
* @access public |
* @return array |
*/ |
function listUsers() |
{ |
$this->_loadStorage(); |
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 = '') |
{ |
$this->_loadStorage(); |
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) |
{ |
$this->_loadStorage(); |
return $this->storage->removeUser($username); |
} |
// }}} |
// {{{ changePassword() |
/** |
* Change password for user in the storage container |
* |
* @access public |
* @param string Username |
* @param string The new password |
* @return mixed True on success, PEAR error object on error |
* and AUTH_METHOD_NOT_SUPPORTED otherwise. |
*/ |
function changePassword($username, $password) |
{ |
$this->_loadStorage(); |
return $this->storage->changePassword($username, $password); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
/tags/v2.0-narmer/api/pear/A_LIRE.txt |
---|
New file |
0,0 → 1,16 |
Liste des packages PEAR : |
============================== |
Package Version State |
Auth 1.4.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.4.11 stable |
Text_Wiki 1.0.0 stable |
/tags/v2.0-narmer/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> </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 |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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> </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(); |
} |
} |
} |
?> |
/tags/v2.0-narmer/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(); |
} |
} |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/Readme |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/Readme |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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> </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"> </td> |
<td><a href="<?php echo ($MonthDecorator->nextMonth()); ?>">Next</a></td> |
</tr> |
</table> |
</body> |
</html> |
/tags/v2.0-narmer/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> </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> |
/tags/v2.0-narmer/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> </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> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/1.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/1.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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>' ); |
?> |
/tags/v2.0-narmer/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> </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"> </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> |
/tags/v2.0-narmer/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> |
/tags/v2.0-narmer/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> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/3.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/3.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/5.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/5.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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> </td>'; |
} else { |
echo '<td>'.$Day->thisDay().'</td>'; |
} |
if ($Day->isLast()) { |
echo "</tr>\n"; |
} |
} |
?> |
</table> |
/tags/v2.0-narmer/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 />'; |
} |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/7.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/7.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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>'; |
} |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/9.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/9.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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>' ); |
?> |
/tags/v2.0-narmer/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"> </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> |
/tags/v2.0-narmer/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> </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"> </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> |
/tags/v2.0-narmer/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>'; ?> |
/tags/v2.0-narmer/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"> |
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> |
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> |
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> |
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> |
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> |
<input type="submit" name="update" value="Set Alarm"><br> |
<?php |
} |
?> |
<?php echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' ); ?> |
</body> |
</html> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/11.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/11.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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()."&m=". |
$Day->thisMonth()."&d=".$Day->thisDay()."&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&y=". |
$Day->thisYear()."&m=".$Day->thisMonth()."&d=".$Day->thisDay(). |
"&mime=wml\" />\n</anchor></td>\n" ); |
} else { |
echo ( "<td><anchor>".$Day->thisDay()."\n<go href=\"?viewday=true&y=". |
$Day->thisYear()."&m=".$Day->thisMonth()."&d=".$Day->thisDay(). |
"&mime=wml\" /></anchor></td>\n" ); |
} |
if ( $Day->isLast() ) { |
echo ( "</tr>\n" ); |
} |
} |
?> |
<tr> |
<td> |
<anchor> |
<< |
<go href="<?php |
echo ( "?y=".$Month->thisYear()."&m=". |
$Month->prevMonth()."&d=".$Month->thisDay()."&mime=wml" ); |
?>"/> |
</anchor> |
</td> |
<td></td><td></td><td></td><td></td><td></td> |
<td> |
<anchor> |
>> |
<go href="<?php |
echo ( "?y=".$Month->thisYear()."&m=". |
$Month->nextMonth()."&d=".$Month->thisDay()."&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()."&m=". |
$Day->thisMonth()."&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&y=". |
$Day->thisYear()."&m=".$Day->thisMonth()."&d=".$Day->thisDay(). |
"&wml\"><strong><u>".$Day->thisDay()."</u></strong></a></td>\n" ); |
} else { |
echo ( "<td><a href=\"".$_SERVER['PHP_SELF']."?viewday=true&y=". |
$Day->thisYear()."&m=".$Day->thisMonth()."&d=".$Day->thisDay(). |
"\">".$Day->thisDay()."</a></td>\n" ); |
} |
if ( $Day->isLast() ) { |
echo ( "</tr>\n" ); |
} |
} |
?> |
<tr> |
<td> |
<a href="<?php |
echo ( "?y=".$Month->thisYear()."&m=". |
$Month->prevMonth()."&d=".$Month->thisDay() ); |
?>"> |
<<</a> |
</td> |
<td></td><td></td><td></td><td></td><td></td> |
<td> |
<a href="<?php |
echo ( "?y=".$Month->thisYear()."&m=". |
$Month->nextMonth()."&d=".$Month->thisDay() ); |
?>">>></a> |
</td> |
</tr> |
</table> |
<?php |
} |
?> |
<?php echo ( '<p><b>Took: '.(getmicrotime()-$start).' seconds</b></p>' ); ?> |
</body> |
</html> |
<?php |
} |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/21.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/21.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/13.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/13.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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; |
} |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/23.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/23.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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'] ); ?>"> |
Month: <input type="text" size="2" name="m" value="<?php echo ( $_GET['m'] ); ?>"> |
<input type="submit" value="Fetch Calendar"> |
</form> |
</body> |
</html> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/15.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/15.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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())); |
?> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/17.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/17.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/19.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/19.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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 |
/tags/v2.0-narmer/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> </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> |
/tags/v2.0-narmer/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 & |
$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 = '&'; |
$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> |
/tags/v2.0-narmer/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> </td>'; |
} else { |
echo '<td>'.$Day->thisDay().'</td>'; |
} |
if ($Day->isLast()) { |
echo "</tr>\n"; |
} |
} |
?> |
</table> |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/2.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/2.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/4.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/4.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/6.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/6.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/8.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/8.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/10.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/10.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/20.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/20.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/12.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/12.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/22.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/22.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/14.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/14.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/16.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/16.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/18.phps |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/tags/v2.0-narmer/api/pear/Calendar/docs/examples/18.phps |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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)); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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'); |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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(); |
} |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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 |
/tags/v2.0-narmer/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()); |
?> |
/tags/v2.0-narmer/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=&month=&day=&hour=&minute=&second=', |
$Uri->this($this->MockCal, 'second') |
); |
} |
function testScalarFragments() { |
$Uri = new Calendar_Util_Uri('year','month','day','hour','minute','second'); |
$Uri->scalar = true; |
$this->assertEqual( |
'&&&&&', |
$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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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'); |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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=&month=&day=&hour=&minute=&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('&&&&&',$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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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 |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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) |
{ |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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.']'; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
} |
} |
} |
?> |
/tags/v2.0-narmer/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&month=10 |
* echo $Uri->prev($Day,'day'); // Displays year=2003&month=10&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 &) |
* @access public |
*/ |
var $separator = '&'; |
/** |
* 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; |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
} |
?> |
/tags/v2.0-narmer/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.3 2006-12-14 15:04:28 jp_milcent 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: 1.7.6 |
* @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 '1.7.6'; |
} |
// }}} |
// {{{ 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¶m2=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: 1.7.6 |
* @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: 1.7.6 |
* @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: 1.7.6 |
* @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: |
*/ |
?> |
/tags/v2.0-narmer/api/pear/PEAR.php |
---|
New file |
0,0 → 1,1101 |
<?php |
/** |
* PEAR, the PHP Extension and Application Repository |
* |
* PEAR class and PEAR_Error class |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category pear |
* @package PEAR |
* @author Sterling Hughes <sterling@php.net> |
* @author Stig Bakken <ssb@php.net> |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @author Greg Beaver <cellog@php.net> |
* @copyright 1997-2006 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: PEAR.php,v 1.2 2006-12-14 15:04:29 jp_milcent Exp $ |
* @link http://pear.php.net/package/PEAR |
* @since File available since Release 0.1 |
*/ |
/**#@+ |
* ERROR constants |
*/ |
define('PEAR_ERROR_RETURN', 1); |
define('PEAR_ERROR_PRINT', 2); |
define('PEAR_ERROR_TRIGGER', 4); |
define('PEAR_ERROR_DIE', 8); |
define('PEAR_ERROR_CALLBACK', 16); |
/** |
* WARNING: obsolete |
* @deprecated |
*/ |
define('PEAR_ERROR_EXCEPTION', 32); |
/**#@-*/ |
define('PEAR_ZE2', (function_exists('version_compare') && |
version_compare(zend_version(), "2-dev", "ge"))); |
if (substr(PHP_OS, 0, 3) == 'WIN') { |
define('OS_WINDOWS', true); |
define('OS_UNIX', false); |
define('PEAR_OS', 'Windows'); |
} else { |
define('OS_WINDOWS', false); |
define('OS_UNIX', true); |
define('PEAR_OS', 'Unix'); // blatant assumption |
} |
// instant backwards compatibility |
if (!defined('PATH_SEPARATOR')) { |
if (OS_WINDOWS) { |
define('PATH_SEPARATOR', ';'); |
} else { |
define('PATH_SEPARATOR', ':'); |
} |
} |
$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; |
$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; |
$GLOBALS['_PEAR_destructor_object_list'] = array(); |
$GLOBALS['_PEAR_shutdown_funcs'] = array(); |
$GLOBALS['_PEAR_error_handler_stack'] = array(); |
@ini_set('track_errors', true); |
/** |
* Base class for other PEAR classes. Provides rudimentary |
* emulation of destructors. |
* |
* If you want a destructor in your class, inherit PEAR and make a |
* destructor method called _yourclassname (same name as the |
* constructor, but with a "_" prefix). Also, in your constructor you |
* have to call the PEAR constructor: $this->PEAR();. |
* The destructor method will be called without parameters. Note that |
* at in some SAPI implementations (such as Apache), any output during |
* the request shutdown (in which destructors are called) seems to be |
* discarded. If you need to get any debug information from your |
* destructor, use error_log(), syslog() or something similar. |
* |
* IMPORTANT! To use the emulated destructors you need to create the |
* objects by reference: $obj =& new PEAR_child; |
* |
* @category pear |
* @package PEAR |
* @author Stig Bakken <ssb@php.net> |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Greg Beaver <cellog@php.net> |
* @copyright 1997-2006 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.4.11 |
* @link http://pear.php.net/package/PEAR |
* @see PEAR_Error |
* @since Class available since PHP 4.0.2 |
* @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear |
*/ |
class PEAR |
{ |
// {{{ properties |
/** |
* Whether to enable internal debug messages. |
* |
* @var bool |
* @access private |
*/ |
var $_debug = false; |
/** |
* Default error mode for this object. |
* |
* @var int |
* @access private |
*/ |
var $_default_error_mode = null; |
/** |
* Default error options used for this object when error mode |
* is PEAR_ERROR_TRIGGER. |
* |
* @var int |
* @access private |
*/ |
var $_default_error_options = null; |
/** |
* Default error handler (callback) for this object, if error mode is |
* PEAR_ERROR_CALLBACK. |
* |
* @var string |
* @access private |
*/ |
var $_default_error_handler = ''; |
/** |
* Which class to use for error objects. |
* |
* @var string |
* @access private |
*/ |
var $_error_class = 'PEAR_Error'; |
/** |
* An array of expected errors. |
* |
* @var array |
* @access private |
*/ |
var $_expected_errors = array(); |
// }}} |
// {{{ constructor |
/** |
* Constructor. Registers this object in |
* $_PEAR_destructor_object_list for destructor emulation if a |
* destructor object exists. |
* |
* @param string $error_class (optional) which class to use for |
* error objects, defaults to PEAR_Error. |
* @access public |
* @return void |
*/ |
function 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()) |
{ |
// if we are called statically, there is a potential |
// that no shutdown func is registered. Bug #6445 |
if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { |
register_shutdown_function("_PEAR_call_destructors"); |
$GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; |
} |
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); |
} |
// }}} |
// {{{ isError() |
/** |
* Tell whether a value is a PEAR error. |
* |
* @param mixed $data the value to test |
* @param int $code if $data is an error object, return true |
* only if $code is a string and |
* $obj->getMessage() == $code or |
* $code is an integer and $obj->getCode() == $code |
* @access public |
* @return bool true if parameter is an error |
*/ |
function isError($data, $code = null) |
{ |
if (is_a($data, 'PEAR_Error')) { |
if (is_null($code)) { |
return true; |
} elseif (is_string($code)) { |
return $data->getMessage() == $code; |
} else { |
return $data->getCode() == $code; |
} |
} |
return false; |
} |
// }}} |
// {{{ setErrorHandling() |
/** |
* Sets how errors generated by this object should be handled. |
* Can be invoked both in objects and statically. If called |
* statically, setErrorHandling sets the default behaviour for all |
* PEAR objects. If called in an object, setErrorHandling sets |
* the default behaviour for that object. |
* |
* @param int $mode |
* One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. |
* |
* @param mixed $options |
* When $mode is PEAR_ERROR_TRIGGER, this is the error level (one |
* of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
* |
* When $mode is PEAR_ERROR_CALLBACK, this parameter is expected |
* to be the callback function or method. A callback |
* function is a string with the name of the function, a |
* callback method is an array of two elements: the element |
* at index 0 is the object, and the element at index 1 is |
* the name of the method to call in the object. |
* |
* When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is |
* a printf format string used when printing the error |
* message. |
* |
* @access public |
* @return void |
* @see PEAR_ERROR_RETURN |
* @see PEAR_ERROR_PRINT |
* @see PEAR_ERROR_TRIGGER |
* @see PEAR_ERROR_DIE |
* @see PEAR_ERROR_CALLBACK |
* @see PEAR_ERROR_EXCEPTION |
* |
* @since PHP 4.0.5 |
*/ |
function setErrorHandling($mode = null, $options = null) |
{ |
if (isset($this) && is_a($this, 'PEAR')) { |
$setmode = &$this->_default_error_mode; |
$setoptions = &$this->_default_error_options; |
} else { |
$setmode = &$GLOBALS['_PEAR_default_error_mode']; |
$setoptions = &$GLOBALS['_PEAR_default_error_options']; |
} |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$setmode = $mode; |
$setoptions = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$setmode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$setoptions = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
} |
// }}} |
// {{{ expectError() |
/** |
* This method is used to tell which errors you expect to get. |
* Expected errors are always returned with error mode |
* PEAR_ERROR_RETURN. Expected error codes are stored in a stack, |
* and this method pushes a new element onto it. The list of |
* expected errors are in effect until they are popped off the |
* stack with the popExpect() method. |
* |
* Note that this method can not be called statically |
* |
* @param mixed $code a single error code or an array of error codes to expect |
* |
* @return int the new depth of the "expected errors" stack |
* @access public |
*/ |
function expectError($code = '*') |
{ |
if (is_array($code)) { |
array_push($this->_expected_errors, $code); |
} else { |
array_push($this->_expected_errors, array($code)); |
} |
return sizeof($this->_expected_errors); |
} |
// }}} |
// {{{ popExpect() |
/** |
* This method pops one element off the expected error codes |
* stack. |
* |
* @return array the list of error codes that were popped |
*/ |
function popExpect() |
{ |
return array_pop($this->_expected_errors); |
} |
// }}} |
// {{{ _checkDelExpect() |
/** |
* This method checks unsets an error code if available |
* |
* @param mixed error code |
* @return bool true if the error code was unset, false otherwise |
* @access private |
* @since PHP 4.3.0 |
*/ |
function _checkDelExpect($error_code) |
{ |
$deleted = false; |
foreach ($this->_expected_errors AS $key => $error_array) { |
if (in_array($error_code, $error_array)) { |
unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); |
$deleted = true; |
} |
// clean up empty arrays |
if (0 == count($this->_expected_errors[$key])) { |
unset($this->_expected_errors[$key]); |
} |
} |
return $deleted; |
} |
// }}} |
// {{{ delExpect() |
/** |
* This method deletes all occurences of the specified element from |
* the expected error codes stack. |
* |
* @param mixed $error_code error code that should be deleted |
* @return mixed list of error codes that were deleted or error |
* @access public |
* @since PHP 4.3.0 |
*/ |
function delExpect($error_code) |
{ |
$deleted = false; |
if ((is_array($error_code) && (0 != count($error_code)))) { |
// $error_code is a non-empty array here; |
// we walk through it trying to unset all |
// values |
foreach($error_code as $key => $error) { |
if ($this->_checkDelExpect($error)) { |
$deleted = true; |
} else { |
$deleted = false; |
} |
} |
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
} elseif (!empty($error_code)) { |
// $error_code comes alone, trying to unset it |
if ($this->_checkDelExpect($error_code)) { |
return true; |
} else { |
return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
} |
} else { |
// $error_code is empty |
return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME |
} |
} |
// }}} |
// {{{ raiseError() |
/** |
* This method is a wrapper that returns an instance of the |
* configured error class with this object's default error |
* handling applied. If the $mode and $options parameters are not |
* specified, the object's defaults are used. |
* |
* @param mixed $message a text error message or a PEAR error object |
* |
* @param int $code a numeric error code (it is up to your class |
* to define these if you want to use codes) |
* |
* @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
* PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. |
* |
* @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter |
* specifies the PHP-internal error level (one of |
* E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
* If $mode is PEAR_ERROR_CALLBACK, this |
* parameter specifies the callback function or |
* method. In other error modes this parameter |
* is ignored. |
* |
* @param string $userinfo If you need to pass along for example debug |
* information, this parameter is meant for that. |
* |
* @param string $error_class The returned error object will be |
* instantiated from this class, if specified. |
* |
* @param bool $skipmsg If true, raiseError will only pass error codes, |
* the error message parameter will be dropped. |
* |
* @access public |
* @return object a PEAR error object |
* @see PEAR::setErrorHandling |
* @since PHP 4.0.5 |
*/ |
function &raiseError($message = null, |
$code = null, |
$mode = null, |
$options = null, |
$userinfo = null, |
$error_class = null, |
$skipmsg = false) |
{ |
// The error is yet a PEAR error object |
if (is_object($message)) { |
$code = $message->getCode(); |
$userinfo = $message->getUserInfo(); |
$error_class = $message->getType(); |
$message->error_message_prefix = ''; |
$message = $message->getMessage(); |
} |
if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { |
if ($exp[0] == "*" || |
(is_int(reset($exp)) && in_array($code, $exp)) || |
(is_string(reset($exp)) && in_array($message, $exp))) { |
$mode = PEAR_ERROR_RETURN; |
} |
} |
// No mode given, try global ones |
if ($mode === null) { |
// Class error handler |
if (isset($this) && isset($this->_default_error_mode)) { |
$mode = $this->_default_error_mode; |
$options = $this->_default_error_options; |
// Global error handler |
} elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { |
$mode = $GLOBALS['_PEAR_default_error_mode']; |
$options = $GLOBALS['_PEAR_default_error_options']; |
} |
} |
if ($error_class !== null) { |
$ec = $error_class; |
} elseif (isset($this) && isset($this->_error_class)) { |
$ec = $this->_error_class; |
} else { |
$ec = 'PEAR_Error'; |
} |
if ($skipmsg) { |
$a = &new $ec($code, $mode, $options, $userinfo); |
return $a; |
} else { |
$a = &new $ec($message, $code, $mode, $options, $userinfo); |
return $a; |
} |
} |
// }}} |
// {{{ throwError() |
/** |
* Simpler form of raiseError with fewer options. In most cases |
* message, code and userinfo are enough. |
* |
* @param string $message |
* |
*/ |
function &throwError($message = null, |
$code = null, |
$userinfo = null) |
{ |
if (isset($this) && is_a($this, 'PEAR')) { |
$a = &$this->raiseError($message, $code, null, null, $userinfo); |
return $a; |
} else { |
$a = &PEAR::raiseError($message, $code, null, null, $userinfo); |
return $a; |
} |
} |
// }}} |
function staticPushErrorHandling($mode, $options = null) |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
$def_mode = &$GLOBALS['_PEAR_default_error_mode']; |
$def_options = &$GLOBALS['_PEAR_default_error_options']; |
$stack[] = array($def_mode, $def_options); |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$def_mode = $mode; |
$def_options = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$def_mode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$def_options = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
$stack[] = array($mode, $options); |
return true; |
} |
function staticPopErrorHandling() |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
$setmode = &$GLOBALS['_PEAR_default_error_mode']; |
$setoptions = &$GLOBALS['_PEAR_default_error_options']; |
array_pop($stack); |
list($mode, $options) = $stack[sizeof($stack) - 1]; |
array_pop($stack); |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$setmode = $mode; |
$setoptions = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$setmode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$setoptions = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
return true; |
} |
// {{{ pushErrorHandling() |
/** |
* Push a new error handler on top of the error handler options stack. With this |
* you can easily override the actual error handler for some code and restore |
* it later with popErrorHandling. |
* |
* @param mixed $mode (same as setErrorHandling) |
* @param mixed $options (same as setErrorHandling) |
* |
* @return bool Always true |
* |
* @see PEAR::setErrorHandling |
*/ |
function pushErrorHandling($mode, $options = null) |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
if (isset($this) && is_a($this, 'PEAR')) { |
$def_mode = &$this->_default_error_mode; |
$def_options = &$this->_default_error_options; |
} else { |
$def_mode = &$GLOBALS['_PEAR_default_error_mode']; |
$def_options = &$GLOBALS['_PEAR_default_error_options']; |
} |
$stack[] = array($def_mode, $def_options); |
if (isset($this) && is_a($this, 'PEAR')) { |
$this->setErrorHandling($mode, $options); |
} else { |
PEAR::setErrorHandling($mode, $options); |
} |
$stack[] = array($mode, $options); |
return true; |
} |
// }}} |
// {{{ popErrorHandling() |
/** |
* Pop the last error handler used |
* |
* @return bool Always true |
* |
* @see PEAR::pushErrorHandling |
*/ |
function popErrorHandling() |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
array_pop($stack); |
list($mode, $options) = $stack[sizeof($stack) - 1]; |
array_pop($stack); |
if (isset($this) && is_a($this, 'PEAR')) { |
$this->setErrorHandling($mode, $options); |
} else { |
PEAR::setErrorHandling($mode, $options); |
} |
return true; |
} |
// }}} |
// {{{ loadExtension() |
/** |
* OS independant PHP extension load. Remember to take care |
* on the correct extension name for case sensitive OSes. |
* |
* @param string $ext The extension name |
* @return bool Success or not on the dl() call |
*/ |
function loadExtension($ext) |
{ |
if (!extension_loaded($ext)) { |
// if either returns true dl() will produce a FATAL error, stop that |
if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { |
return false; |
} |
if (OS_WINDOWS) { |
$suffix = '.dll'; |
} elseif (PHP_OS == 'HP-UX') { |
$suffix = '.sl'; |
} elseif (PHP_OS == 'AIX') { |
$suffix = '.a'; |
} elseif (PHP_OS == 'OSX') { |
$suffix = '.bundle'; |
} else { |
$suffix = '.so'; |
} |
return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); |
} |
return true; |
} |
// }}} |
} |
// {{{ _PEAR_call_destructors() |
function _PEAR_call_destructors() |
{ |
global $_PEAR_destructor_object_list; |
if (is_array($_PEAR_destructor_object_list) && |
sizeof($_PEAR_destructor_object_list)) |
{ |
reset($_PEAR_destructor_object_list); |
if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { |
$_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); |
} |
while (list($k, $objref) = each($_PEAR_destructor_object_list)) { |
$classname = get_class($objref); |
while ($classname) { |
$destructor = "_$classname"; |
if (method_exists($objref, $destructor)) { |
$objref->$destructor(); |
break; |
} else { |
$classname = get_parent_class($classname); |
} |
} |
} |
// Empty the object list to ensure that destructors are |
// not called more than once. |
$_PEAR_destructor_object_list = array(); |
} |
// Now call the shutdown functions |
if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { |
foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { |
call_user_func_array($value[0], $value[1]); |
} |
} |
} |
// }}} |
/** |
* Standard PEAR error class for PHP 4 |
* |
* This class is supserseded by {@link PEAR_Exception} in PHP 5 |
* |
* @category pear |
* @package PEAR |
* @author Stig Bakken <ssb@php.net> |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Gregory Beaver <cellog@php.net> |
* @copyright 1997-2006 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.4.11 |
* @link http://pear.php.net/manual/en/core.pear.pear-error.php |
* @see PEAR::raiseError(), PEAR::throwError() |
* @since Class available since PHP 4.0.2 |
*/ |
class PEAR_Error |
{ |
// {{{ properties |
var $error_message_prefix = ''; |
var $mode = PEAR_ERROR_RETURN; |
var $level = E_USER_NOTICE; |
var $code = -1; |
var $message = ''; |
var $userinfo = ''; |
var $backtrace = null; |
// }}} |
// {{{ constructor |
/** |
* PEAR_Error constructor |
* |
* @param string $message message |
* |
* @param int $code (optional) error code |
* |
* @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, |
* PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, |
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION |
* |
* @param mixed $options (optional) error level, _OR_ in the case of |
* PEAR_ERROR_CALLBACK, the callback function or object/method |
* tuple. |
* |
* @param string $userinfo (optional) additional user/debug info |
* |
* @access public |
* |
*/ |
function 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_Exception for exceptions", E_USER_WARNING); |
eval('$e = new Exception($this->message, $this->code);throw($e);'); |
} |
} |
// }}} |
// {{{ getMode() |
/** |
* Get the error mode from an error object. |
* |
* @return int error mode |
* @access public |
*/ |
function getMode() { |
return $this->mode; |
} |
// }}} |
// {{{ getCallback() |
/** |
* Get the callback function/method from an error object. |
* |
* @return mixed callback function or object/method array |
* @access public |
*/ |
function getCallback() { |
return $this->callback; |
} |
// }}} |
// {{{ getMessage() |
/** |
* Get the error message from an error object. |
* |
* @return string full error message |
* @access public |
*/ |
function getMessage() |
{ |
return ($this->error_message_prefix . $this->message); |
} |
// }}} |
// {{{ getCode() |
/** |
* Get error code from an error object |
* |
* @return int error code |
* @access public |
*/ |
function getCode() |
{ |
return $this->code; |
} |
// }}} |
// {{{ getType() |
/** |
* Get the name of this error/exception. |
* |
* @return string error/exception name (type) |
* @access public |
*/ |
function getType() |
{ |
return get_class($this); |
} |
// }}} |
// {{{ getUserInfo() |
/** |
* Get additional user-supplied information. |
* |
* @return string user-supplied information |
* @access public |
*/ |
function getUserInfo() |
{ |
return $this->userinfo; |
} |
// }}} |
// {{{ getDebugInfo() |
/** |
* Get additional debug information supplied by the application. |
* |
* @return string debug information |
* @access public |
*/ |
function getDebugInfo() |
{ |
return $this->getUserInfo(); |
} |
// }}} |
// {{{ getBacktrace() |
/** |
* Get the call backtrace from where the error was generated. |
* Supported with PHP 4.3.0 or newer. |
* |
* @param int $frame (optional) what frame to fetch |
* @return array Backtrace, or NULL if not available. |
* @access public |
*/ |
function getBacktrace($frame = null) |
{ |
if (defined('PEAR_IGNORE_BACKTRACE')) { |
return null; |
} |
if ($frame === null) { |
return $this->backtrace; |
} |
return $this->backtrace[$frame]; |
} |
// }}} |
// {{{ addUserInfo() |
function addUserInfo($info) |
{ |
if (empty($this->userinfo)) { |
$this->userinfo = $info; |
} else { |
$this->userinfo .= " ** $info"; |
} |
} |
// }}} |
// {{{ toString() |
/** |
* 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: |
*/ |
?> |
/tags/v2.0-narmer/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 = '<< Back'; |
/** |
* @var string image/text to use as "next" link |
* @access private |
*/ |
var $_nextImg = 'Next >>'; |
/** |
* @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 == '&') { |
$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(' ', $this->_spacesBeforeSeparator); |
$this->_spacesAfter = str_repeat(' ', $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]); |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
?> |
/tags/v2.0-narmer/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; ?> |
<input type="submit" value="submit" /> |
</form> |
<hr /> |
</body> |
</html> |
/tags/v2.0-narmer/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(' ', '', $this->_getBackLink()); |
$next = str_replace(' ', '', $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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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 = '«'; |
$this->_nextImg = '»'; |
$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(' ', '', $this->_getBackLink()); |
$next = str_replace(' ', '', $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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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( |
'/(&|&|\?)('.$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; |
} |
// }}} |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
} |
?> |
/tags/v2.0-narmer/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' => '测试', |
'encoded2' => '안녕', |
); |
$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> |
/tags/v2.0-narmer/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); |
?> |
/tags/v2.0-narmer/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 |
*/ |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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()); |
?> |
/tags/v2.0-narmer/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' => '»' |
); |
$this->pager = Pager::factory($options); |
$expected = ' <a href="./">test?pageID=2" title="next page">»</a> '; |
$this->assertEqual($expected, $this->pager->_getNextLink()); |
} |
} |
if (!defined('TEST_RUNNING')) { |
define('TEST_RUNNING', true); |
$test = &new TestOfPagerXSS(); |
$test->run(new HtmlReporter()); |
} |
?> |
/tags/v2.0-narmer/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'); |
?> |
/tags/v2.0-narmer/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()); |
} |
} |
?> |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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&escape=äö%<>+&pageID='; |
//$this->assertEqual($expected, $this->pager->_getLinksUrl()); |
$expected = 'request%5B0%5D=aRequest&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&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' => '测试', |
), |
'perPage' => 5, |
); |
$this->pager =& Pager::factory($options); |
//$expected = '<a href="'.$_SERVER['PHP_SELF'].'?test=测试" 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&arr[1]=orange&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&arr%5B1%5D=orange&no=test&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&arr%5B1%5D=orange&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', '&'); |
$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&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> '; |
$this->assertEqual($expected, $this->pager->_printFirstPage()); |
$this->pager->_firstPageText = 'FIRST'; |
$expected = '<a href="' . $_SERVER['PHP_SELF'] . '?pageID=1" title="first page">[FIRST]</a> '; |
$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> '; |
$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 = '«'; |
$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> '; |
$this->assertEqual($expected, $this->pager->_getBackLink()); |
} |
function testGetNexLink() { |
$img = '»'; |
$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 = ' <a href="' . $_SERVER['PHP_SELF'] . '?pageID=2" title="next page">'.$img.'</a> '; |
$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('안녕')); |
$test_strings_encoded = array( |
'encoded0' => '试', |
'encoded1' => '测试', |
'encoded2' => '안녕', |
'encoded3' => '안 녕', |
'encoded4' => '안 |
녕', |
); |
$test_strings_plain = array( |
'plain1' => '안녕', |
'plain2' => '더보기', |
// 'plain3' => '이젠 전화도 |
//로 걸면 무료', |
'plain4' => 'abcde', //not multibyte |
'plain5' => '&#abcfg;', //invalid hex-encoded char |
'plain5' => '안 nasty 녕', //mixed plain/encoded text |
); |
foreach ($test_strings_encoded as $string) { |
//echo '<hr />'.str_replace('&', '&', $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()); |
} |
} |
?> |
/tags/v2.0-narmer/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)); |
} |
} |
?> |
/tags/v2.0-narmer/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'; |
?> |
/tags/v2.0-narmer/api/pear/Pager/tests/pager_include.php |
---|
New file |
0,0 → 1,4 |
<?php |
// $Id$ |
require_once 'Pager/Pager.php'; |
?> |
/tags/v2.0-narmer/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' => '测试', |
'encoded2' => '안녕', |
); |
$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('&', '&', $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'); |
} |
} |
} |
?> |
/tags/v2.0-narmer/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); |
} |
} |
?> |
/tags/v2.0-narmer/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. |
/tags/v2.0-narmer/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()); |
} |
?> |
/tags/v2.0-narmer/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)); |
} |
} |
?> |
/tags/v2.0-narmer/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; |
} |
// }}} |
} |
?> |