/trunk/api/pear/HTML/Common.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/api/pear/HTML/Common.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/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.1 2005-03-30 08:50:33 jpm 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; |
} |
} |
} |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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('', ''); |
} |
} |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/date.php |
---|
New file |
0,0 → 1,451 |
<?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.1 2005-03-30 08:50:33 jpm 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', 'Fev', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'), |
'months_long' => array ('Janvier', 'Fevrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Decembre') |
), |
'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', 'Fev', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'), |
'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', 'Septimbre', '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('Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень') |
) |
); |
// }}} |
// {{{ 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 '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 '\\': |
$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 ($this->_options['addEmptyOption']) { |
// Preserve the keys |
$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', (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], |
'H' => $arr[5], |
'i' => $arr[6], |
's' => $arr[7], |
'a' => $arr[8], |
'A' => $arr[9] |
); |
} |
parent::setValue($value); |
} |
// }}} |
// {{{ toHtml() |
function toHtml() |
{ |
include_once('HTML/QuickForm/Renderer/Default.php'); |
$renderer =& new HTML_QuickForm_Renderer_Default(); |
$renderer->setElementTemplate($this->_wrap[0] . '{element}' . $this->_wrap[1]); |
parent::accept($renderer); |
return $renderer->toHtml(); |
} |
// }}} |
// {{{ 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); |
} |
} |
// }}} |
} |
?> |
/trunk/api/pear/HTML/QuickForm/select.php |
---|
New file |
0,0 → 1,577 |
<?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.1 2005-03-30 08:50:33 jpm 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) || is_subclass_of($options, "db_common")): |
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 ($val == $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)? ' id="' . $id . '"': ''; |
} else { |
$idAttr = ''; |
} |
foreach ($value as $key => $item) { |
$html .= '<input type="hidden"' . $idAttr . ' name="' . |
$name . '" value="' . $this->_values[$key] . '" />'; |
} |
} |
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); |
} |
} |
// }}} |
} //end class HTML_QuickForm_select |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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; |
} |
} |
} |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 (!empty($this->_required)){ |
$this->_renderRequired($ret['label'], $ret['html'], $required, $error); |
} |
if (!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 |
} |
?> |
/trunk/api/pear/HTML/QuickForm/Renderer/ObjectFlexy.php |
---|
New file |
0,0 → 1,413 |
<?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.1 2005-03-30 08:50:33 jpm Exp $ |
require_once("HTML/QuickForm/Renderer/Object.php"); |
/** |
* @abstract Long Description |
* 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"); |
* |
* @see QuickFormFlexyObject |
* |
* Based on the code for HTML_QuickForm_Renderer_ArraySmarty |
* |
* @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 |
* |
* @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 |
* |
* @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} |
* |
* @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} |
* |
* @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 |
/** |
* @abstract Long Description |
* This class represents the 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> |
* |
* @public |
*/ |
class QuickformFlexyForm { |
/** |
* 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() |
{ |
$hdr = "<form " . $this->attributes . ">\n"; |
return $hdr; |
} |
/** |
* Output form javascript |
* {form.outputJavaScript():h} |
* @return string Javascript |
*/ |
function outputJavaScript() |
{ |
return $this->javascript; |
} |
} // end class QuickformFlexyForm |
/** |
* 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 QuickformFlexyElement { |
/** |
* 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; |
} // end class QuickformFlexyElement |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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; |
} |
} |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/Renderer/Default.php |
---|
New file |
0,0 → 1,471 |
<?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.1 2005-03-30 08:50:33 jpm 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() |
{ |
return $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->_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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/Renderer/Object.php |
---|
New file |
0,0 → 1,438 |
<?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.1 2005-03-30 08:50:33 jpm 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 |
* |
* @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 |
* @public |
*/ |
function HTML_QuickForm_Renderer_Object($collecthidden = false) |
{ |
$this->HTML_QuickForm_Renderer(); |
$this->_collectHidden = $collecthidden; |
$this->_obj = new QuickformForm; |
} |
/** |
* Return the rendered Object |
* @public |
*/ |
function toObject() |
{ |
return $this->_obj; |
} |
/** |
* Set the class of the form elements. Defaults to StdClass. |
* @param type string Name of element class |
* @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->_view->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 |
* |
* @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 |
* |
* @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 |
/** |
* @abstract Long Description |
* This class represents the 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> |
* |
* @public |
*/ |
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() { |
$hdr = "<form " . $this->attributes . ">\n"; |
return $hdr; |
} |
/** |
* 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) |
{ |
if($this->type == $type) { |
return true; |
} else { |
return false; |
} |
} |
function notFrozen() |
{ |
if(!$this->frozen) { |
return true; |
} else { |
return false; |
} |
} |
function isButton() |
{ |
if($this->type == "submit" || $this->type == "reset") { |
return true; |
} else { |
return false; |
} |
} |
function outputStyle() |
{ |
$filename = "styles/".$this->style.".html"; |
ob_start(); |
HTML_Template_Flexy::staticQuickTemplate($filename, $this); |
$ret = ob_get_contents(); |
ob_end_clean(); |
return $ret; |
} |
} // end class QuickformElement |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 ($value == '') { |
return false; |
} |
return true; |
} // end func validate |
function getValidationScript($options = null) |
{ |
return array('', "{jsVar} == ''"); |
} // end func getValidationScript |
} // end class HTML_QuickForm_Rule_Required |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.1 $ |
*/ |
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}"); |
} |
} |
?> |
/trunk/api/pear/HTML/QuickForm/advcheckbox.php |
---|
New file |
0,0 → 1,279 |
<?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.1 2005-03-30 08:50:33 jpm 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 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 (isset($caller->_submitValues) && 0 < count($caller->_submitValues)) { |
$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 |
?> |
/trunk/api/pear/HTML/QuickForm/hierselect.php |
---|
New file |
0,0 → 1,444 |
<?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> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: hierselect.php,v 1.1 2005-03-30 08:50:33 jpm 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 = ''; |
/** |
* The javascript array name |
*/ |
var $_jsArrayName = ''; |
// }}} |
// {{{ 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(); |
$this->_setJS(); |
} // 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(); |
$this->_setJS(); |
} // 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) { |
if (eval("return isset(\$this->_options[{$key}]{$toLoad});") ) { |
$array = eval("return \$this->_options[{$key}]{$toLoad};"); |
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 .= '[\''.$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 |
// }}} |
// {{{ _setJS() |
/** |
* Set the JavaScript for each select element (excluding de main one). |
* |
* @access private |
* @return void |
*/ |
function _setJS() |
{ |
$this->_js = $js = ''; |
$this->_jsArrayName = 'hs_' . $this->getName(); |
for ($i = 1; $i < $this->_nbElements; $i++) { |
$this->_setJSArray($this->_jsArrayName, $this->_options[$i], $js); |
} |
} // end func _setJS |
// }}} |
// {{{ _setJSArray() |
/** |
* Recursively builds the JavaScript array defining the options that a select |
* element can have. |
* |
* @param string $grpName Group Name attribute |
* @param array $options Select element options |
* @param string $js JavaScript definition is build using this variable |
* @param string $optValue The value for the current JavaScript option |
* |
* @access private |
* @return void |
*/ |
function _setJSArray($grpName, $options, &$js, $optValue = '') |
{ |
if (is_array($options)) { |
$js = ''; |
// For a hierselect containing 3 elements: |
// if option 1 has been selected for the 1st element |
// and option 3 has been selected for the 2nd element, |
// then the javascript array containing the values to load |
// on the 3rd element will have the following name: grpName_1_3 |
$name = ($optValue === '') ? $grpName : $grpName.'_'.$optValue; |
foreach($options AS $k => $v) { |
$this->_setJSArray($name, $v, $js, $k); |
} |
// if $js !== '' add it to the JavaScript |
$this->_js .= ($js !== '') ? $name." = {\n".$js."\n}\n" : ''; |
$js = ''; |
} else { |
// $js empty means that we are adding the first element to the JavaScript. |
if ($js != '') { |
$js .= ",\n"; |
} |
$js .= '"'.$optValue.'":"'.$options.'"'; |
} |
} |
// }}} |
// {{{ toHtml() |
/** |
* Returns Html for the group |
* |
* @access public |
* @return string |
*/ |
function toHtml() |
{ |
if ($this->_flagFrozen) { |
$this->_js = ''; |
} else { |
// set the onchange attribute for each element |
$keys = array_keys($this->_elements); |
$nbElements = count($keys); |
$nbElementsUsingFnc = $nbElements - 1; // last element doesn't need it |
for ($i = 0; $i < $nbElementsUsingFnc; $i++) { |
$select =& $this->_elements[$keys[$i]]; |
$select->updateAttributes( |
array('onChange' => 'swapOptions(this, \''.$this->getName().'\', '.$keys[$i].', '.$nbElements.', \''.$this->_jsArrayName.'\');') |
); |
} |
// create the js function to call |
if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) { |
$this->_js .= "function swapOptions(frm, grpName, eleIndex, nbElements, arName)\n" |
."{\n" |
." var n = \"\";\n" |
." var ctl;\n\n" |
." for (var i = 0; i < nbElements; i++) {\n" |
." ctl = frm.form[grpName+'['+i+']'];\n" |
." if (!ctl) {\n" |
." ctl = frm.form[grpName+'['+i+'][]'];\n" |
." }\n" |
." if (i <= eleIndex) {\n" |
." n += \"_\"+ctl.value;\n" |
." } else {\n" |
." ctl.length = 0;\n" |
." }\n" |
." }\n\n" |
." var t = eval(\"typeof(\"+arName + n +\")\");\n" |
." if (t != 'undefined') {\n" |
." var the_array = eval(arName+n);\n" |
." var j = 0;\n" |
." n = eleIndex + 1;\n" |
." ctl = frm.form[grpName+'['+ n +']'];\n" |
." if (!ctl) {\n" |
." ctl = frm.form[grpName+'['+ n +'][]'];\n" |
." }\n" |
." for (var i in the_array) {\n" |
." opt = new Option(the_array[i], i, false, false);\n" |
." ctl.options[j++] = opt;\n" |
." }\n" |
." }\n" |
." if (eleIndex+1 < nbElements) {\n" |
." swapOptions(frm, grpName, eleIndex+1, nbElements, arName);\n" |
." }\n" |
."}\n"; |
define('HTML_QUICKFORM_HIERSELECT_EXISTS', true); |
} |
} |
include_once('HTML/QuickForm/Renderer/Default.php'); |
$renderer =& new HTML_QuickForm_Renderer_Default(); |
$renderer->setElementTemplate('{element}'); |
parent::accept($renderer); |
return "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>" . |
$renderer->toHtml(); |
} // end func toHtml |
// }}} |
// {{{ 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) |
{ |
$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 { |
return parent::onQuickFormEvent($event, $arg, $caller); |
} |
} // end func onQuickFormEvent |
// }}} |
} // end class HTML_QuickForm_hierselect |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/element.php |
---|
New file |
0,0 → 1,478 |
<?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.1 2005-03-30 08:50:33 jpm 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 type="hidden"' . |
(isset($id)? ' id="' . $id . '"': '') . |
' name="' . $this->getName() . '"' . |
' value="' . htmlspecialchars($this->getValue()) . '" />'; |
} |
} |
// }}} |
// {{{ 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 |
?> |
/trunk/api/pear/HTML/QuickForm/hiddenselect.php |
---|
New file |
0,0 → 1,103 |
<?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.1 2005-03-30 08:50:33 jpm 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 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/group.php |
---|
New file |
0,0 → 1,568 |
<?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.1 2005-03-30 08:50:33 jpm 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) |
{ |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
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 = (!empty($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() |
{ |
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() |
{ |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
$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) |
{ |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
$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(); |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
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': |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
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) |
{ |
if (empty($this->_elements)) { |
$this->_createElements(); |
} |
$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 |
} |
// }}} |
// {{{ 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 |
?> |
/trunk/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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm/RuleRegistry.php |
---|
New file |
0,0 → 1,317 |
<?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.1 2005-03-30 08:50:33 jpm 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 = " var {$elementName}Elements = '::"; |
for ($i = 0, $count = count($element->_elements); $i < $count; $i++) { |
$value .= $element->getElementName($i) . '::'; |
} |
$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 ({$elementName}Elements.indexOf('::' + _element.name + '::') >= 0) {\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':\n" . |
" if (-1 != _element.selectedIndex) {\n" . |
" value{$jsIndex}[valueIdx++] = _element.options[_element.selectedIndex].value;\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 ({$elementName}Elements.indexOf('::' + _element.name + '::') >= 0) {\n" . |
" switch (_element.type) {\n" . |
" case 'checkbox':\n" . |
" case 'radio':\n" . |
" _element.checked = _element.defaultChecked;\n" . |
" break;\n" . |
" case 'select':\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}'].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') { |
$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 |
?> |
/trunk/api/pear/HTML/QuickForm/autocomplete.php |
---|
New file |
0,0 → 1,240 |
<?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.1 2005-03-30 08:50:33 jpm 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(); |
// }}} |
// {{{ 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')) { |
$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 .= '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 |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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 |
?> |
/trunk/api/pear/HTML/QuickForm.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/api/pear/HTML/QuickForm.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/api/pear/HTML/Table.php |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/api/pear/HTML/Table.php |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/api/pear/DB/common.php |
---|
New file |
0,0 → 1,2156 |
<?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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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 or DB_FETCHMODE_ASSOC, |
* possibly bit-wise OR'ed with |
* DB_FETCHMODE_FLIPPED |
* |
* @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_FLIPPED, |
* 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 |
* |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/api/pear/DB/oci8.php |
---|
New file |
0,0 → 1,1109 |
<?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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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'; |
} |
$char = empty($dsn['charset']) ? null : $dsn['charset']; |
$this->connection = @$connect_function($dsn['username'], |
$dsn['password'], |
$dsn['database'], |
$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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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.1 2005-03-30 08:50:33 jpm 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.5 |
* @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: |
*/ |
?> |
/trunk/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); |
} |
} |
?> |
/trunk/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; |
} |
} |
/trunk/api/pear/Net/FTP.php |
---|
New file |
0,0 → 1,2116 |
<?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.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 |
*/ |
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: 1.3.0 |
* @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+)\s+(\w+)\s+(\w+)\s+(\S+\s+\S+\s+\S+)\s+(.+)/', |
'map' => array('name'=>8,'size'=>6,'rights'=>2,'user'=>4,'group'=>5, |
'files_inside'=>3,'date'=>7,'is_dir'=>1) |
), |
'windows' => array( |
'pattern' => '/(.+)\s+(.+)\s+((<DIR>)|[0-9]+)\s+(.+)/', |
'map' => array('name'=>5,'date'=>1,'is_dir'=>3) |
) |
); |
/** |
* 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) { |
$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 (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) { |
$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 (!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 ($dir_list === false) { |
return PEAR::raiseError('Could not get raw directory listing.', NET_FTP_ERR_RAWDIRLIST_FAILED); |
} |
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; |
} |
} |
?> |
/trunk/api/pear/Net/URL.php |
---|
New file |
0,0 → 1,410 |
<?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.1 2005-03-30 08:50:33 jpm 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_SERVER_VARS['HTTPS'] == 'on' ? 'https' : '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; |
} |
} |
?> |
/trunk/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; |
} |
} |
?> |
/trunk/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; |
} |
} |
?> |
/trunk/api/pear/Auth.php |
---|
New file |
0,0 → 1,869 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Martin Jansen <mj@php.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: Auth.php,v 1.1 2005-03-30 08:50:19 jpm Exp $ |
// |
require_once 'PEAR.php'; |
define('AUTH_IDLED', -1); |
define('AUTH_EXPIRED', -2); |
define('AUTH_WRONG_LOGIN', -3); |
/** |
* PEAR::Auth |
* |
* The PEAR::Auth class provides methods for creating an |
* authentication system using PHP. |
* |
* @author Martin Jansen <mj@php.net> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth { |
/** |
* Auth lifetime in seconds |
* |
* If this variable is set to 0, auth never expires |
* |
* @var integer |
* @see setExpire(), checkAuth() |
*/ |
var $expire = 0; |
/** |
* Has the auth session expired? |
* |
* @var bool |
* @see checkAuth(), drawLogin() |
*/ |
var $expired = false; |
/** |
* Maximum time of idleness in seconds |
* |
* The difference to $expire is, that the idletime gets |
* refreshed each time, checkAuth() is called. If this |
* variable is set to 0, idle time is never checked. |
* |
* @var integer |
* @see setIdle(), checkAuth() |
*/ |
var $idle = 0; |
/** |
* Is the maximum idletime over? |
* |
* @var boolean |
* @see checkAuth(), drawLogin(); |
*/ |
var $idled = false; |
/** |
* Storage object |
* |
* @var object |
* @see Auth(), validateLogin() |
*/ |
var $storage = ''; |
/** |
* Function defined by the user, that creates the login screen |
* |
* @var string |
*/ |
var $loginFunction = ''; |
/** |
* Should the login form be displayed? |
* |
* @var bool |
* @see setShowlogin() |
*/ |
var $showLogin = true; |
/** |
* Current authentication status |
* |
* @var string |
*/ |
var $status = ''; |
/** |
* Username |
* |
* @var string |
*/ |
var $username = ''; |
/** |
* Password |
* |
* @var string |
*/ |
var $password = ''; |
/** |
* Login callback function name |
* |
* @var string |
* @see setLoginCallback() |
*/ |
var $loginCallback = ''; |
/** |
* Failed Login callback function name |
* |
* @var string |
* @see setLoginFailedCallback() |
*/ |
var $loginFailedCallback = ''; |
/** |
* Logout callback function name |
* |
* @var string |
* @see setLogoutCallback() |
*/ |
var $logoutCallback = ''; |
/** |
* Auth session-array name |
* |
* @var string |
*/ |
var $_sessionName = '_authsession'; |
/** |
* Package Version |
* |
* @var string |
*/ |
var $version = "1.2.3"; |
// {{{ Constructor |
/** |
* Constructor |
* |
* Set up the storage driver. |
* |
* @param string Type of the storage driver |
* @param mixed Additional options for the storage driver |
* (example: if you are using DB as the storage |
* driver, you have to pass the dsn string here) |
* |
* @param string Name of the function that creates the login form |
* @param boolean Should the login form be displayed if neccessary? |
* @return void |
*/ |
function Auth($storageDriver, $options = '', $loginFunction = '', $showLogin = true) |
{ |
if (!empty($options['sessionName'])) { |
$this->_sessionName = $options['sessionName']; |
unset($options['sessionName']); |
} |
if ($loginFunction != '' && is_callable($loginFunction)) { |
$this->loginFunction = $loginFunction; |
} |
if (is_bool($showLogin)) { |
$this->showLogin = $showLogin; |
} |
if (is_object($storageDriver)) { |
$this->storage =& $storageDriver; |
} else { |
$this->storage = $this->_factory($storageDriver, $options); |
} |
// Pass a reference to auth to the container, ugly but works |
// this is used by the DB container to use method setAuthData not staticaly. |
$this->storage->_auth_obj =& $this; |
} |
// }}} |
// {{{ _factory() |
/** |
* Return a storage driver based on $driver and $options |
* |
* @access private |
* @static |
* @param string $driver Type of storage class to return |
* @param string $options Optional parameters for the storage class |
* @return object Object Storage object |
*/ |
function _factory($driver, $options = '') |
{ |
$storage_path = 'Auth/Container/' . $driver . '.php'; |
$storage_class = 'Auth_Container_' . $driver; |
require_once $storage_path; |
return new $storage_class($options); |
} |
// }}} |
// {{{ assignData() |
/** |
* Assign data from login form to internal values |
* |
* This function takes the values for username and password |
* from $HTTP_POST_VARS and assigns them to internal variables. |
* If you wish to use another source apart from $HTTP_POST_VARS, |
* you have to derive this function. |
* |
* @access private |
* @global $HTTP_POST_VARS |
* @see Auth |
* @return void |
*/ |
function assignData() |
{ |
$post = &$this->_importGlobalVariable('post'); |
if (isset($post['username']) && $post['username'] != '') { |
$this->username = (get_magic_quotes_gpc() == 1 ? stripslashes($post['username']) : $post['username']); |
} |
if (isset($post['password']) && $post['password'] != '') { |
$this->password = (get_magic_quotes_gpc() == 1 ? stripslashes($post['password']) : $post['password'] ); |
} |
} |
// }}} |
// {{{ start() |
/** |
* Start new auth session |
* |
* @access public |
* @return void |
*/ |
function start() |
{ |
$this->assignData(); |
@session_start(); |
if (!$this->checkAuth()) { |
$this->login(); |
} |
} |
// }}} |
// {{{ login() |
/** |
* Login function |
* |
* @access private |
* @return void |
*/ |
function login() |
{ |
$login_ok = false; |
/** |
* When the user has already entered a username, |
* we have to validate it. |
*/ |
if (!empty($this->username)) { |
if (true === $this->storage->fetchData($this->username, $this->password)) { |
$login_ok = true; |
} else { |
if (is_callable($this->loginFailedCallback)) { |
call_user_func($this->loginFailedCallback,$this->username, $this); |
} |
} |
} |
if (!empty($this->username) && $login_ok) { |
$this->setAuth($this->username); |
if (is_callable($this->loginCallback)) { |
call_user_func($this->loginCallback,$this->username, $this); |
} |
} |
/** |
* If the login failed or the user entered no username, |
* output the login screen again. |
*/ |
if (!empty($this->username) && !$login_ok) { |
$this->status = AUTH_WRONG_LOGIN; |
} |
if ((empty($this->username) || !$login_ok) && $this->showLogin) { |
$this->drawLogin($this->storage->activeUser); |
return; |
} |
} |
// }}} |
// {{{ setExpire() |
/** |
* Set the maximum expire time |
* |
* @access public |
* @param integer time in seconds |
* @param bool add time to current expire time or not |
* @return void |
*/ |
function setExpire($time, $add = false) |
{ |
if ($add) { |
$this->expire += $time; |
} else { |
$this->expire = $time; |
} |
} |
// }}} |
// {{{ setIdle() |
/** |
* Set the maximum idle time |
* |
* @access public |
* @param integer time in seconds |
* @param bool add time to current maximum idle time or not |
* @return void |
*/ |
function setIdle($time, $add = false) |
{ |
if ($add) { |
$this->idle += $time; |
} else { |
$this->idle = $time; |
} |
} |
// }}} |
// {{{ setSessionname() |
/** |
* Set name of the session to a customized value. |
* |
* If you are using multiple instances of PEAR::Auth |
* on the same domain, you can change the name of |
* session per application via this function. |
* |
* @access public |
* @param string New name for the session |
* @return void |
*/ |
function setSessionname($name = 'PHPSESSID') |
{ |
@session_name($name); |
} |
// }}} |
// {{{ setShowLogin() |
/** |
* Should the login form be displayed if neccessary? |
* |
* @access public |
* @param bool show login form or not |
* @return void |
*/ |
function setShowLogin($showLogin = true) |
{ |
$this->showLogin = $showLogin; |
} |
/** |
* Register a callback function to be called on user login. |
* The function will receive two parameters, the username and a reference to the auth object. |
* |
* @access public |
* @param string callback function name |
* @return void |
* @see setLogoutCallback() |
*/ |
function setLoginCallback($loginCallback) |
{ |
$this->loginCallback = $loginCallback; |
} |
/** |
* Register a callback function to be called on failed user login. |
* The function will receive a single parameter, the username and a reference to the auth object. |
* |
* @access public |
* @param string callback function name |
* @return void |
*/ |
function setFailedLoginCallback($loginFailedCallback) |
{ |
$this->loginFailedCallback = $loginFailedCallback; |
} |
/** |
* Register a callback function to be called on user logout. |
* The function will receive three parameters, the username and a reference to the auth object. |
* |
* @access public |
* @param string callback function name |
* @return void |
* @see setLoginCallback() |
*/ |
function setLogoutCallback($logoutCallback) |
{ |
$this->logoutCallback = $logoutCallback; |
} |
// }}} |
// {{{ setAuthData() |
/** |
* Register additional information that is to be stored |
* in the session. |
* |
* @access public |
* @param string Name of the data field |
* @param mixed Value of the data field |
* @param boolean Should existing data be overwritten? (default |
* is true) |
* @return void |
*/ |
function setAuthData($name, $value, $overwrite = true) |
{ |
$session = &Auth::_importGlobalVariable('session'); |
if (!empty($session[$this->_sessionName]['data'][$name]) && $overwrite == false) { |
return; |
} |
$session[$this->_sessionName]['data'][$name] = $value; |
} |
// }}} |
// {{{ getAuthData() |
/** |
* Get additional information that is stored in the session. |
* |
* If no value for the first parameter is passed, the method will |
* return all data that is currently stored. |
* |
* @access public |
* @param string Name of the data field |
* @return mixed Value of the data field. |
*/ |
function getAuthData($name = null) |
{ |
$session = &Auth::_importGlobalVariable('session'); |
if(!isset($session[$this->_sessionName]['data'])){ |
return(null); |
} |
if (is_null($name)) { |
if(isset($session[$this->_sessionName]['data'])) { |
return $session[$this->_sessionName]['data']; |
} else { |
return null; |
} |
} |
if (isset($session[$this->_sessionName]['data'][$name])) { |
return $session[$this->_sessionName]['data'][$name]; |
} else { |
return null; |
} |
} |
// }}} |
// {{{ setAuth() |
/** |
* Register variable in a session telling that the user |
* has logged in successfully |
* |
* @access public |
* @param string Username |
* @return void |
*/ |
function setAuth($username) |
{ |
$session = &Auth::_importGlobalVariable('session'); |
if (!isset($session[$this->_sessionName]) && !isset($_SESSION)) { |
session_register($this->_sessionName); |
} |
if (!isset($session[$this->_sessionName]) || !is_array($session[$this->_sessionName])) { |
$session[$this->_sessionName] = array(); |
} |
if(!isset($session[$this->_sessionName]['data'])){ |
$session[$this->_sessionName]['data'] = array(); |
} |
$session[$this->_sessionName]['registered'] = true; |
$session[$this->_sessionName]['username'] = $username; |
$session[$this->_sessionName]['timestamp'] = time(); |
$session[$this->_sessionName]['idle'] = time(); |
} |
// }}} |
// {{{ checkAuth() |
/** |
* Checks if there is a session with valid auth information. |
* |
* @access private |
* @return boolean Whether or not the user is authenticated. |
*/ |
function checkAuth() |
{ |
$session = &$this->_importGlobalVariable('session'); |
if (isset($session[$this->_sessionName])) { |
// Check if authentication session is expired |
if ($this->expire > 0 && |
isset($session[$this->_sessionName]['timestamp']) && |
($session[$this->_sessionName]['timestamp'] + $this->expire) < time()) { |
$this->logout(); |
$this->expired = true; |
$this->status = AUTH_EXPIRED; |
return false; |
} |
// Check if maximum idle time is reached |
if ($this->idle > 0 && |
isset($session[$this->_sessionName]['idle']) && |
($session[$this->_sessionName]['idle'] + $this->idle) < time()) { |
$this->logout(); |
$this->idled = true; |
$this->status = AUTH_IDLED; |
return false; |
} |
if (isset($session[$this->_sessionName]['registered']) && |
isset($session[$this->_sessionName]['username']) && |
$session[$this->_sessionName]['registered'] == true && |
$session[$this->_sessionName]['username'] != '') { |
Auth::updateIdle(); |
return true; |
} |
} |
return false; |
} |
// }}} |
// {{{ getAuth() |
/** |
* Has the user been authenticated? |
* |
* @access public |
* @return bool True if the user is logged in, otherwise false. |
*/ |
function getAuth() |
{ |
$session = &$this->_importGlobalVariable('session'); |
if (!empty($session) && |
(isset($session[$this->_sessionName]['registered']) && |
$session[$this->_sessionName]['registered'] === true)) |
{ |
return true; |
} else { |
return false; |
} |
} |
// }}} |
// {{{ drawLogin() |
/** |
* Draw the login form |
* |
* Normally you will not use this output in your application, |
* because you can pass a different function name to the |
* constructor. For more information on this, please |
* consult the documentation. |
* |
* @access private |
* @param string Username if already entered |
* @return void |
*/ |
function drawLogin($username = '') |
{ |
if (is_callable($this->loginFunction)) { |
call_user_func($this->loginFunction, $username, $this->status, $this); |
} else { |
$server = &$this->_importGlobalVariable('server'); |
echo '<center>'."\n"; |
if (!empty($this->status) && $this->status == AUTH_EXPIRED) { |
echo '<i>Your session expired. Please login again!</i>'."\n"; |
} else if (!empty($this->status) && $this->status == AUTH_IDLED) { |
echo '<i>You have been idle for too long. Please login again!</i>'."\n"; |
} else if (!empty ($this->status) && $this->status == AUTH_WRONG_LOGIN) { |
echo '<i>Wrong login data!</i>'."\n"; |
} |
PEAR::raiseError('You are using the built-in login screen of PEAR::Auth.<br />See the <a href="http://pear.php.net/manual/">manual</a> for details on how to create your own login function.', null); |
echo '<form method="post" action="' . $server['PHP_SELF'] . '">'."\n"; |
echo '<table border="0" cellpadding="2" cellspacing="0" summary="login form">'."\n"; |
echo '<tr>'."\n"; |
echo ' <td colspan="2" bgcolor="#eeeeee"><b>Login:</b></td>'."\n"; |
echo '</tr>'."\n"; |
echo '<tr>'."\n"; |
echo ' <td>Username:</td>'."\n"; |
echo ' <td><input type="text" name="username" value="' . $username . '" /></td>'."\n"; |
echo '</tr>'."\n"; |
echo '<tr>'."\n"; |
echo ' <td>Password:</td>'."\n"; |
echo ' <td><input type="password" name="password" /></td>'."\n"; |
echo '</tr>'."\n"; |
echo '<tr>'."\n"; |
echo ' <td colspan="2" bgcolor="#eeeeee"><input type="submit" /></td>'."\n"; |
echo '</tr>'."\n"; |
echo '</table>'."\n"; |
echo '</form>'."\n"; |
echo '</center>'."\n\n"; |
} |
} |
// }}} |
// {{{ logout() |
/** |
* Logout function |
* |
* This function clears any auth tokens in the currently |
* active session and executes the logout callback function, |
* if any |
* |
* @access public |
* @return void |
*/ |
function logout() |
{ |
$session = &$this->_importGlobalVariable('session'); |
if (is_callable($this->logoutCallback)) { |
call_user_func($this->logoutCallback, $session[$this->_sessionName]['username'], $this); |
} |
$this->username = ''; |
$this->password = ''; |
$session[$this->_sessionName] = array(); |
if (isset($_SESSION)) { |
unset($session[$this->_sessionName]); |
} else { |
session_unregister($this->_sessionName); |
} |
} |
// }}} |
// {{{ updateIdle() |
/** |
* Update the idletime |
* |
* @access private |
* @return void |
*/ |
function updateIdle() |
{ |
$session = &$this->_importGlobalVariable('session'); |
$session[$this->_sessionName]['idle'] = time(); |
} |
// }}} |
// {{{ getUsername() |
/** |
* Get the username |
* |
* @access public |
* @return string |
*/ |
function getUsername() |
{ |
$session = &$this->_importGlobalVariable('session'); |
if (!isset($session[$this->_sessionName]['username'])) { |
return ''; |
} |
return $session[$this->_sessionName]['username']; |
} |
// }}} |
// {{{ getStatus() |
/** |
* Get the current status |
* |
* @access public |
* @return string |
*/ |
function getStatus() |
{ |
return $this->status; |
} |
// }}} |
// {{{ sessionValidThru() |
/** |
* Returns the time up to the session is valid |
* |
* @access public |
* @return integer |
*/ |
function sessionValidThru() |
{ |
$session = &$this->_importGlobalVariable('session'); |
if (!isset($session[$this->_sessionName]['idle'])) { |
return 0; |
} |
return ($session[$this->_sessionName]['idle'] + $this->idle); |
} |
// }}} |
// {{{ listUsers() |
/** |
* List all users that are currently available in the storage |
* container |
* |
* @access public |
* @return array |
*/ |
function listUsers() |
{ |
return $this->storage->listUsers(); |
} |
// }}} |
// {{{ addUser() |
/** |
* Add user to the storage container |
* |
* @access public |
* @param string Username |
* @param string Password |
* @param mixed Additional parameters |
* @return mixed True on success, PEAR error object on error |
* and AUTH_METHOD_NOT_SUPPORTED otherwise. |
*/ |
function addUser($username, $password, $additional = '') |
{ |
return $this->storage->addUser($username, $password, $additional); |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @access public |
* @param string Username |
* @return mixed True on success, PEAR error object on error |
* and AUTH_METHOD_NOT_SUPPORTED otherwise. |
*/ |
function removeUser($username) |
{ |
return $this->storage->removeUser($username); |
} |
// }}} |
// {{{ _importGlobalVariable() |
/** |
* Import variables from special namespaces. |
* |
* @access private |
* @param string Type of variable (server, session, post) |
* @return array |
*/ |
function &_importGlobalVariable($variable) |
{ |
$var = null; |
switch (strtolower($variable)) { |
case 'server' : |
if (isset($_SERVER)) { |
$var = &$_SERVER; |
} else { |
$var = &$GLOBALS['HTTP_SERVER_VARS']; |
} |
break; |
case 'session' : |
if (isset($_SESSION)) { |
$var = &$_SESSION; |
} else { |
$var = &$GLOBALS['HTTP_SESSION_VARS']; |
} |
break; |
case 'post' : |
if (isset($_POST)) { |
$var = &$_POST; |
} else { |
$var = &$GLOBALS['HTTP_POST_VARS']; |
} |
break; |
case 'cookie' : |
if (isset($_COOKIE)) { |
$var = &$_COOKIE; |
} else { |
$var = &$GLOBALS['HTTP_COOKIE_VARS']; |
} |
break; |
case 'get' : |
if (isset($_GET)) { |
$var = &$_GET; |
} else { |
$var = &$GLOBALS['HTTP_GET_VARS']; |
} |
break; |
default: |
break; |
} |
return $var; |
} |
// }}} |
} |
?> |
/trunk/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.1 2005-03-30 08:50:19 jpm 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.5 |
* @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.5'; |
} |
// }}} |
// {{{ 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.5 |
* @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.5 |
* @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.5 |
* @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: |
*/ |
?> |
/trunk/api/pear/PEAR.php |
---|
New file |
0,0 → 1,1055 |
<?php |
// |
// +--------------------------------------------------------------------+ |
// | PEAR, the PHP Extension and Application Repository | |
// +--------------------------------------------------------------------+ |
// | Copyright (c) 1997-2004 The PHP Group | |
// +--------------------------------------------------------------------+ |
// | This source file is subject to version 3.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available through the world-wide-web at the following url: | |
// | http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +--------------------------------------------------------------------+ |
// | Authors: Sterling Hughes <sterling@php.net> | |
// | Stig Bakken <ssb@php.net> | |
// | Tomas V.V.Cox <cox@idecnet.com> | |
// +--------------------------------------------------------------------+ |
// |
// $Id: PEAR.php,v 1.1 2005-03-30 08:50:19 jpm Exp $ |
// |
define('PEAR_ERROR_RETURN', 1); |
define('PEAR_ERROR_PRINT', 2); |
define('PEAR_ERROR_TRIGGER', 4); |
define('PEAR_ERROR_DIE', 8); |
define('PEAR_ERROR_CALLBACK', 16); |
/** |
* WARNING: obsolete |
* @deprecated |
*/ |
define('PEAR_ERROR_EXCEPTION', 32); |
define('PEAR_ZE2', (function_exists('version_compare') && |
version_compare(zend_version(), "2-dev", "ge"))); |
if (substr(PHP_OS, 0, 3) == 'WIN') { |
define('OS_WINDOWS', true); |
define('OS_UNIX', false); |
define('PEAR_OS', 'Windows'); |
} else { |
define('OS_WINDOWS', false); |
define('OS_UNIX', true); |
define('PEAR_OS', 'Unix'); // blatant assumption |
} |
// instant backwards compatibility |
if (!defined('PATH_SEPARATOR')) { |
if (OS_WINDOWS) { |
define('PATH_SEPARATOR', ';'); |
} else { |
define('PATH_SEPARATOR', ':'); |
} |
} |
$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; |
$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; |
$GLOBALS['_PEAR_destructor_object_list'] = array(); |
$GLOBALS['_PEAR_shutdown_funcs'] = array(); |
$GLOBALS['_PEAR_error_handler_stack'] = array(); |
@ini_set('track_errors', true); |
/** |
* Base class for other PEAR classes. Provides rudimentary |
* emulation of destructors. |
* |
* If you want a destructor in your class, inherit PEAR and make a |
* destructor method called _yourclassname (same name as the |
* constructor, but with a "_" prefix). Also, in your constructor you |
* have to call the PEAR constructor: $this->PEAR();. |
* The destructor method will be called without parameters. Note that |
* at in some SAPI implementations (such as Apache), any output during |
* the request shutdown (in which destructors are called) seems to be |
* discarded. If you need to get any debug information from your |
* destructor, use error_log(), syslog() or something similar. |
* |
* IMPORTANT! To use the emulated destructors you need to create the |
* objects by reference: $obj =& new PEAR_child; |
* |
* @since PHP 4.0.2 |
* @author Stig Bakken <ssb@php.net> |
* @see http://pear.php.net/manual/ |
*/ |
class PEAR |
{ |
// {{{ properties |
/** |
* Whether to enable internal debug messages. |
* |
* @var bool |
* @access private |
*/ |
var $_debug = false; |
/** |
* Default error mode for this object. |
* |
* @var int |
* @access private |
*/ |
var $_default_error_mode = null; |
/** |
* Default error options used for this object when error mode |
* is PEAR_ERROR_TRIGGER. |
* |
* @var int |
* @access private |
*/ |
var $_default_error_options = null; |
/** |
* Default error handler (callback) for this object, if error mode is |
* PEAR_ERROR_CALLBACK. |
* |
* @var string |
* @access private |
*/ |
var $_default_error_handler = ''; |
/** |
* Which class to use for error objects. |
* |
* @var string |
* @access private |
*/ |
var $_error_class = 'PEAR_Error'; |
/** |
* An array of expected errors. |
* |
* @var array |
* @access private |
*/ |
var $_expected_errors = array(); |
// }}} |
// {{{ constructor |
/** |
* Constructor. Registers this object in |
* $_PEAR_destructor_object_list for destructor emulation if a |
* destructor object exists. |
* |
* @param string $error_class (optional) which class to use for |
* error objects, defaults to PEAR_Error. |
* @access public |
* @return void |
*/ |
function PEAR($error_class = null) |
{ |
$classname = strtolower(get_class($this)); |
if ($this->_debug) { |
print "PEAR constructor called, class=$classname\n"; |
} |
if ($error_class !== null) { |
$this->_error_class = $error_class; |
} |
while ($classname && strcasecmp($classname, "pear")) { |
$destructor = "_$classname"; |
if (method_exists($this, $destructor)) { |
global $_PEAR_destructor_object_list; |
$_PEAR_destructor_object_list[] = &$this; |
if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { |
register_shutdown_function("_PEAR_call_destructors"); |
$GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; |
} |
break; |
} else { |
$classname = get_parent_class($classname); |
} |
} |
} |
// }}} |
// {{{ destructor |
/** |
* Destructor (the emulated type of...). Does nothing right now, |
* but is included for forward compatibility, so subclass |
* destructors should always call it. |
* |
* See the note in the class desciption about output from |
* destructors. |
* |
* @access public |
* @return void |
*/ |
function _PEAR() { |
if ($this->_debug) { |
printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); |
} |
} |
// }}} |
// {{{ getStaticProperty() |
/** |
* If you have a class that's mostly/entirely static, and you need static |
* properties, you can use this method to simulate them. Eg. in your method(s) |
* do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); |
* You MUST use a reference, or they will not persist! |
* |
* @access public |
* @param string $class The calling classname, to prevent clashes |
* @param string $var The variable to retrieve. |
* @return mixed A reference to the variable. If not set it will be |
* auto initialised to NULL. |
*/ |
function &getStaticProperty($class, $var) |
{ |
static $properties; |
return $properties[$class][$var]; |
} |
// }}} |
// {{{ registerShutdownFunc() |
/** |
* Use this function to register a shutdown method for static |
* classes. |
* |
* @access public |
* @param mixed $func The function name (or array of class/method) to call |
* @param mixed $args The arguments to pass to the function |
* @return void |
*/ |
function registerShutdownFunc($func, $args = array()) |
{ |
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); |
} |
// }}} |
// {{{ isError() |
/** |
* Tell whether a value is a PEAR error. |
* |
* @param mixed $data the value to test |
* @param int $code if $data is an error object, return true |
* only if $code is a string and |
* $obj->getMessage() == $code or |
* $code is an integer and $obj->getCode() == $code |
* @access public |
* @return bool true if parameter is an error |
*/ |
function isError($data, $code = null) |
{ |
if (is_a($data, 'PEAR_Error')) { |
if (is_null($code)) { |
return true; |
} elseif (is_string($code)) { |
return $data->getMessage() == $code; |
} else { |
return $data->getCode() == $code; |
} |
} |
return false; |
} |
// }}} |
// {{{ setErrorHandling() |
/** |
* Sets how errors generated by this object should be handled. |
* Can be invoked both in objects and statically. If called |
* statically, setErrorHandling sets the default behaviour for all |
* PEAR objects. If called in an object, setErrorHandling sets |
* the default behaviour for that object. |
* |
* @param int $mode |
* One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. |
* |
* @param mixed $options |
* When $mode is PEAR_ERROR_TRIGGER, this is the error level (one |
* of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
* |
* When $mode is PEAR_ERROR_CALLBACK, this parameter is expected |
* to be the callback function or method. A callback |
* function is a string with the name of the function, a |
* callback method is an array of two elements: the element |
* at index 0 is the object, and the element at index 1 is |
* the name of the method to call in the object. |
* |
* When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is |
* a printf format string used when printing the error |
* message. |
* |
* @access public |
* @return void |
* @see PEAR_ERROR_RETURN |
* @see PEAR_ERROR_PRINT |
* @see PEAR_ERROR_TRIGGER |
* @see PEAR_ERROR_DIE |
* @see PEAR_ERROR_CALLBACK |
* @see PEAR_ERROR_EXCEPTION |
* |
* @since PHP 4.0.5 |
*/ |
function setErrorHandling($mode = null, $options = null) |
{ |
if (isset($this) && is_a($this, 'PEAR')) { |
$setmode = &$this->_default_error_mode; |
$setoptions = &$this->_default_error_options; |
} else { |
$setmode = &$GLOBALS['_PEAR_default_error_mode']; |
$setoptions = &$GLOBALS['_PEAR_default_error_options']; |
} |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$setmode = $mode; |
$setoptions = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$setmode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$setoptions = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
} |
// }}} |
// {{{ expectError() |
/** |
* This method is used to tell which errors you expect to get. |
* Expected errors are always returned with error mode |
* PEAR_ERROR_RETURN. Expected error codes are stored in a stack, |
* and this method pushes a new element onto it. The list of |
* expected errors are in effect until they are popped off the |
* stack with the popExpect() method. |
* |
* Note that this method can not be called statically |
* |
* @param mixed $code a single error code or an array of error codes to expect |
* |
* @return int the new depth of the "expected errors" stack |
* @access public |
*/ |
function expectError($code = '*') |
{ |
if (is_array($code)) { |
array_push($this->_expected_errors, $code); |
} else { |
array_push($this->_expected_errors, array($code)); |
} |
return sizeof($this->_expected_errors); |
} |
// }}} |
// {{{ popExpect() |
/** |
* This method pops one element off the expected error codes |
* stack. |
* |
* @return array the list of error codes that were popped |
*/ |
function popExpect() |
{ |
return array_pop($this->_expected_errors); |
} |
// }}} |
// {{{ _checkDelExpect() |
/** |
* This method checks unsets an error code if available |
* |
* @param mixed error code |
* @return bool true if the error code was unset, false otherwise |
* @access private |
* @since PHP 4.3.0 |
*/ |
function _checkDelExpect($error_code) |
{ |
$deleted = false; |
foreach ($this->_expected_errors AS $key => $error_array) { |
if (in_array($error_code, $error_array)) { |
unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); |
$deleted = true; |
} |
// clean up empty arrays |
if (0 == count($this->_expected_errors[$key])) { |
unset($this->_expected_errors[$key]); |
} |
} |
return $deleted; |
} |
// }}} |
// {{{ delExpect() |
/** |
* This method deletes all occurences of the specified element from |
* the expected error codes stack. |
* |
* @param mixed $error_code error code that should be deleted |
* @return mixed list of error codes that were deleted or error |
* @access public |
* @since PHP 4.3.0 |
*/ |
function delExpect($error_code) |
{ |
$deleted = false; |
if ((is_array($error_code) && (0 != count($error_code)))) { |
// $error_code is a non-empty array here; |
// we walk through it trying to unset all |
// values |
foreach($error_code as $key => $error) { |
if ($this->_checkDelExpect($error)) { |
$deleted = true; |
} else { |
$deleted = false; |
} |
} |
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
} elseif (!empty($error_code)) { |
// $error_code comes alone, trying to unset it |
if ($this->_checkDelExpect($error_code)) { |
return true; |
} else { |
return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME |
} |
} else { |
// $error_code is empty |
return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME |
} |
} |
// }}} |
// {{{ raiseError() |
/** |
* This method is a wrapper that returns an instance of the |
* configured error class with this object's default error |
* handling applied. If the $mode and $options parameters are not |
* specified, the object's defaults are used. |
* |
* @param mixed $message a text error message or a PEAR error object |
* |
* @param int $code a numeric error code (it is up to your class |
* to define these if you want to use codes) |
* |
* @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
* PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. |
* |
* @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter |
* specifies the PHP-internal error level (one of |
* E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
* If $mode is PEAR_ERROR_CALLBACK, this |
* parameter specifies the callback function or |
* method. In other error modes this parameter |
* is ignored. |
* |
* @param string $userinfo If you need to pass along for example debug |
* information, this parameter is meant for that. |
* |
* @param string $error_class The returned error object will be |
* instantiated from this class, if specified. |
* |
* @param bool $skipmsg If true, raiseError will only pass error codes, |
* the error message parameter will be dropped. |
* |
* @access public |
* @return object a PEAR error object |
* @see PEAR::setErrorHandling |
* @since PHP 4.0.5 |
*/ |
function raiseError($message = null, |
$code = null, |
$mode = null, |
$options = null, |
$userinfo = null, |
$error_class = null, |
$skipmsg = false) |
{ |
// The error is yet a PEAR error object |
if (is_object($message)) { |
$code = $message->getCode(); |
$userinfo = $message->getUserInfo(); |
$error_class = $message->getType(); |
$message->error_message_prefix = ''; |
$message = $message->getMessage(); |
} |
if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { |
if ($exp[0] == "*" || |
(is_int(reset($exp)) && in_array($code, $exp)) || |
(is_string(reset($exp)) && in_array($message, $exp))) { |
$mode = PEAR_ERROR_RETURN; |
} |
} |
// No mode given, try global ones |
if ($mode === null) { |
// Class error handler |
if (isset($this) && isset($this->_default_error_mode)) { |
$mode = $this->_default_error_mode; |
$options = $this->_default_error_options; |
// Global error handler |
} elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { |
$mode = $GLOBALS['_PEAR_default_error_mode']; |
$options = $GLOBALS['_PEAR_default_error_options']; |
} |
} |
if ($error_class !== null) { |
$ec = $error_class; |
} elseif (isset($this) && isset($this->_error_class)) { |
$ec = $this->_error_class; |
} else { |
$ec = 'PEAR_Error'; |
} |
if ($skipmsg) { |
return new $ec($code, $mode, $options, $userinfo); |
} else { |
return new $ec($message, $code, $mode, $options, $userinfo); |
} |
} |
// }}} |
// {{{ throwError() |
/** |
* Simpler form of raiseError with fewer options. In most cases |
* message, code and userinfo are enough. |
* |
* @param string $message |
* |
*/ |
function throwError($message = null, |
$code = null, |
$userinfo = null) |
{ |
if (isset($this) && is_a($this, 'PEAR')) { |
return $this->raiseError($message, $code, null, null, $userinfo); |
} else { |
return PEAR::raiseError($message, $code, null, null, $userinfo); |
} |
} |
// }}} |
function staticPushErrorHandling($mode, $options = null) |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
$def_mode = &$GLOBALS['_PEAR_default_error_mode']; |
$def_options = &$GLOBALS['_PEAR_default_error_options']; |
$stack[] = array($def_mode, $def_options); |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$def_mode = $mode; |
$def_options = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$def_mode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$def_options = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
$stack[] = array($mode, $options); |
return true; |
} |
function staticPopErrorHandling() |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
$setmode = &$GLOBALS['_PEAR_default_error_mode']; |
$setoptions = &$GLOBALS['_PEAR_default_error_options']; |
array_pop($stack); |
list($mode, $options) = $stack[sizeof($stack) - 1]; |
array_pop($stack); |
switch ($mode) { |
case PEAR_ERROR_EXCEPTION: |
case PEAR_ERROR_RETURN: |
case PEAR_ERROR_PRINT: |
case PEAR_ERROR_TRIGGER: |
case PEAR_ERROR_DIE: |
case null: |
$setmode = $mode; |
$setoptions = $options; |
break; |
case PEAR_ERROR_CALLBACK: |
$setmode = $mode; |
// class/object method callback |
if (is_callable($options)) { |
$setoptions = $options; |
} else { |
trigger_error("invalid error callback", E_USER_WARNING); |
} |
break; |
default: |
trigger_error("invalid error mode", E_USER_WARNING); |
break; |
} |
return true; |
} |
// {{{ pushErrorHandling() |
/** |
* Push a new error handler on top of the error handler options stack. With this |
* you can easily override the actual error handler for some code and restore |
* it later with popErrorHandling. |
* |
* @param mixed $mode (same as setErrorHandling) |
* @param mixed $options (same as setErrorHandling) |
* |
* @return bool Always true |
* |
* @see PEAR::setErrorHandling |
*/ |
function pushErrorHandling($mode, $options = null) |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
if (isset($this) && is_a($this, 'PEAR')) { |
$def_mode = &$this->_default_error_mode; |
$def_options = &$this->_default_error_options; |
} else { |
$def_mode = &$GLOBALS['_PEAR_default_error_mode']; |
$def_options = &$GLOBALS['_PEAR_default_error_options']; |
} |
$stack[] = array($def_mode, $def_options); |
if (isset($this) && is_a($this, 'PEAR')) { |
$this->setErrorHandling($mode, $options); |
} else { |
PEAR::setErrorHandling($mode, $options); |
} |
$stack[] = array($mode, $options); |
return true; |
} |
// }}} |
// {{{ popErrorHandling() |
/** |
* Pop the last error handler used |
* |
* @return bool Always true |
* |
* @see PEAR::pushErrorHandling |
*/ |
function popErrorHandling() |
{ |
$stack = &$GLOBALS['_PEAR_error_handler_stack']; |
array_pop($stack); |
list($mode, $options) = $stack[sizeof($stack) - 1]; |
array_pop($stack); |
if (isset($this) && is_a($this, 'PEAR')) { |
$this->setErrorHandling($mode, $options); |
} else { |
PEAR::setErrorHandling($mode, $options); |
} |
return true; |
} |
// }}} |
// {{{ loadExtension() |
/** |
* OS independant PHP extension load. Remember to take care |
* on the correct extension name for case sensitive OSes. |
* |
* @param string $ext The extension name |
* @return bool Success or not on the dl() call |
*/ |
function loadExtension($ext) |
{ |
if (!extension_loaded($ext)) { |
// if either returns true dl() will produce a FATAL error, stop that |
if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { |
return false; |
} |
if (OS_WINDOWS) { |
$suffix = '.dll'; |
} elseif (PHP_OS == 'HP-UX') { |
$suffix = '.sl'; |
} elseif (PHP_OS == 'AIX') { |
$suffix = '.a'; |
} elseif (PHP_OS == 'OSX') { |
$suffix = '.bundle'; |
} else { |
$suffix = '.so'; |
} |
return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); |
} |
return true; |
} |
// }}} |
} |
// {{{ _PEAR_call_destructors() |
function _PEAR_call_destructors() |
{ |
global $_PEAR_destructor_object_list; |
if (is_array($_PEAR_destructor_object_list) && |
sizeof($_PEAR_destructor_object_list)) |
{ |
reset($_PEAR_destructor_object_list); |
if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { |
$_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); |
} |
while (list($k, $objref) = each($_PEAR_destructor_object_list)) { |
$classname = get_class($objref); |
while ($classname) { |
$destructor = "_$classname"; |
if (method_exists($objref, $destructor)) { |
$objref->$destructor(); |
break; |
} else { |
$classname = get_parent_class($classname); |
} |
} |
} |
// Empty the object list to ensure that destructors are |
// not called more than once. |
$_PEAR_destructor_object_list = array(); |
} |
// Now call the shutdown functions |
if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { |
foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { |
call_user_func_array($value[0], $value[1]); |
} |
} |
} |
// }}} |
class PEAR_Error |
{ |
// {{{ properties |
var $error_message_prefix = ''; |
var $mode = PEAR_ERROR_RETURN; |
var $level = E_USER_NOTICE; |
var $code = -1; |
var $message = ''; |
var $userinfo = ''; |
var $backtrace = null; |
// }}} |
// {{{ constructor |
/** |
* PEAR_Error constructor |
* |
* @param string $message message |
* |
* @param int $code (optional) error code |
* |
* @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, |
* PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, |
* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION |
* |
* @param mixed $options (optional) error level, _OR_ in the case of |
* PEAR_ERROR_CALLBACK, the callback function or object/method |
* tuple. |
* |
* @param string $userinfo (optional) additional user/debug info |
* |
* @access public |
* |
*/ |
function PEAR_Error($message = 'unknown error', $code = null, |
$mode = null, $options = null, $userinfo = null) |
{ |
if ($mode === null) { |
$mode = PEAR_ERROR_RETURN; |
} |
$this->message = $message; |
$this->code = $code; |
$this->mode = $mode; |
$this->userinfo = $userinfo; |
if (function_exists("debug_backtrace")) { |
if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { |
$this->backtrace = debug_backtrace(); |
} |
} |
if ($mode & PEAR_ERROR_CALLBACK) { |
$this->level = E_USER_NOTICE; |
$this->callback = $options; |
} else { |
if ($options === null) { |
$options = E_USER_NOTICE; |
} |
$this->level = $options; |
$this->callback = null; |
} |
if ($this->mode & PEAR_ERROR_PRINT) { |
if (is_null($options) || is_int($options)) { |
$format = "%s"; |
} else { |
$format = $options; |
} |
printf($format, $this->getMessage()); |
} |
if ($this->mode & PEAR_ERROR_TRIGGER) { |
trigger_error($this->getMessage(), $this->level); |
} |
if ($this->mode & PEAR_ERROR_DIE) { |
$msg = $this->getMessage(); |
if (is_null($options) || is_int($options)) { |
$format = "%s"; |
if (substr($msg, -1) != "\n") { |
$msg .= "\n"; |
} |
} else { |
$format = $options; |
} |
die(sprintf($format, $msg)); |
} |
if ($this->mode & PEAR_ERROR_CALLBACK) { |
if (is_callable($this->callback)) { |
call_user_func($this->callback, $this); |
} |
} |
if ($this->mode & PEAR_ERROR_EXCEPTION) { |
trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING); |
eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);'); |
} |
} |
// }}} |
// {{{ getMode() |
/** |
* Get the error mode from an error object. |
* |
* @return int error mode |
* @access public |
*/ |
function getMode() { |
return $this->mode; |
} |
// }}} |
// {{{ getCallback() |
/** |
* Get the callback function/method from an error object. |
* |
* @return mixed callback function or object/method array |
* @access public |
*/ |
function getCallback() { |
return $this->callback; |
} |
// }}} |
// {{{ getMessage() |
/** |
* Get the error message from an error object. |
* |
* @return string full error message |
* @access public |
*/ |
function getMessage() |
{ |
return ($this->error_message_prefix . $this->message); |
} |
// }}} |
// {{{ getCode() |
/** |
* Get error code from an error object |
* |
* @return int error code |
* @access public |
*/ |
function getCode() |
{ |
return $this->code; |
} |
// }}} |
// {{{ getType() |
/** |
* Get the name of this error/exception. |
* |
* @return string error/exception name (type) |
* @access public |
*/ |
function getType() |
{ |
return get_class($this); |
} |
// }}} |
// {{{ getUserInfo() |
/** |
* Get additional user-supplied information. |
* |
* @return string user-supplied information |
* @access public |
*/ |
function getUserInfo() |
{ |
return $this->userinfo; |
} |
// }}} |
// {{{ getDebugInfo() |
/** |
* Get additional debug information supplied by the application. |
* |
* @return string debug information |
* @access public |
*/ |
function getDebugInfo() |
{ |
return $this->getUserInfo(); |
} |
// }}} |
// {{{ getBacktrace() |
/** |
* Get the call backtrace from where the error was generated. |
* Supported with PHP 4.3.0 or newer. |
* |
* @param int $frame (optional) what frame to fetch |
* @return array Backtrace, or NULL if not available. |
* @access public |
*/ |
function getBacktrace($frame = null) |
{ |
if ($frame === null) { |
return $this->backtrace; |
} |
return $this->backtrace[$frame]; |
} |
// }}} |
// {{{ addUserInfo() |
function addUserInfo($info) |
{ |
if (empty($this->userinfo)) { |
$this->userinfo = $info; |
} else { |
$this->userinfo .= " ** $info"; |
} |
} |
// }}} |
// {{{ toString() |
/** |
* Make a string representation of this object. |
* |
* @return string a string with an object summary |
* @access public |
*/ |
function toString() { |
$modes = array(); |
$levels = array(E_USER_NOTICE => 'notice', |
E_USER_WARNING => 'warning', |
E_USER_ERROR => 'error'); |
if ($this->mode & PEAR_ERROR_CALLBACK) { |
if (is_array($this->callback)) { |
$callback = (is_object($this->callback[0]) ? |
strtolower(get_class($this->callback[0])) : |
$this->callback[0]) . '::' . |
$this->callback[1]; |
} else { |
$callback = $this->callback; |
} |
return sprintf('[%s: message="%s" code=%d mode=callback '. |
'callback=%s prefix="%s" info="%s"]', |
strtolower(get_class($this)), $this->message, $this->code, |
$callback, $this->error_message_prefix, |
$this->userinfo); |
} |
if ($this->mode & PEAR_ERROR_PRINT) { |
$modes[] = 'print'; |
} |
if ($this->mode & PEAR_ERROR_TRIGGER) { |
$modes[] = 'trigger'; |
} |
if ($this->mode & PEAR_ERROR_DIE) { |
$modes[] = 'die'; |
} |
if ($this->mode & PEAR_ERROR_RETURN) { |
$modes[] = 'return'; |
} |
return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. |
'prefix="%s" info="%s"]', |
strtolower(get_class($this)), $this->message, $this->code, |
implode("|", $modes), $levels[$this->level], |
$this->error_message_prefix, |
$this->userinfo); |
} |
// }}} |
} |
/* |
* Local Variables: |
* mode: php |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/trunk/api/pear/Auth/Container.php |
---|
New file |
0,0 → 1,177 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Martin Jansen <mj@php.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: Container.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
define("AUTH_METHOD_NOT_SUPPORTED", -4); |
/** |
* Storage class for fetching login data |
* |
* @author Martin Jansen <mj@php.net> |
* @package Auth |
*/ |
class Auth_Container |
{ |
/** |
* User that is currently selected from the storage container. |
* |
* @access public |
*/ |
var $activeUser = ""; |
// {{{ Constructor |
/** |
* Constructor |
* |
* Has to be overwritten by each storage class |
* |
* @access public |
*/ |
function Auth_Container() |
{ |
} |
// }}} |
// {{{ fetchData() |
/** |
* Fetch data from storage container |
* |
* Has to be overwritten by each storage class |
* |
* @access public |
*/ |
function fetchData() |
{ |
} |
// }}} |
// {{{ verifyPassword() |
/** |
* Crypt and verfiy the entered password |
* |
* @param string Entered password |
* @param string Password from the data container (usually this password |
* is already encrypted. |
* @param string Type of algorithm with which the password from |
* the container has been crypted. (md5, crypt etc.) |
* Defaults to "md5". |
* @return bool True, if the passwords match |
*/ |
function verifyPassword($password1, $password2, $cryptType = "md5") |
{ |
switch ($cryptType) { |
case "crypt" : |
return (($password2 == "**" . $password1) || |
(crypt($password1, $password2) == $password2) |
); |
break; |
case "none" : |
return ($password1 == $password2); |
break; |
case "md5" : |
return (md5($password1) == $password2); |
break; |
default : |
if (function_exists($cryptType)) { |
return ($cryptType($password1) == $password2); |
} |
else if (method_exists($this,$cryptType)) { |
return ($this->$cryptType($password1) == $password2); |
} else { |
return false; |
} |
break; |
} |
} |
// }}} |
// {{{ listUsers() |
/** |
* List all users that are available from the storage container |
*/ |
function listUsers() |
{ |
return AUTH_METHOD_NOT_SUPPORTED; |
} |
/** |
* Returns a user assoc array |
* |
* Containers which want should overide this |
* |
* @param string The username |
*/ |
function getUser($username) |
{ |
$users = $this->listUsers(); |
if($users === AUTH_METHOD_NOT_SUPPORTED){ |
return(AUTH_METHOD_NOT_SUPPORTED); |
} |
for($i=0;$c = count($users),$i<$c;$i++){ |
if($users[$i]['username'] == $username){ |
return($users[$i]); |
} |
} |
return(false); |
} |
// }}} |
// {{{ addUser() |
/** |
* Add a new user to the storage container |
* |
* @param string Username |
* @param string Password |
* @param array Additional information |
* |
* @return boolean |
*/ |
function addUser($username, $password, $additional=null) |
{ |
return AUTH_METHOD_NOT_SUPPORTED; |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @param string Username |
*/ |
function removeUser($username) |
{ |
return AUTH_METHOD_NOT_SUPPORTED; |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/File.php |
---|
New file |
0,0 → 1,200 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Stefan Ekman <stekman@sedata.org> | |
// | Martin Jansen <mj@php.net> | |
// | Mika Tuupola <tuupola@appelsiini.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: File.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "File/Passwd.php"; |
require_once "Auth/Container.php"; |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from an encrypted password file. |
* |
* This storage container can handle CVS pserver style passwd files. |
* |
* @author Stefan Ekman <stekman@sedata.org> |
* @author Michael Wallner <mike@php.net> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_File extends Auth_Container |
{ |
/** |
* Path to passwd file |
* |
* @var string |
*/ |
var $pwfile = ''; |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* @param string $filename path to passwd file |
* @return object Auth_Container_File new Auth_Container_File object |
*/ |
function Auth_Container_File($filename) |
{ |
$this->pwfile = $filename; |
} |
// }}} |
// {{{ fetchData() |
/** |
* Authenticate an user |
* |
* @param string username |
* @param string password |
* @return mixed boolean|PEAR_Error |
*/ |
function fetchData($user, $pass) |
{ |
return File_Passwd::staticAuth('Cvs', $this->pwfile, $user, $pass); |
} |
// }}} |
// {{{ listUsers() |
/** |
* List all available users |
* |
* @return array |
*/ |
function listUsers() |
{ |
$pw_obj = &$this->_load(); |
if (PEAR::isError($pw_obj)) { |
return array(); |
} |
$users = $pw_obj->listUser(); |
if (!is_array($users)) { |
return array(); |
} |
foreach ($users as $key => $value) { |
$retVal[] = array("username" => $key, |
"password" => $value['passwd'], |
"cvsuser" => $value['system']); |
} |
return $retVal; |
} |
// }}} |
// {{{ addUser() |
/** |
* Add a new user to the storage container |
* |
* @param string username |
* @param string password |
* @param mixed CVS username |
* |
* @return boolean |
*/ |
function addUser($user, $pass, $additional='') |
{ |
$cvs = (string) (is_array($additional) && isset($additional['cvsuser'])) ? |
$additional['cvsuser'] : $additional; |
$pw_obj = &$this->_load(); |
if (PEAR::isError($pw_obj)) { |
return false; |
} |
$res = $pw_obj->addUser($user, $pass, $cvs); |
if(PEAR::isError($res)){ |
return false; |
} |
$res = $pw_obj->save(); |
if (PEAR::isError($res)) { |
return false; |
} |
return true; |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @param string Username |
* @return boolean |
*/ |
function removeUser($user) |
{ |
$pw_obj = &$this->_load(); |
if (PEAR::isError($pw_obj)) { |
return false; |
} |
$res = $pw_obj->delUser($user); |
if(PEAR::isError($res)){ |
return false; |
} |
$res = $pw_obj->save(); |
if (PEAR::isError($res)) { |
return false; |
} |
return true; |
} |
// }}} |
// {{{ _load() |
/** |
* Load and initialize the File_Passwd object |
* |
* @return object File_Passwd_Cvs|PEAR_Error |
*/ |
function &_load() |
{ |
static $pw_obj; |
if (!isset($pw_obj)) { |
$pw_obj = File_Passwd::factory('Cvs'); |
if (PEAR::isError($pw_obj)) { |
return $pw_obj; |
} |
$pw_obj->setFile($this->pwfile); |
$res = $pw_obj->load(); |
if (PEAR::isError($res)) { |
return $res; |
} |
} |
return $pw_obj; |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/LDAP.php |
---|
New file |
0,0 → 1,472 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Jan Wagner <wagner@netsols.de> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: LDAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "Auth/Container.php"; |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from LDAP |
* |
* This class is heavily based on the DB and File containers. By default it |
* connects to localhost:389 and searches for uid=$username with the scope |
* "sub". If no search base is specified, it will try to determine it via |
* the namingContexts attribute. It takes its parameters in a hash, connects |
* to the ldap server, binds anonymously, searches for the user, and tries |
* to bind as the user with the supplied password. When a group was set, it |
* will look for group membership of the authenticated user. If all goes |
* well the authentication was successful. |
* |
* Parameters: |
* |
* host: localhost (default), ldap.netsols.de or 127.0.0.1 |
* port: 389 (default) or 636 or whereever your server runs |
* url: ldap://localhost:389/ |
* useful for ldaps://, works only with openldap2 ? |
* it will be preferred over host and port |
* binddn: If set, searching for user will be done after binding |
* as this user, if not set the bind will be anonymous. |
* This is reported to make the container work with MS |
* Active Directory, but should work with any server that |
* is configured this way. |
* This has to be a complete dn for now (basedn and |
* userdn will not be appended). |
* bindpw: The password to use for binding with binddn |
* scope: one, sub (default), or base |
* basedn: the base dn of your server |
* userdn: gets prepended to basedn when searching for user |
* userattr: the user attribute to search for (default: uid) |
* useroc: objectclass of user (for the search filter) |
* (default: posixAccount) |
* groupdn: gets prepended to basedn when searching for group |
* groupattr : the group attribute to search for (default: cn) |
* groupoc : objectclass of group (for the search filter) |
* (default: groupOfUniqueNames) |
* memberattr : the attribute of the group object where the user dn |
* may be found (default: uniqueMember) |
* memberisdn: whether the memberattr is the dn of the user (default) |
* or the value of userattr (usually uid) |
* group: the name of group to search for |
* debug: Enable/Disable debugging output (default: false) |
* |
* To use this storage container, you have to use the following syntax: |
* |
* <?php |
* ... |
* |
* $a = new Auth("LDAP", array( |
* 'host' => 'localhost', |
* 'port' => '389', |
* 'basedn' => 'o=netsols,c=de', |
* 'userattr' => 'uid' |
* 'binddn' => 'cn=admin,o=netsols,c=de', |
* 'bindpw' => 'password')); |
* |
* $a2 = new Auth('LDAP', array( |
* 'url' => 'ldaps://ldap.netsols.de', |
* 'basedn' => 'o=netsols,c=de', |
* 'scope' => 'one', |
* 'userdn' => 'ou=People', |
* 'groupdn' => 'ou=Groups', |
* 'groupoc' => 'posixGroup', |
* 'memberattr' => 'memberUid', |
* 'memberisdn' => false, |
* 'group' => 'admin' |
* )); |
* |
* $a3 = new Auth('LDAP', array( |
* 'host' => 'ad.netsols.de', |
* 'basedn' => 'dc=netsols,dc=de', |
* 'userdn' => 'ou=Users', |
* 'binddn' => 'cn=Jan Wagner,ou=Users,dc=netsols,dc=de', |
* 'bindpw' => '*******', |
* 'userattr' => 'samAccountName', |
* 'useroc' => 'user', |
* 'debug' => true |
* )); |
* |
* The parameter values have to correspond |
* to the ones for your LDAP server of course. |
* |
* When talking to a Microsoft ActiveDirectory server you have to |
* use 'samaccountname' as the 'userattr' and follow special rules |
* to translate the ActiveDirectory directory names into 'basedn'. |
* The 'basedn' for the default 'Users' folder on an ActiveDirectory |
* server for the ActiveDirectory Domain (which is not related to |
* its DNS name) "win2000.example.org" would be: |
* "CN=Users, DC=win2000, DC=example, DC=org' |
* where every component of the domain name becomes a DC attribute |
* of its own. If you want to use a custom users folder you have to |
* replace "CN=Users" with a sequence of "OU" attributes that specify |
* the path to your custom folder in reverse order. |
* So the ActiveDirectory folder |
* "win2000.example.org\Custom\Accounts" |
* would become |
* "OU=Accounts, OU=Custom, DC=win2000, DC=example, DC=org' |
* |
* It seems that binding anonymously to an Active Directory |
* is not allowed, so you have to set binddn and bindpw for |
* user searching, |
* |
* Example a3 shows a tested example for connenction to Windows 2000 |
* Active Directory |
* |
* @author Jan Wagner <wagner@netsols.de> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_LDAP extends Auth_Container |
{ |
/** |
* Options for the class |
* @var array |
*/ |
var $options = array(); |
/** |
* Connection ID of LDAP Link |
* @var string |
*/ |
var $conn_id = false; |
/** |
* LDAP search function to use |
* @var string |
*/ |
var $ldap_search_func; |
/** |
* Constructor of the container class |
* |
* @param $params, associative hash with host,port,basedn and userattr key |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_LDAP($params) |
{ |
$this->_setDefaults(); |
if (is_array($params)) { |
$this->_parseOptions($params); |
} |
} |
// }}} |
// {{{ _connect() |
/** |
* Connect to the LDAP server using the global options |
* |
* @access private |
* @return object Returns a PEAR error object if an error occurs. |
*/ |
function _connect() |
{ |
// connect |
if (isset($this->options['url']) && $this->options['url'] != '') { |
$this->_debug('Connecting with URL', __LINE__); |
$conn_params = array($this->options['url']); |
} else { |
$this->_debug('Connecting with host:port', __LINE__); |
$conn_params = array($this->options['host'], $this->options['port']); |
} |
if(($this->conn_id = @call_user_func_array('ldap_connect', $conn_params)) === false) { |
return PEAR::raiseError('Auth_Container_LDAP: Could not connect to server.', 41, PEAR_ERROR_DIE); |
} |
$this->_debug('Successfully connected to server', __LINE__); |
// try switchig to LDAPv3 |
$ver = 0; |
if(@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver >= 2) { |
$this->_debug('Switching to LDAPv3', __LINE__); |
@ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, 3); |
} |
// bind with credentials or anonymously |
if($this->options['binddn'] && $this->options['bindpw']) { |
$this->_debug('Binding with credentials', __LINE__); |
$bind_params = array($this->conn_id, $this->options['binddn'], $this->options['bindpw']); |
} else { |
$this->_debug('Binding anonymously', __LINE__); |
$bind_params = array($this->conn_id); |
} |
// bind for searching |
if ((@call_user_func_array('ldap_bind', $bind_params)) == false) { |
$this->_debug(); |
$this->_disconnect(); |
return PEAR::raiseError("Auth_Container_LDAP: Could not bind to LDAP server.", 41, PEAR_ERROR_DIE); |
} |
$this->_debug('Binding was successful', __LINE__); |
} |
/** |
* Disconnects (unbinds) from ldap server |
* |
* @access private |
*/ |
function _disconnect() |
{ |
if($this->_isValidLink()) { |
$this->_debug('disconnecting from server'); |
@ldap_unbind($this->conn_id); |
} |
} |
/** |
* Tries to find Basedn via namingContext Attribute |
* |
* @access private |
*/ |
function _getBaseDN() |
{ |
if ($this->options['basedn'] == "" && $this->_isValidLink()) { |
$this->_debug("basedn not set, searching via namingContexts.", __LINE__); |
$result_id = @ldap_read($this->conn_id, "", "(objectclass=*)", array("namingContexts")); |
if (ldap_count_entries($this->conn_id, $result_id) == 1) { |
$this->_debug("got result for namingContexts", __LINE__); |
$entry_id = ldap_first_entry($this->conn_id, $result_id); |
$attrs = ldap_get_attributes($this->conn_id, $entry_id); |
$basedn = $attrs['namingContexts'][0]; |
if ($basedn != "") { |
$this->_debug("result for namingContexts was $basedn", __LINE__); |
$this->options['basedn'] = $basedn; |
} |
} |
ldap_free_result($result_id); |
} |
// if base ist still not set, raise error |
if ($this->options['basedn'] == "") { |
return PEAR::raiseError("Auth_Container_LDAP: LDAP search base not specified!", 41, PEAR_ERROR_DIE); |
} |
return true; |
} |
/** |
* determines whether there is a valid ldap conenction or not |
* |
* @accessd private |
* @return boolean |
*/ |
function _isValidLink() |
{ |
if(is_resource($this->conn_id)) { |
if(get_resource_type($this->conn_id) == 'ldap link') { |
return true; |
} |
} |
return false; |
} |
/** |
* Set some default options |
* |
* @access private |
*/ |
function _setDefaults() |
{ |
$this->options['host'] = 'localhost'; |
$this->options['port'] = '389'; |
$this->options['binddn'] = ''; |
$this->options['bindpw'] = ''; |
$this->options['scope'] = 'sub'; |
$this->options['basedn'] = ''; |
$this->options['userdn'] = ''; |
$this->options['userattr'] = "uid"; |
$this->options['useroc'] = 'posixAccount'; |
$this->options['groupdn'] = ''; |
$this->options['groupattr'] = 'cn'; |
$this->options['groupoc'] = 'groupOfUniqueNames'; |
$this->options['memberattr'] = 'uniqueMember'; |
$this->options['memberisdn'] = true; |
$this->options['debug'] = false; |
} |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
foreach ($array as $key => $value) { |
$this->options[$key] = $value; |
} |
// get the according search function for selected scope |
switch($this->options['scope']) { |
case 'one': |
$this->ldap_search_func = 'ldap_list'; |
break; |
case 'base': |
$this->ldap_search_func = 'ldap_read'; |
break; |
default: |
$this->ldap_search_func = 'ldap_search'; |
break; |
} |
$this->_debug("LDAP search function will be: {$this->ldap_search_func}", __LINE__); |
} |
/** |
* Fetch data from LDAP server |
* |
* Searches the LDAP server for the given username/password |
* combination. |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
$this->_connect(); |
$this->_getBaseDN(); |
// make search filter |
$filter = sprintf('(&(objectClass=%s)(%s=%s))', $this->options['useroc'], $this->options['userattr'], $username); |
// make search base dn |
$search_basedn = $this->options['userdn']; |
if ($search_basedn != '' && substr($search_basedn, -1) != ',') { |
$search_basedn .= ','; |
} |
$search_basedn .= $this->options['basedn']; |
// make functions params array |
$func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['userattr'])); |
$this->_debug("Searching with $filter in $search_basedn", __LINE__); |
// search |
if (($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) == false) { |
$this->_debug('User not found', __LINE__); |
} elseif (ldap_count_entries($this->conn_id, $result_id) == 1) { // did we get just one entry? |
$this->_debug('User was found', __LINE__); |
// then get the user dn |
$entry_id = ldap_first_entry($this->conn_id, $result_id); |
$user_dn = ldap_get_dn($this->conn_id, $entry_id); |
ldap_free_result($result_id); |
// need to catch an empty password as openldap seems to return TRUE |
// if anonymous binding is allowed |
if ($password != "") { |
$this->_debug("Bind as $user_dn", __LINE__); |
// try binding as this user with the supplied password |
if (@ldap_bind($this->conn_id, $user_dn, $password)) { |
$this->_debug('Bind successful', __LINE__); |
// check group if appropiate |
if(isset($this->options['group'])) { |
// decide whether memberattr value is a dn or the username |
$this->_debug('Checking group membership', __LINE__); |
return $this->checkGroup(($this->options['memberisdn']) ? $user_dn : $username); |
} else { |
$this->_debug('Authenticated', __LINE__); |
$this->_disconnect(); |
return true; // user authenticated |
} // checkGroup |
} // bind |
} // non-empty password |
} // one entry |
// default |
$this->_debug('NOT authenticated!', __LINE__); |
$this->_disconnect(); |
return false; |
} |
/** |
* Validate group membership |
* |
* Searches the LDAP server for group membership of the |
* authenticated user |
* |
* @param string Distinguished Name of the authenticated User |
* @return boolean |
*/ |
function checkGroup($user) |
{ |
// make filter |
$filter = sprintf('(&(%s=%s)(objectClass=%s)(%s=%s))', |
$this->options['groupattr'], |
$this->options['group'], |
$this->options['groupoc'], |
$this->options['memberattr'], |
$user |
); |
// make search base dn |
$search_basedn = $this->options['groupdn']; |
if($search_basedn != '' && substr($search_basedn, -1) != ',') { |
$search_basedn .= ','; |
} |
$search_basedn .= $this->options['basedn']; |
$func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['memberattr'])); |
$this->_debug("Searching with $filter in $search_basedn", __LINE__); |
// search |
if(($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) != false) { |
if(ldap_count_entries($this->conn_id, $result_id) == 1) { |
ldap_free_result($result_id); |
$this->_debug('User is member of group', __LINE__); |
$this->_disconnect(); |
return true; |
} |
} |
// default |
$this->_debug('User is NOT member of group', __LINE__); |
$this->_disconnect(); |
return false; |
} |
/** |
* Outputs debugging messages |
* |
* @access private |
* @param string Debugging Message |
* @param integer Line number |
*/ |
function _debug($msg = '', $line = 0) |
{ |
if($this->options['debug'] === true) { |
if($msg == '' && $this->_isValidLink()) { |
$msg = 'LDAP_Error: ' . @ldap_err2str(@ldap_errno($this->_conn_id)); |
} |
print("$line: $msg <br />"); |
} |
} |
} |
?> |
/trunk/api/pear/Auth/Container/POP3.php |
---|
New file |
0,0 → 1,107 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2002 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Stefan Ekman <stekman@sedata.org> | |
// | Martin Jansen <mj@php.net> | |
// | Mika Tuupola <tuupola@appelsiini.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: POP3.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once('Auth/Container.php'); |
require_once('PEAR.php'); |
require_once('Net/POP3.php'); |
/** |
* Storage driver for Authentication on a POP3 server. |
* |
* @author Yavor Shahpasov <yavo@netsmart.com.cy> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_POP3 extends Auth_Container |
{ |
/** |
* POP3 Server |
* @var string |
*/ |
var $server='localhost'; |
/** |
* POP3 Server port |
* @var string |
*/ |
var $port='110'; |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* @param $server string server or server:port combination |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_POP3($server=null) |
{ |
if(isset($server)){ |
if(is_array($server)){ |
if(isset($server['host'])){ |
$this->server = $server['host']; |
} |
if(isset($server['port'])){ |
$this->port = $server['port']; |
} |
} |
else{ |
if(strstr($server, ':')){ |
$serverparts = explode(':', trim($server)); |
$this->server = $serverparts[0]; |
$this->port = $serverparts[1]; |
} |
else |
{ |
$this->server = $server; |
} |
} |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Try to login to the POP3 server |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
$pop3 =& new Net_POP3(); |
$res = $pop3->connect($this->server, $this->port); |
if(!$res){ |
return($res); |
} |
$result = $pop3->login($username, $password); |
$pop3->disconnect(); |
return $result; |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/MDB.php |
---|
New file |
0,0 → 1,392 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Author: Lorenzo Alberton <l.alberton@quipo.it> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: MDB.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once 'Auth/Container.php'; |
require_once 'MDB.php'; |
/** |
* Storage driver for fetching login data from a database |
* |
* This storage driver can use all databases which are supported |
* by the PEAR MDB abstraction layer to fetch login data. |
* |
* @author Lorenzo Alberton <l.alberton@quipo.it> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_MDB extends Auth_Container |
{ |
/** |
* Additional options for the storage container |
* @var array |
*/ |
var $options = array(); |
/** |
* DB object |
* @var object |
*/ |
var $db = null; |
var $dsn = ''; |
/** |
* User that is currently selected from the DB. |
* @var string |
*/ |
var $activeUser = ''; |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* Initate connection to the database via PEAR::DB |
* |
* @param string Connection data or DB object |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_MDB($dsn) |
{ |
$this->_setDefaults(); |
if (is_array($dsn)) { |
$this->_parseOptions($dsn); |
if (empty($this->options['dsn'])) { |
PEAR::raiseError('No connection parameters specified!'); |
} |
} else { |
$this->options['dsn'] = $dsn; |
} |
} |
// }}} |
// {{{ _connect() |
/** |
* Connect to database by using the given DSN string |
* |
* @access private |
* @param string DSN string |
* @return mixed Object on error, otherwise bool |
*/ |
function _connect($dsn) |
{ |
if (is_string($dsn) || is_array($dsn)) { |
$this->db =& MDB::Connect($dsn); |
} elseif (get_parent_class($dsn) == "mdb_common") { |
$this->db = $dsn; |
} elseif (is_object($dsn) && MDB::isError($dsn)) { |
return PEAR::raiseError($dsn->getMessage(), $dsn->code); |
} else { |
return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__, |
41, |
PEAR_ERROR_RETURN, |
null, |
null |
); |
} |
if (MDB::isError($this->db) || PEAR::isError($this->db)) { |
return PEAR::raiseError($this->db->getMessage(), $this->db->code); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ _prepare() |
/** |
* Prepare database connection |
* |
* This function checks if we have already opened a connection to |
* the database. If that's not the case, a new connection is opened. |
* |
* @access private |
* @return mixed True or a DB error object. |
*/ |
function _prepare() |
{ |
return $this->_connect($this->options['dsn']); |
} |
// }}} |
// {{{ query() |
/** |
* Prepare query to the database |
* |
* This function checks if we have already opened a connection to |
* the database. If that's not the case, a new connection is opened. |
* After that the query is passed to the database. |
* |
* @access public |
* @param string Query string |
* @return mixed a MDB_result object or MDB_OK on success, a MDB |
* or PEAR error on failure |
*/ |
function query($query) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return $err; |
} |
return $this->db->query($query); |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
* @return void |
*/ |
function _setDefaults() |
{ |
$this->options['table'] = 'auth'; |
$this->options['usernamecol'] = 'username'; |
$this->options['passwordcol'] = 'password'; |
$this->options['dsn'] = ''; |
$this->options['db_fields'] = ''; |
$this->options['cryptType'] = 'md5'; |
} |
// }}} |
// {{{ _parseOptions() |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
foreach ($array as $key => $value) { |
if (isset($this->options[$key])) { |
$this->options[$key] = $value; |
} |
} |
// Include additional fields if they exist |
if (!empty($this->options['db_fields'])) { |
if (is_array($this->options['db_fields'])) { |
$this->options['db_fields'] = join($this->options['db_fields'], ', '); |
} |
$this->options['db_fields'] = ', ' . $this->options['db_fields']; |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from database |
* |
* This function uses the given username to fetch |
* the corresponding login data from the database |
* table. If an account that matches the passed username |
* and password is found, the function returns true. |
* Otherwise it returns false. |
* |
* @param string Username |
* @param string Password |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
// Find if db_fileds contains a *, i so assume all col are selected |
if (strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else{ |
$sql_from = $this->options['usernamecol'] . ', '. $this->options['passwordcol'] . $this->options['db_fields']; |
} |
$query = sprintf("SELECT %s FROM %s WHERE %s = %s", |
$sql_from, |
$this->options['table'], |
$this->options['usernamecol'], |
$this->db->getTextValue($username) |
); |
$res = $this->db->getRow($query, null, null, null, MDB_FETCHMODE_ASSOC); |
if (MDB::isError($res) || PEAR::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} |
if (!is_array($res)) { |
$this->activeUser = ''; |
return false; |
} |
if ($this->verifyPassword(trim($password, "\r\n"), |
trim($res[$this->options['passwordcol']], "\r\n"), |
$this->options['cryptType'])) { |
// Store additional field values in the session |
foreach ($res as $key => $value) { |
if ($key == $this->options['passwordcol'] || |
$key == $this->options['usernamecol']) { |
continue; |
} |
// Use reference to the auth object if exists |
// This is because the auth session variable can change so a static call to setAuthData does not make sence |
if(is_object($this->_auth_obj)){ |
$this->_auth_obj->setAuthData($key, $value); |
} else { |
Auth::setAuthData($key, $value); |
} |
} |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
// {{{ listUsers() |
function listUsers() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$retVal = array(); |
// Find if db_fileds contains a *, i so assume all col are selected |
if (strstr($this->options['db_fields'], '*')) { |
$sql_from = '*'; |
} else{ |
$sql_from = $this->options['db_fields']; |
} |
$query = sprintf('SELECT %s FROM %s', |
$sql_from, |
$this->options['table'] |
); |
$res = $this->db->getAll($query, null, null, null, MDB_FETCHMODE_ASSOC); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
foreach ($res as $user) { |
$user['username'] = $user[$this->options['usernamecol']]; |
$retVal[] = $user; |
} |
} |
return $retVal; |
} |
// }}} |
// {{{ addUser() |
/** |
* Add user to the storage container |
* |
* @access public |
* @param string Username |
* @param string Password |
* @param mixed Additional information that are stored in the DB |
* |
* @return mixed True on success, otherwise error object |
*/ |
function addUser($username, $password, $additional = "") |
{ |
if (function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$additional_key = ''; |
$additional_value = ''; |
if (is_array($additional)) { |
foreach ($additional as $key => $value) { |
$additional_key .= ', ' . $key; |
$additional_value .= ', ' . $this->db->getTextValue($value); |
} |
} |
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)", |
$this->options['table'], |
$this->options['usernamecol'], |
$this->options['passwordcol'], |
$additional_key, |
$this->db->getTextValue($username), |
$this->db->getTextValue($cryptFunction($password)), |
$additional_value |
); |
$res = $this->query($query); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @access public |
* @param string Username |
* |
* @return mixed True on success, otherwise error object |
*/ |
function removeUser($username) |
{ |
$query = sprintf("DELETE FROM %s WHERE %s = %s", |
$this->options['table'], |
$this->options['usernamecol'], |
$this->db->getTextValue($username) |
); |
$res = $this->query($query); |
if (MDB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->code); |
} else { |
return true; |
} |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/SOAP.php |
---|
New file |
0,0 → 1,170 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2002 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Bruno Pedro <bpedro@co.sapo.pt> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: SOAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "Auth/Container.php"; |
require_once "PEAR.php"; |
require_once 'SOAP/Client.php'; |
/** |
* Storage driver for fetching login data from SOAP |
* |
* This class takes one parameter (options), where |
* you specify the following fields: endpoint, namespace, |
* method, encoding, usernamefield and passwordfield. |
* |
* You can use specify features of your SOAP service |
* by providing its parameters in an associative manner by |
* using the '_features' array through the options parameter. |
* |
* The 'matchpassword' option should be set to false if your |
* webservice doesn't return (username,password) pairs, but |
* instead returns error when the login is invalid. |
* |
* Example usage: |
* |
* <?php |
* |
* ... |
* |
* $options = array ( |
* 'endpoint' => 'http://your.soap.service/endpoint', |
* 'namespace' => 'urn:/Your/Namespace', |
* 'method' => 'get', |
* 'encoding' => 'UTF-8', |
* 'usernamefield' => 'login', |
* 'passwordfield' => 'password', |
* 'matchpasswords' => false, |
* '_features' => array ( |
* 'example_feature' => 'example_value', |
* 'another_example' => '' |
* ) |
* ); |
* $auth = new Auth('SOAP', $options, 'loginFunction'); |
* $auth->start(); |
* |
* ... |
* |
* ?> |
* |
* @author Bruno Pedro <bpedro@co.sapo.pt> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_SOAP extends Auth_Container |
{ |
/** |
* Required options for the class |
* @var array |
* @access private |
*/ |
var $_requiredOptions = array('endpoint', 'namespace', 'method', 'encoding', 'usernamefield', 'passwordfield'); |
/** |
* Options for the class |
* @var array |
* @access private |
*/ |
var $_options = array(); |
/** |
* Optional SOAP features |
* @var array |
* @access private |
*/ |
var $_features = array(); |
/** |
* The SOAP response |
* @var array |
* @access public |
*/ |
var $soapResponse = array(); |
/** |
* Constructor of the container class |
* |
* @param $options, associative array with endpoint, namespace, method, |
* usernamefield, passwordfield and optional features |
*/ |
function Auth_Container_SOAP($options) |
{ |
$this->_options = $options; |
if (!isset($this->_options['matchpasswords'])) { |
$this->_options['matchpasswords'] = true; |
} |
if (!empty($this->_options['_features'])) { |
$this->_features = $this->_options['_features']; |
unset($this->_options['_features']); |
} |
} |
/** |
* Fetch data from SOAP service |
* |
* Requests the SOAP service for the given username/password |
* combination. |
* |
* @param string Username |
* @param string Password |
* @return mixed Returns the SOAP response or false if something went wrong |
*/ |
function fetchData($username, $password) |
{ |
// check if all required options are set |
if (array_intersect($this->_requiredOptions, array_keys($this->_options)) != $this->_requiredOptions) { |
return false; |
} else { |
// create a SOAP client and set encoding |
$soapClient = new SOAP_Client($this->_options['endpoint']); |
$soapClient->setEncoding($this->_options['encoding']); |
} |
// assign username and password fields |
$usernameField = new SOAP_Value($this->_options['usernamefield'],'string', $username); |
$passwordField = new SOAP_Value($this->_options['passwordfield'],'string', $password); |
$SOAPParams = array($usernameField, $passwordField); |
// assign optional features |
foreach ($this->_features as $fieldName => $fieldValue) { |
$SOAPParams[] = new SOAP_Value($fieldName, 'string', $fieldValue); |
} |
// make SOAP call |
$this->soapResponse = $soapClient->call( |
$this->_options['method'], |
$SOAPParams, |
array('namespace' => $this->_options['namespace']) |
); |
if (!PEAR::isError($this->soapResponse)) { |
if ($this->_options['matchpasswords']) { |
// check if passwords match |
if ($password == $this->soapResponse->{$this->_options['passwordfield']}) { |
return true; |
} else { |
return false; |
} |
} else { |
return true; |
} |
} else { |
return false; |
} |
} |
} |
?> |
/trunk/api/pear/Auth/Container/SMBPasswd.php |
---|
New file |
0,0 → 1,134 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Michael Bretterklieber <michael@bretterklieber.com> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: SMBPasswd.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "File/SMBPasswd.php"; |
require_once "Auth/Container.php"; |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from an SAMBA smbpasswd file. |
* |
* This storage container can handle SAMBA smbpasswd files. |
* |
* Example: |
* $a = new Auth("SMBPasswd", '/usr/local/private/smbpasswd'); |
* $a->start(); |
* if ($a->getAuth()) { |
* printf ("AUTH OK<br>\n"); |
* $a->logout(); |
* } |
* |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_SMBPasswd extends Auth_Container |
{ |
/** |
* File_SMBPasswd object |
* @var object |
*/ |
var $pwfile; |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* @param $filename string filename for a passwd type file |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_SMBPasswd($filename) |
{ |
$this->pwfile = new File_SMBPasswd($filename,0); |
if (!$this->pwfile->load()) { |
PEAR::raiseError("Error while reading file contents.", 41, PEAR_ERROR_DIE); |
return; |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from pwfile |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
return $this->pwfile->verifyAccount($username, $password); |
} |
// }}} |
// {{{ listUsers() |
function listUsers() |
{ |
return $this->pwfile->getAccounts(); |
} |
// }}} |
// {{{ addUser() |
/** |
* Add a new user to the storage container |
* |
* @param string Username |
* @param string Password |
* @param array Additional information |
* |
* @return boolean |
*/ |
function addUser($username, $password, $additional = '') |
{ |
$res = $this->pwfile->addUser($user, $additional['userid'], $pass); |
if ($res === true) { |
return $this->pwfile->save(); |
} |
return $res; |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @param string Username |
*/ |
function removeUser($username) |
{ |
$res = $this->pwfile->delUser($username); |
if ($res === true) { |
return $this->pwfile->save(); |
} |
return $res; |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/DB.php |
---|
New file |
0,0 → 1,409 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Martin Jansen <mj@php.net> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: DB.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once 'Auth/Container.php'; |
require_once 'DB.php'; |
/** |
* Storage driver for fetching login data from a database |
* |
* This storage driver can use all databases which are supported |
* by the PEAR DB abstraction layer to fetch login data. |
* |
* @author Martin Jansen <mj@php.net> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_DB extends Auth_Container |
{ |
/** |
* Additional options for the storage container |
* @var array |
*/ |
var $options = array(); |
/** |
* DB object |
* @var object |
*/ |
var $db = null; |
var $dsn = ''; |
/** |
* User that is currently selected from the DB. |
* @var string |
*/ |
var $activeUser = ''; |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* Initate connection to the database via PEAR::DB |
* |
* @param string Connection data or DB object |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_DB($dsn) |
{ |
$this->_setDefaults(); |
if (is_array($dsn)) { |
$this->_parseOptions($dsn); |
if (empty($this->options['dsn'])) { |
PEAR::raiseError('No connection parameters specified!'); |
} |
} else { |
$this->options['dsn'] = $dsn; |
} |
} |
// }}} |
// {{{ _connect() |
/** |
* Connect to database by using the given DSN string |
* |
* @access private |
* @param string DSN string |
* @return mixed Object on error, otherwise bool |
*/ |
function _connect($dsn) |
{ |
if (is_string($dsn) || is_array($dsn)) { |
$this->db = DB::Connect($dsn); |
} elseif (get_parent_class($dsn) == "db_common") { |
$this->db = $dsn; |
} elseif (DB::isError($dsn)) { |
return PEAR::raiseError($dsn->getMessage(), $dsn->getCode()); |
} else { |
return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__, |
41, |
PEAR_ERROR_RETURN, |
null, |
null |
); |
} |
if (DB::isError($this->db) || PEAR::isError($this->db)) { |
return PEAR::raiseError($this->db->getMessage(), $this->db->getCode()); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ _prepare() |
/** |
* Prepare database connection |
* |
* This function checks if we have already opened a connection to |
* the database. If that's not the case, a new connection is opened. |
* |
* @access private |
* @return mixed True or a DB error object. |
*/ |
function _prepare() |
{ |
if (!DB::isConnection($this->db)) { |
$res = $this->_connect($this->options['dsn']); |
if(DB::isError($res) || PEAR::isError($res)){ |
return $res; |
} |
} |
return true; |
} |
// }}} |
// {{{ query() |
/** |
* Prepare query to the database |
* |
* This function checks if we have already opened a connection to |
* the database. If that's not the case, a new connection is opened. |
* After that the query is passed to the database. |
* |
* @access public |
* @param string Query string |
* @return mixed a DB_result object or DB_OK on success, a DB |
* or PEAR error on failure |
*/ |
function query($query) |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return $err; |
} |
return $this->db->query($query); |
} |
// }}} |
// {{{ _setDefaults() |
/** |
* Set some default options |
* |
* @access private |
* @return void |
*/ |
function _setDefaults() |
{ |
$this->options['table'] = 'auth'; |
$this->options['usernamecol'] = 'username'; |
$this->options['passwordcol'] = 'password'; |
$this->options['dsn'] = ''; |
$this->options['db_fields'] = ''; |
$this->options['cryptType'] = 'md5'; |
} |
// }}} |
// {{{ _parseOptions() |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
foreach ($array as $key => $value) { |
if (isset($this->options[$key])) { |
$this->options[$key] = $value; |
} |
} |
/* Include additional fields if they exist */ |
if(!empty($this->options['db_fields'])){ |
if(is_array($this->options['db_fields'])){ |
$this->options['db_fields'] = join($this->options['db_fields'], ', '); |
} |
$this->options['db_fields'] = ', '.$this->options['db_fields']; |
} |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from database |
* |
* This function uses the given username to fetch |
* the corresponding login data from the database |
* table. If an account that matches the passed username |
* and password is found, the function returns true. |
* Otherwise it returns false. |
* |
* @param string Username |
* @param string Password |
* @return mixed Error object or boolean |
*/ |
function fetchData($username, $password) |
{ |
// Prepare for a database query |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
// Find if db_fileds contains a *, i so assume all col are selected |
if(strstr($this->options['db_fields'], '*')){ |
$sql_from = "*"; |
} |
else{ |
$sql_from = $this->options['usernamecol'] . ", ".$this->options['passwordcol'].$this->options['db_fields']; |
} |
/** |
Old Style, removed to go around the oci8 |
problem |
See bug 206 |
http://pear.php.net/bugs/bug.php?id=206 |
$query = "SELECT ! FROM ! WHERE ! = ?"; |
$query_params = array( |
$sql_from, |
$this->options['table'], |
$this->options['usernamecol'], |
$username |
); |
*/ |
$query = "SELECT ".$sql_from. |
" FROM ".$this->options['table']. |
" WHERE ".$this->options['usernamecol']." = '".$this->db->quoteString($username)."'"; |
$res = $this->db->getRow($query, null, DB_FETCHMODE_ASSOC); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} |
if (!is_array($res)) { |
$this->activeUser = ''; |
return false; |
} |
if ($this->verifyPassword(trim($password, "\r\n"), |
trim($res[$this->options['passwordcol']], "\r\n"), |
$this->options['cryptType'])) { |
// Store additional field values in the session |
foreach ($res as $key => $value) { |
if ($key == $this->options['passwordcol'] || |
$key == $this->options['usernamecol']) { |
continue; |
} |
// Use reference to the auth object if exists |
// This is because the auth session variable can change so a static call to setAuthData does not make sence |
if(is_object($this->_auth_obj)){ |
$this->_auth_obj->setAuthData($key, $value); |
} else { |
Auth::setAuthData($key, $value); |
} |
} |
return true; |
} |
$this->activeUser = $res[$this->options['usernamecol']]; |
return false; |
} |
// }}} |
// {{{ listUsers() |
function listUsers() |
{ |
$err = $this->_prepare(); |
if ($err !== true) { |
return PEAR::raiseError($err->getMessage(), $err->getCode()); |
} |
$retVal = array(); |
// Find if db_fileds contains a *, i so assume all col are selected |
if(strstr($this->options['db_fields'], '*')){ |
$sql_from = "*"; |
} |
else{ |
$sql_from = $this->options['usernamecol'] . ", ".$this->options['passwordcol'].$this->options['db_fields']; |
} |
$query = sprintf("SELECT %s FROM %s", |
$sql_from, |
$this->options['table'] |
); |
$res = $this->db->getAll($query, null, DB_FETCHMODE_ASSOC); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
foreach ($res as $user) { |
$user['username'] = $user[$this->options['usernamecol']]; |
$retVal[] = $user; |
} |
} |
return $retVal; |
} |
// }}} |
// {{{ addUser() |
/** |
* Add user to the storage container |
* |
* @access public |
* @param string Username |
* @param string Password |
* @param mixed Additional information that are stored in the DB |
* |
* @return mixed True on success, otherwise error object |
*/ |
function addUser($username, $password, $additional = "") |
{ |
if (function_exists($this->options['cryptType'])) { |
$cryptFunction = $this->options['cryptType']; |
} else { |
$cryptFunction = 'md5'; |
} |
$additional_key = ''; |
$additional_value = ''; |
if (is_array($additional)) { |
foreach ($additional as $key => $value) { |
$additional_key .= ', ' . $key; |
$additional_value .= ", '" . $value . "'"; |
} |
} |
$query = sprintf("INSERT INTO %s (%s, %s%s) VALUES ('%s', '%s'%s)", |
$this->options['table'], |
$this->options['usernamecol'], |
$this->options['passwordcol'], |
$additional_key, |
$username, |
$cryptFunction($password), |
$additional_value |
); |
$res = $this->query($query); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
return true; |
} |
} |
// }}} |
// {{{ removeUser() |
/** |
* Remove user from the storage container |
* |
* @access public |
* @param string Username |
* |
* @return mixed True on success, otherwise error object |
*/ |
function removeUser($username) |
{ |
$query = sprintf("DELETE FROM %s WHERE %s = '%s'", |
$this->options['table'], |
$this->options['usernamecol'], |
$username |
); |
$res = $this->query($query); |
if (DB::isError($res)) { |
return PEAR::raiseError($res->getMessage(), $res->getCode()); |
} else { |
return true; |
} |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Container/IMAP.php |
---|
New file |
0,0 → 1,170 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Jeroen Houben <jeroen@terena.nl> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: IMAP.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "Auth/Container.php"; |
require_once "PEAR.php"; |
/** |
* Storage driver for fetching login data from an IMAP server |
* |
* This class is based on LDAP containers, but it very simple. |
* By default it connects to localhost:143 |
* The constructor will first check if the host:port combination is |
* actually reachable. This behaviour can be disabled. |
* It then tries to create an IMAP stream (without opening a mailbox) |
* If you wish to pass extended options to the connections, you may |
* do so by specifying protocol options. |
* |
* To use this storage containers, you have to use the |
* following syntax: |
* |
* <?php |
* ... |
* $params = array( |
* 'host' => 'mail.example.com', |
* 'port' => 143, |
* ); |
* $myAuth = new Auth('IMAP', $params); |
* .... |
* |
* By default we connect without any protocol options set. However, some |
* servers require you to connect with the notls or norsh options set. |
* To do this you need to add the following value to the params array: |
* 'baseDSN' => '/imap/notls/norsh' |
* |
* To connect to an SSL IMAP server: |
* 'baseDSN' => '/imap/ssl' |
* |
* To connect to an SSL IMAP server with a self-signed certificate: |
* 'baseDSN' => '/imap/ssl/novalidate-cert' |
* |
* Further options may be available and can be found on the php site at |
* http://www.php.net/manual/function.imap-open.php |
* |
*/ |
/* |
* |
* @author Jeroen Houben <jeroen@terena.nl>, Cipriano Groenendal <cipri@campai.nl> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_IMAP extends Auth_Container |
{ |
/** |
* Options for the class |
* @var array |
*/ |
var $options = array(); |
/** |
* Constructor of the container class |
* |
* @param $params, associative hash with host,port,basedn and userattr key |
* @param $params, associative array with host, port, baseDSN, checkServer key. |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_IMAP($params) |
{ |
if (!extension_loaded('imap')) { |
return PEAR::raiseError("Cannot use IMAP authentication, IMAP extension not loaded!", |
41, PEAR_ERROR_DIE); |
} |
$this->_setDefaults(); |
// set parameters (if any) |
if (is_array($params)) { |
$this->_parseOptions($params); |
} |
if ($this->options['checkServer']) { |
$this->_checkServer($this->options['timeout']); |
} |
return true; |
} |
/** |
* Set some default options |
* |
* @access private |
*/ |
function _setDefaults() |
{ |
$this->options['host'] = 'localhost'; |
$this->options['port'] = 143; |
$this->options['baseDSN'] = ''; |
$this->options['checkServer'] = true; |
$this->options['timeout'] = 20; |
} |
/** |
* Check if the given server and port are reachable |
* |
* @access private |
*/ |
function _checkServer() { |
$fp = @fsockopen ($this->options['host'], $this->options['port'], |
$errno, $errstr, $timeout); |
if (is_resource($fp)) { |
@fclose($fp); |
} else { |
$message = "Error connecting to IMAP server " |
. $this->options['host'] |
. ":" . $this->options['port']; |
return PEAR::raiseError($message, 41, PEAR_ERROR_DIE); |
} |
} |
/** |
* Parse options passed to the container class |
* |
* @access private |
* @param array |
*/ |
function _parseOptions($array) |
{ |
foreach ($array as $key => $value) { |
$this->options[$key] = $value; |
} |
} |
/** |
* Try to open a IMAP stream using $username / $password |
* |
* @param string Username |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
$dsn = '{'.$this->options['host'].':'.$this->options['port'].$this->options['baseDSN'].'}'; |
$conn = @imap_open ($dsn, $username, $password, OP_HALFOPEN); |
if (is_resource($conn)){ |
$this->activeUser = $username; |
@imap_close($conn); |
return true; |
} else { |
$this->activeUser = ''; |
return false; |
} |
} |
} |
?> |
/trunk/api/pear/Auth/Container/RADIUS.php |
---|
New file |
0,0 → 1,154 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Michael Bretterklieber <michael@bretterklieber.com> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: RADIUS.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "Auth/Container.php"; |
require_once "Auth/RADIUS.php"; |
/** |
* Storage driver for authenticating users against RADIUS servers. |
* |
* @author Michael Bretterklieber <michael@bretterklieber.com> |
* @access public |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_RADIUS extends Auth_Container |
{ |
/** |
* Contains a RADIUS object |
* @var object |
*/ |
var $radius; |
/** |
* Contains the authentication type |
* @var string |
*/ |
var $authtype; |
/** |
* Constructor of the container class. |
* |
* $options can have these keys: |
* 'servers' an array containing an array: servername, port, |
* sharedsecret, timeout, maxtries |
* 'configfile' The filename of the configuration file |
* 'authtype' The type of authentication, one of: PAP, CHAP_MD5, |
* MSCHAPv1, MSCHAPv2, default is PAP |
* |
* @param $options associative array |
* @return object Returns an error object if something went wrong |
*/ |
function Auth_Container_RADIUS($options) |
{ |
$this->authtype = 'PAP'; |
if (isset($options['authtype'])) { |
$this->authtype = $options['authtype']; |
} |
$classname = 'Auth_RADIUS_' . $this->authtype; |
if (!class_exists($classname)) { |
PEAR::raiseError("Unknown Authtype, please use on of: PAP, CHAP_MD5, MSCHAPv1, MSCHAPv2!", |
41, PEAR_ERROR_DIE); |
} |
$this->radius = new $classname; |
if (isset($options['configfile'])) { |
$this->radius->setConfigfile($options['configfile']); |
} |
$servers = $options['servers']; |
if (is_array($servers)) { |
foreach ($servers as $server) { |
$servername = $server[0]; |
$port = isset($server[1]) ? $server[1] : 0; |
$sharedsecret = isset($server[2]) ? $server[2] : 'testing123'; |
$timeout = isset($server[3]) ? $server[3] : 3; |
$maxtries = isset($server[4]) ? $server[4] : 3; |
$this->radius->addServer($servername, $port, $sharedsecret, $timeout, $maxtries); |
} |
} |
if (!$this->radius->start()) { |
PEAR::raiseError($this->radius->getError(), 41, PEAR_ERROR_DIE); |
} |
} |
/** |
* Authenticate |
* |
* @param string Username |
* @param string Password |
* @return bool true on success, false on reject |
*/ |
function fetchData($username, $password, $challenge = null) |
{ |
switch($this->authtype) { |
case 'CHAP_MD5': |
case 'MSCHAPv1': |
if (isset($challenge)) { |
echo $password; |
$this->radius->challenge = $challenge; |
$this->radius->chapid = 1; |
$this->radius->response = pack('H*', $password); |
} else { |
require_once 'Crypt_CHAP/CHAP.php'; |
$classname = 'Crypt_' . $this->authtype; |
$crpt = new $classname; |
$crpt->password = $password; |
$this->radius->challenge = $crpt->challenge; |
$this->radius->chapid = $crpt->chapid; |
$this->radius->response = $crpt->challengeResponse(); |
break; |
} |
case 'MSCHAPv2': |
require_once 'Crypt_CHAP/CHAP.php'; |
$crpt = new Crypt_MSCHAPv2; |
$crpt->username = $username; |
$crpt->password = $password; |
$this->radius->challenge = $crpt->authChallenge; |
$this->radius->peerChallenge = $crpt->peerChallenge; |
$this->radius->chapid = $crpt->chapid; |
$this->radius->response = $crpt->challengeResponse(); |
break; |
default: |
$this->radius->password = $password; |
break; |
} |
$this->radius->username = $username; |
$this->radius->putAuthAttributes(); |
$result = $this->radius->send(); |
if (PEAR::isError($result)) { |
return false; |
} |
$this->radius->getAttributes(); |
// just for debugging |
// $this->radius->dumpAttributes(); |
return $result; |
} |
} |
?> |
/trunk/api/pear/Auth/Container/vpopmail.php |
---|
New file |
0,0 → 1,66 |
<?PHP |
/* vim: set expandtab tabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Author: Stanislav Grozev <tacho@orbitel.bg> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: vpopmail.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// |
require_once "Auth/Container.php"; |
/** |
* Storage driver for fetching login data from vpopmail |
* |
* @author Stanislav Grozev <tacho@orbitel.bg> |
* @package Auth |
* @version $Revision: 1.1 $ |
*/ |
class Auth_Container_vpopmail extends Auth_Container { |
// {{{ Constructor |
/** |
* Constructor of the container class |
* |
* @return integer Always returns 1. |
*/ |
function Auth_Container_vpopmail() |
{ |
return 1; |
} |
// }}} |
// {{{ fetchData() |
/** |
* Get user information from vpopmail |
* |
* @param string Username - has to be valid email address |
* @param string Password |
* @return boolean |
*/ |
function fetchData($username, $password) |
{ |
$userdata = array(); |
$userdata = preg_split("/@/", $username, 2); |
$result = @vpopmail_auth_user($userdata[0], $userdata[1], $password); |
return $result; |
} |
// }}} |
} |
?> |
/trunk/api/pear/Auth/Auth.php |
---|
New file |
0,0 → 1,5 |
<?php |
include_once('Auth.php'); |
?> |