You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2031 lines
76 KiB
2031 lines
76 KiB
2 years ago
|
<?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$
|
||
|
|
||
|
require_once('PEAR.php');
|
||
|
require_once('HTML/Common.php');
|
||
|
/**
|
||
|
* Static utility methods.
|
||
|
*/
|
||
|
require_once('HTML/QuickForm/utils.php');
|
||
|
|
||
|
$GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] =
|
||
|
array(
|
||
|
'group' =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
|
||
|
'hidden' =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
|
||
|
'reset' =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
|
||
|
'checkbox' =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
|
||
|
'file' =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
|
||
|
'image' =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
|
||
|
'password' =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
|
||
|
'radio' =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
|
||
|
'button' =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
|
||
|
'submit' =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
|
||
|
'select' =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
|
||
|
'hiddenselect' =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
|
||
|
'text' =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
|
||
|
'textarea' =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
|
||
|
'link' =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
|
||
|
'advcheckbox' =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
|
||
|
'date' =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
|
||
|
'static' =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
|
||
|
'header' =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
|
||
|
'html' =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
|
||
|
'hierselect' =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
|
||
|
'autocomplete' =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
|
||
|
'xbutton' =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
|
||
|
);
|
||
|
|
||
|
$GLOBALS['_HTML_QuickForm_registered_rules'] = array(
|
||
|
'required' => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
|
||
|
'maxlength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
|
||
|
'minlength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
|
||
|
'rangelength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
|
||
|
'email' => array('html_quickform_rule_email', 'HTML/QuickForm/Rule/Email.php'),
|
||
|
'regex' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'lettersonly' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'alphanumeric' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'numeric' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'nopunctuation' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'nonzero' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
|
||
|
'callback' => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
|
||
|
'compare' => array('html_quickform_rule_compare', 'HTML/QuickForm/Rule/Compare.php')
|
||
|
);
|
||
|
|
||
|
// {{{ error codes
|
||
|
|
||
|
/*
|
||
|
* Error codes for the QuickForm interface, which will be mapped to textual messages
|
||
|
* in the QuickForm::errorMessage() function. If you are to add a new error code, be
|
||
|
* sure to add the textual messages to the QuickForm::errorMessage() function as well
|
||
|
*/
|
||
|
|
||
|
define('QUICKFORM_OK', 1);
|
||
|
define('QUICKFORM_ERROR', -1);
|
||
|
define('QUICKFORM_INVALID_RULE', -2);
|
||
|
define('QUICKFORM_NONEXIST_ELEMENT', -3);
|
||
|
define('QUICKFORM_INVALID_FILTER', -4);
|
||
|
define('QUICKFORM_UNREGISTERED_ELEMENT', -5);
|
||
|
define('QUICKFORM_INVALID_ELEMENT_NAME', -6);
|
||
|
define('QUICKFORM_INVALID_PROCESS', -7);
|
||
|
define('QUICKFORM_DEPRECATED', -8);
|
||
|
define('QUICKFORM_INVALID_DATASOURCE', -9);
|
||
|
|
||
|
// }}}
|
||
|
|
||
|
/**
|
||
|
* Create, validate and process HTML forms
|
||
|
*
|
||
|
* @author Adam Daniel <adaniel1@eesus.jnj.com>
|
||
|
* @author Bertrand Mansion <bmansion@mamasam.com>
|
||
|
* @version 2.0
|
||
|
* @since PHP 4.0.3pl1
|
||
|
*/
|
||
|
class HTML_QuickForm extends HTML_Common {
|
||
|
// {{{ properties
|
||
|
|
||
|
/**
|
||
|
* Array containing the form fields
|
||
|
* @since 1.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_elements = array();
|
||
|
|
||
|
/**
|
||
|
* Array containing element name to index map
|
||
|
* @since 1.1
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_elementIndex = array();
|
||
|
|
||
|
/**
|
||
|
* Array containing indexes of duplicate elements
|
||
|
* @since 2.10
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_duplicateIndex = array();
|
||
|
|
||
|
/**
|
||
|
* Array containing required field IDs
|
||
|
* @since 1.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_required = array();
|
||
|
|
||
|
/**
|
||
|
* Prefix message in javascript alert if error
|
||
|
* @since 1.0
|
||
|
* @var string
|
||
|
* @access public
|
||
|
*/
|
||
|
var $_jsPrefix = 'Invalid information entered.';
|
||
|
|
||
|
/**
|
||
|
* Postfix message in javascript alert if error
|
||
|
* @since 1.0
|
||
|
* @var string
|
||
|
* @access public
|
||
|
*/
|
||
|
var $_jsPostfix = 'Please correct these fields.';
|
||
|
|
||
|
/**
|
||
|
* Datasource object implementing the informal
|
||
|
* datasource protocol
|
||
|
* @since 3.3
|
||
|
* @var object
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_datasource;
|
||
|
|
||
|
/**
|
||
|
* Array of default form values
|
||
|
* @since 2.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_defaultValues = array();
|
||
|
|
||
|
/**
|
||
|
* Array of constant form values
|
||
|
* @since 2.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_constantValues = array();
|
||
|
|
||
|
/**
|
||
|
* Array of submitted form values
|
||
|
* @since 1.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_submitValues = array();
|
||
|
|
||
|
/**
|
||
|
* Array of submitted form files
|
||
|
* @since 1.0
|
||
|
* @var integer
|
||
|
* @access public
|
||
|
*/
|
||
|
var $_submitFiles = array();
|
||
|
|
||
|
/**
|
||
|
* Value for maxfilesize hidden element if form contains file input
|
||
|
* @since 1.0
|
||
|
* @var integer
|
||
|
* @access public
|
||
|
*/
|
||
|
var $_maxFileSize = 1048576; // 1 Mb = 1048576
|
||
|
|
||
|
/**
|
||
|
* Flag to know if all fields are frozen
|
||
|
* @since 1.0
|
||
|
* @var boolean
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_freezeAll = false;
|
||
|
|
||
|
/**
|
||
|
* Array containing the form rules
|
||
|
* @since 1.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_rules = array();
|
||
|
|
||
|
/**
|
||
|
* Form rules, global variety
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_formRules = array();
|
||
|
|
||
|
/**
|
||
|
* Array containing the validation errors
|
||
|
* @since 1.0
|
||
|
* @var array
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_errors = array();
|
||
|
|
||
|
/**
|
||
|
* Note for required fields in the form
|
||
|
* @var string
|
||
|
* @since 1.0
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
|
||
|
|
||
|
/**
|
||
|
* Whether the form was submitted
|
||
|
* @var boolean
|
||
|
* @access private
|
||
|
*/
|
||
|
var $_flagSubmitted = false;
|
||
|
|
||
|
// }}}
|
||
|
// {{{ constructor
|
||
|
|
||
|
/**
|
||
|
* Class constructor
|
||
|
* @param string $formName Form's name.
|
||
|
* @param string $method (optional)Form's method defaults to 'POST'
|
||
|
* @param string $action (optional)Form's action
|
||
|
* @param string $target (optional)Form's target defaults to '_self'
|
||
|
* @param mixed $attributes (optional)Extra attributes for <form> tag
|
||
|
* @param bool $trackSubmit (optional)Whether to track if the form was submitted by adding a special hidden field
|
||
|
* @access public
|
||
|
*/
|
||
|
public function __construct($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false)
|
||
|
{
|
||
|
parent::__construct($attributes);
|
||
|
$method = (strtoupper($method) == 'GET') ? 'get' : 'post';
|
||
|
$action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
|
||
|
$target = empty($target) ? array() : array('target' => $target);
|
||
|
$attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
|
||
|
$this->updateAttributes($attributes);
|
||
|
if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
|
||
|
if (1 == get_magic_quotes_gpc()) {
|
||
|
$this->_submitValues = ('get' == $method? $_GET: $_POST); // we already eliminated magic quotes in moodle setup.php
|
||
|
foreach ($_FILES as $keyFirst => $valFirst) {
|
||
|
foreach ($valFirst as $keySecond => $valSecond) {
|
||
|
if ('name' == $keySecond) {
|
||
|
$this->_submitFiles[$keyFirst][$keySecond] = $valSecond; // we already eliminated magic quotes in moodle setup.php
|
||
|
} else {
|
||
|
$this->_submitFiles[$keyFirst][$keySecond] = $valSecond;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
$this->_submitValues = 'get' == $method? $_GET: $_POST;
|
||
|
$this->_submitFiles = $_FILES;
|
||
|
}
|
||
|
$this->_flagSubmitted = count($this->_submitValues) > 0 || count($this->_submitFiles) > 0;
|
||
|
}
|
||
|
if ($trackSubmit) {
|
||
|
unset($this->_submitValues['_qf__' . $formName]);
|
||
|
$this->addElement('hidden', '_qf__' . $formName, null);
|
||
|
}
|
||
|
if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', ini_get('upload_max_filesize'), $matches)) {
|
||
|
// see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
|
||
|
switch (strtoupper($matches['2'])) {
|
||
|
case 'G':
|
||
|
$this->_maxFileSize = $matches['1'] * 1073741824;
|
||
|
break;
|
||
|
case 'M':
|
||
|
$this->_maxFileSize = $matches['1'] * 1048576;
|
||
|
break;
|
||
|
case 'K':
|
||
|
$this->_maxFileSize = $matches['1'] * 1024;
|
||
|
break;
|
||
|
default:
|
||
|
$this->_maxFileSize = $matches['1'];
|
||
|
}
|
||
|
}
|
||
|
} // end constructor
|
||
|
|
||
|
/**
|
||
|
* Old syntax of class constructor. Deprecated in PHP7.
|
||
|
*
|
||
|
* @deprecated since Moodle 3.1
|
||
|
*/
|
||
|
public function HTML_QuickForm($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false) {
|
||
|
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
|
||
|
self::__construct($formName, $method, $action, $target, $attributes, $trackSubmit);
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ apiVersion()
|
||
|
|
||
|
/**
|
||
|
* Returns the current API version
|
||
|
*
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return float
|
||
|
*/
|
||
|
function apiVersion()
|
||
|
{
|
||
|
return 3.2;
|
||
|
} // end func apiVersion
|
||
|
|
||
|
// }}}
|
||
|
// {{{ registerElementType()
|
||
|
|
||
|
/**
|
||
|
* Registers a new element type
|
||
|
*
|
||
|
* @param string $typeName Name of element type
|
||
|
* @param string $include Include path for element type
|
||
|
* @param string $className Element class name
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
static function registerElementType($typeName, $include, $className)
|
||
|
{
|
||
|
$GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
|
||
|
} // end func registerElementType
|
||
|
|
||
|
// }}}
|
||
|
// {{{ registerRule()
|
||
|
|
||
|
/**
|
||
|
* Registers a new validation rule
|
||
|
*
|
||
|
* @param string $ruleName Name of validation rule
|
||
|
* @param string $type Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
|
||
|
* @param string $data1 Name of function, regular expression or HTML_QuickForm_Rule classname
|
||
|
* @param string $data2 Object parent of above function or HTML_QuickForm_Rule file path
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
static function registerRule($ruleName, $type, $data1, $data2 = null)
|
||
|
{
|
||
|
include_once('HTML/QuickForm/RuleRegistry.php');
|
||
|
$registry =& HTML_QuickForm_RuleRegistry::singleton();
|
||
|
$registry->registerRule($ruleName, $type, $data1, $data2);
|
||
|
} // end func registerRule
|
||
|
|
||
|
// }}}
|
||
|
// {{{ elementExists()
|
||
|
|
||
|
/**
|
||
|
* Returns true if element is in the form
|
||
|
*
|
||
|
* @param string $element form name of element to check
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return boolean
|
||
|
*/
|
||
|
function elementExists($element=null)
|
||
|
{
|
||
|
return isset($this->_elementIndex[$element]);
|
||
|
} // end func elementExists
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setDatasource()
|
||
|
|
||
|
/**
|
||
|
* Sets a datasource object for this form object
|
||
|
*
|
||
|
* Datasource default and constant values will feed the QuickForm object if
|
||
|
* the datasource implements defaultValues() and constantValues() methods.
|
||
|
*
|
||
|
* @param object $datasource datasource object implementing the informal datasource protocol
|
||
|
* @param mixed $defaultsFilter string or array of filter(s) to apply to default values
|
||
|
* @param mixed $constantsFilter string or array of filter(s) to apply to constants values
|
||
|
* @since 3.3
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
|
||
|
{
|
||
|
if (is_object($datasource)) {
|
||
|
$this->_datasource =& $datasource;
|
||
|
if (is_callable(array($datasource, 'defaultValues'))) {
|
||
|
$this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
|
||
|
}
|
||
|
if (is_callable(array($datasource, 'constantValues'))) {
|
||
|
$this->setConstants($datasource->constantValues($this), $constantsFilter);
|
||
|
}
|
||
|
} else {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
} // end func setDatasource
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setDefaults()
|
||
|
|
||
|
/**
|
||
|
* Initializes default form values
|
||
|
*
|
||
|
* @param array $defaultValues values used to fill the form
|
||
|
* @param mixed $filter (optional) filter(s) to apply to all default values
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setDefaults($defaultValues = null, $filter = null)
|
||
|
{
|
||
|
if (is_array($defaultValues)) {
|
||
|
if (isset($filter)) {
|
||
|
if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
|
||
|
foreach ($filter as $val) {
|
||
|
if (!is_callable($val)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
|
||
|
} else {
|
||
|
$defaultValues = $this->_recursiveFilter($val, $defaultValues);
|
||
|
}
|
||
|
}
|
||
|
} elseif (!is_callable($filter)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
|
||
|
} else {
|
||
|
$defaultValues = $this->_recursiveFilter($filter, $defaultValues);
|
||
|
}
|
||
|
}
|
||
|
$this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
|
||
|
foreach (array_keys($this->_elements) as $key) {
|
||
|
$this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
|
||
|
}
|
||
|
}
|
||
|
} // end func setDefaults
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setConstants()
|
||
|
|
||
|
/**
|
||
|
* Initializes constant form values.
|
||
|
* These values won't get overridden by POST or GET vars
|
||
|
*
|
||
|
* @param array $constantValues values used to fill the form
|
||
|
* @param mixed $filter (optional) filter(s) to apply to all default values
|
||
|
*
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setConstants($constantValues = null, $filter = null)
|
||
|
{
|
||
|
if (is_array($constantValues)) {
|
||
|
if (isset($filter)) {
|
||
|
if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
|
||
|
foreach ($filter as $val) {
|
||
|
if (!is_callable($val)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
|
||
|
} else {
|
||
|
$constantValues = $this->_recursiveFilter($val, $constantValues);
|
||
|
}
|
||
|
}
|
||
|
} elseif (!is_callable($filter)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
|
||
|
} else {
|
||
|
$constantValues = $this->_recursiveFilter($filter, $constantValues);
|
||
|
}
|
||
|
}
|
||
|
$this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
|
||
|
foreach (array_keys($this->_elements) as $key) {
|
||
|
$this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
|
||
|
}
|
||
|
}
|
||
|
} // end func setConstants
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setMaxFileSize()
|
||
|
|
||
|
/**
|
||
|
* Sets the value of MAX_FILE_SIZE hidden element
|
||
|
*
|
||
|
* @param int $bytes Size in bytes
|
||
|
* @since 3.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setMaxFileSize($bytes = 0)
|
||
|
{
|
||
|
if ($bytes > 0) {
|
||
|
$this->_maxFileSize = $bytes;
|
||
|
}
|
||
|
if (!$this->elementExists('MAX_FILE_SIZE')) {
|
||
|
$this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
|
||
|
} else {
|
||
|
$el =& $this->getElement('MAX_FILE_SIZE');
|
||
|
$el->updateAttributes(array('value' => $this->_maxFileSize));
|
||
|
}
|
||
|
} // end func setMaxFileSize
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getMaxFileSize()
|
||
|
|
||
|
/**
|
||
|
* Returns the value of MAX_FILE_SIZE hidden element
|
||
|
*
|
||
|
* @since 3.0
|
||
|
* @access public
|
||
|
* @return int max file size in bytes
|
||
|
*/
|
||
|
function getMaxFileSize()
|
||
|
{
|
||
|
return $this->_maxFileSize;
|
||
|
} // end func getMaxFileSize
|
||
|
|
||
|
// }}}
|
||
|
// {{{ &createElement()
|
||
|
|
||
|
/**
|
||
|
* Creates a new form element of the given type.
|
||
|
*
|
||
|
* This method accepts variable number of parameters, their
|
||
|
* meaning and count depending on $elementType
|
||
|
*
|
||
|
* @param string $elementType type of element to add (text, textarea, file...)
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return object extended class of HTML_element
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &createElement($elementType)
|
||
|
{
|
||
|
if (!isset($this) || !($this instanceof HTML_QuickForm)) {
|
||
|
// Several form elements in Moodle core before 3.2 were calling this method
|
||
|
// statically suppressing PHP notices. This debugging message should notify
|
||
|
// developers who copied such code and did not test their plugins on PHP 7.1.
|
||
|
// Example of fixing group form elements can be found in commit
|
||
|
// https://github.com/moodle/moodle/commit/721e2def56a48fab4f8d3ec7847af5cd03f5ec79
|
||
|
debugging('Function createElement() can not be called statically, ' .
|
||
|
'this will no longer work in PHP 7.1',
|
||
|
DEBUG_DEVELOPER);
|
||
|
}
|
||
|
$args = func_get_args();
|
||
|
$element = self::_loadElement('createElement', $elementType, array_slice($args, 1));
|
||
|
return $element;
|
||
|
} // end func createElement
|
||
|
|
||
|
// }}}
|
||
|
// {{{ _loadElement()
|
||
|
|
||
|
/**
|
||
|
* Returns a form element of the given type
|
||
|
*
|
||
|
* @param string $event event to send to newly created element ('createElement' or 'addElement')
|
||
|
* @param string $type element type
|
||
|
* @param array $args arguments for event
|
||
|
* @since 2.0
|
||
|
* @access private
|
||
|
* @return object a new element
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &_loadElement($event, $type, $args)
|
||
|
{
|
||
|
$type = strtolower($type);
|
||
|
if (!self::isTypeRegistered($type)) {
|
||
|
$error = self::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
$className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
|
||
|
$includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
|
||
|
include_once($includeFile);
|
||
|
$elementObject = new $className(); //Moodle: PHP 5.3 compatibility
|
||
|
for ($i = 0; $i < 5; $i++) {
|
||
|
if (!isset($args[$i])) {
|
||
|
$args[$i] = null;
|
||
|
}
|
||
|
}
|
||
|
$err = $elementObject->onQuickFormEvent($event, $args, $this);
|
||
|
if ($err !== true) {
|
||
|
return $err;
|
||
|
}
|
||
|
return $elementObject;
|
||
|
} // end func _loadElement
|
||
|
|
||
|
// }}}
|
||
|
// {{{ addElement()
|
||
|
|
||
|
/**
|
||
|
* Adds an element into the form
|
||
|
*
|
||
|
* If $element is a string representing element type, then this
|
||
|
* method accepts variable number of parameters, their meaning
|
||
|
* and count depending on $element
|
||
|
*
|
||
|
* @param mixed $element element object or type of element to add (text, textarea, file...)
|
||
|
* @since 1.0
|
||
|
* @return object reference to element
|
||
|
* @access public
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &addElement($element)
|
||
|
{
|
||
|
if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
|
||
|
$elementObject = &$element;
|
||
|
$elementObject->onQuickFormEvent('updateValue', null, $this);
|
||
|
} else {
|
||
|
$args = func_get_args();
|
||
|
$elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1));
|
||
|
$pear = new PEAR();
|
||
|
if ($pear->isError($elementObject)) {
|
||
|
return $elementObject;
|
||
|
}
|
||
|
}
|
||
|
$elementName = $elementObject->getName();
|
||
|
|
||
|
// Add the element if it is not an incompatible duplicate
|
||
|
if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
|
||
|
if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
|
||
|
$elementObject->getType()) {
|
||
|
$this->_elements[] =& $elementObject;
|
||
|
$elKeys = array_keys($this->_elements);
|
||
|
$this->_duplicateIndex[$elementName][] = end($elKeys);
|
||
|
} else {
|
||
|
$error = self::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
} else {
|
||
|
$this->_elements[] =& $elementObject;
|
||
|
$elKeys = array_keys($this->_elements);
|
||
|
$this->_elementIndex[$elementName] = end($elKeys);
|
||
|
}
|
||
|
if ($this->_freezeAll) {
|
||
|
$elementObject->freeze();
|
||
|
}
|
||
|
|
||
|
return $elementObject;
|
||
|
} // end func addElement
|
||
|
|
||
|
// }}}
|
||
|
// {{{ insertElementBefore()
|
||
|
|
||
|
/**
|
||
|
* Inserts a new element right before the other element
|
||
|
*
|
||
|
* Warning: it is not possible to check whether the $element is already
|
||
|
* added to the form, therefore if you want to move the existing form
|
||
|
* element to a new position, you'll have to use removeElement():
|
||
|
* $form->insertElementBefore($form->removeElement('foo', false), 'bar');
|
||
|
*
|
||
|
* @access public
|
||
|
* @since 3.2.4
|
||
|
* @param object HTML_QuickForm_element Element to insert
|
||
|
* @param string Name of the element before which the new one is inserted
|
||
|
* @return object HTML_QuickForm_element reference to inserted element
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &insertElementBefore(&$element, $nameAfter)
|
||
|
{
|
||
|
if (!empty($this->_duplicateIndex[$nameAfter])) {
|
||
|
$error = self::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, 'Several elements named "' . $nameAfter . '" exist in HTML_QuickForm::insertElementBefore().', 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
} elseif (!$this->elementExists($nameAfter)) {
|
||
|
$error = self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
$elementName = $element->getName();
|
||
|
$targetIdx = $this->_elementIndex[$nameAfter];
|
||
|
$duplicate = false;
|
||
|
// Like in addElement(), check that it's not an incompatible duplicate
|
||
|
if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
|
||
|
if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
|
||
|
$error = self::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
$duplicate = true;
|
||
|
}
|
||
|
// Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
|
||
|
$elKeys = array_keys($this->_elements);
|
||
|
for ($i = end($elKeys); $i >= $targetIdx; $i--) {
|
||
|
if (isset($this->_elements[$i])) {
|
||
|
$currentName = $this->_elements[$i]->getName();
|
||
|
$this->_elements[$i + 1] =& $this->_elements[$i];
|
||
|
if ($this->_elementIndex[$currentName] == $i) {
|
||
|
$this->_elementIndex[$currentName] = $i + 1;
|
||
|
} else {
|
||
|
if (!empty($currentName)) {
|
||
|
$dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
|
||
|
$this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
|
||
|
}
|
||
|
}
|
||
|
unset($this->_elements[$i]);
|
||
|
}
|
||
|
}
|
||
|
// Put the element in place finally
|
||
|
$this->_elements[$targetIdx] =& $element;
|
||
|
if (!$duplicate) {
|
||
|
$this->_elementIndex[$elementName] = $targetIdx;
|
||
|
} else {
|
||
|
$this->_duplicateIndex[$elementName][] = $targetIdx;
|
||
|
}
|
||
|
$element->onQuickFormEvent('updateValue', null, $this);
|
||
|
if ($this->_freezeAll) {
|
||
|
$element->freeze();
|
||
|
}
|
||
|
// If not done, the elements will appear in reverse order
|
||
|
ksort($this->_elements);
|
||
|
return $element;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ addGroup()
|
||
|
|
||
|
/**
|
||
|
* Adds an element group
|
||
|
* @param array $elements array of elements composing the group
|
||
|
* @param string $name (optional)group name
|
||
|
* @param string $groupLabel (optional)group label
|
||
|
* @param string $separator (optional)string to separate elements
|
||
|
* @param string $appendName (optional)specify whether the group name should be
|
||
|
* used in the form element name ex: group[element]
|
||
|
* @return object reference to added group of elements
|
||
|
* @since 2.8
|
||
|
* @access public
|
||
|
* @throws PEAR_Error
|
||
|
*/
|
||
|
function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
|
||
|
{
|
||
|
static $anonGroups = 1;
|
||
|
|
||
|
if (0 == strlen($name)) {
|
||
|
$name = 'qf_group_' . $anonGroups++;
|
||
|
$appendName = false;
|
||
|
}
|
||
|
$group =& $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
|
||
|
return $group;
|
||
|
} // end func addGroup
|
||
|
|
||
|
// }}}
|
||
|
// {{{ &getElement()
|
||
|
|
||
|
/**
|
||
|
* Returns a reference to the element
|
||
|
*
|
||
|
* @param string $element Element name
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return object reference to element
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &getElement($element)
|
||
|
{
|
||
|
if (isset($this->_elementIndex[$element])) {
|
||
|
return $this->_elements[$this->_elementIndex[$element]];
|
||
|
} else {
|
||
|
$error = self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
} // end func getElement
|
||
|
|
||
|
// }}}
|
||
|
// {{{ &getElementValue()
|
||
|
|
||
|
/**
|
||
|
* Returns the element's raw value
|
||
|
*
|
||
|
* This returns the value as submitted by the form (not filtered)
|
||
|
* or set via setDefaults() or setConstants()
|
||
|
*
|
||
|
* @param string $element Element name
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return mixed element value
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &getElementValue($element)
|
||
|
{
|
||
|
if (!isset($this->_elementIndex[$element])) {
|
||
|
$error = self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
$value = $this->_elements[$this->_elementIndex[$element]]->getValue();
|
||
|
if (isset($this->_duplicateIndex[$element])) {
|
||
|
foreach ($this->_duplicateIndex[$element] as $index) {
|
||
|
if (null !== ($v = $this->_elements[$index]->getValue())) {
|
||
|
if (is_array($value)) {
|
||
|
$value[] = $v;
|
||
|
} else {
|
||
|
$value = (null === $value)? $v: array($value, $v);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $value;
|
||
|
} // end func getElementValue
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getSubmitValue()
|
||
|
|
||
|
/**
|
||
|
* Returns the elements value after submit and filter
|
||
|
*
|
||
|
* @param string Element name
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return mixed submitted element value or null if not set
|
||
|
*/
|
||
|
function getSubmitValue($elementName)
|
||
|
{
|
||
|
$value = null;
|
||
|
if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
|
||
|
$value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
|
||
|
if (is_array($value) && isset($this->_submitFiles[$elementName])) {
|
||
|
foreach ($this->_submitFiles[$elementName] as $k => $v) {
|
||
|
$value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} elseif ('file' == $this->getElementType($elementName)) {
|
||
|
return $this->getElementValue($elementName);
|
||
|
|
||
|
} elseif (false !== ($pos = strpos($elementName, '['))) {
|
||
|
$base = substr($elementName, 0, $pos);
|
||
|
$keys = str_replace(
|
||
|
array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
|
||
|
substr($elementName, $pos + 1, -1)
|
||
|
);
|
||
|
$idx = "['" . $keys . "']";
|
||
|
$keyArray = explode("']['", $keys);
|
||
|
|
||
|
if (isset($this->_submitValues[$base])) {
|
||
|
$value = HTML_QuickForm_utils::recursiveValue($this->_submitValues[$base], $keyArray, NULL);
|
||
|
}
|
||
|
|
||
|
if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
|
||
|
$props = array('name', 'type', 'size', 'tmp_name', 'error');
|
||
|
$code = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
|
||
|
" return null;\n" .
|
||
|
"} else {\n" .
|
||
|
" \$v = array();\n";
|
||
|
foreach ($props as $prop) {
|
||
|
$code .= " \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
|
||
|
}
|
||
|
$fileValue = eval($code . " return \$v;\n}\n");
|
||
|
if (null !== $fileValue) {
|
||
|
$value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This is only supposed to work for groups with appendName = false
|
||
|
if (null === $value && 'group' == $this->getElementType($elementName)) {
|
||
|
$group =& $this->getElement($elementName);
|
||
|
$elements =& $group->getElements();
|
||
|
foreach (array_keys($elements) as $key) {
|
||
|
$name = $group->getElementName($key);
|
||
|
// prevent endless recursion in case of radios and such
|
||
|
if ($name != $elementName) {
|
||
|
if (null !== ($v = $this->getSubmitValue($name))) {
|
||
|
$value[$name] = $v;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $value;
|
||
|
} // end func getSubmitValue
|
||
|
|
||
|
// }}}
|
||
|
// {{{ _reindexFiles()
|
||
|
|
||
|
/**
|
||
|
* A helper function to change the indexes in $_FILES array
|
||
|
*
|
||
|
* @param mixed Some value from the $_FILES array
|
||
|
* @param string The key from the $_FILES array that should be appended
|
||
|
* @return array
|
||
|
*/
|
||
|
function _reindexFiles($value, $key)
|
||
|
{
|
||
|
if (!is_array($value)) {
|
||
|
return array($key => $value);
|
||
|
} else {
|
||
|
$ret = array();
|
||
|
foreach ($value as $k => $v) {
|
||
|
$ret[$k] = $this->_reindexFiles($v, $key);
|
||
|
}
|
||
|
return $ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getElementError()
|
||
|
|
||
|
/**
|
||
|
* Returns error corresponding to validated element
|
||
|
*
|
||
|
* @param string $element Name of form element to check
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return string error message corresponding to checked element
|
||
|
*/
|
||
|
function getElementError($element)
|
||
|
{
|
||
|
if (isset($this->_errors[$element])) {
|
||
|
return $this->_errors[$element];
|
||
|
}
|
||
|
} // end func getElementError
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setElementError()
|
||
|
|
||
|
/**
|
||
|
* Set error message for a form element
|
||
|
*
|
||
|
* @param string $element Name of form element to set error for
|
||
|
* @param string $message Error message, if empty then removes the current error message
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setElementError($element, $message = null)
|
||
|
{
|
||
|
if (!empty($message)) {
|
||
|
$this->_errors[$element] = $message;
|
||
|
} else {
|
||
|
unset($this->_errors[$element]);
|
||
|
}
|
||
|
} // end func setElementError
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getElementType()
|
||
|
|
||
|
/**
|
||
|
* Returns the type of the given element
|
||
|
*
|
||
|
* @param string $element Name of form element
|
||
|
* @since 1.1
|
||
|
* @access public
|
||
|
* @return string Type of the element, false if the element is not found
|
||
|
*/
|
||
|
function getElementType($element)
|
||
|
{
|
||
|
if (isset($this->_elementIndex[$element])) {
|
||
|
return $this->_elements[$this->_elementIndex[$element]]->getType();
|
||
|
}
|
||
|
return false;
|
||
|
} // end func getElementType
|
||
|
|
||
|
// }}}
|
||
|
// {{{ updateElementAttr()
|
||
|
|
||
|
/**
|
||
|
* Updates Attributes for one or more elements
|
||
|
*
|
||
|
* @param mixed $elements Array of element names/objects or string of elements to be updated
|
||
|
* @param mixed $attrs Array or sting of html attributes
|
||
|
* @since 2.10
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function updateElementAttr($elements, $attrs)
|
||
|
{
|
||
|
if (is_string($elements)) {
|
||
|
$elements = preg_split('/[ ]?,[ ]?/', $elements);
|
||
|
}
|
||
|
foreach (array_keys($elements) as $key) {
|
||
|
if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
|
||
|
$elements[$key]->updateAttributes($attrs);
|
||
|
} elseif (isset($this->_elementIndex[$elements[$key]])) {
|
||
|
$this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
|
||
|
if (isset($this->_duplicateIndex[$elements[$key]])) {
|
||
|
foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
|
||
|
$this->_elements[$index]->updateAttributes($attrs);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} // end func updateElementAttr
|
||
|
|
||
|
// }}}
|
||
|
// {{{ removeElement()
|
||
|
|
||
|
/**
|
||
|
* Removes an element
|
||
|
*
|
||
|
* The method "unlinks" an element from the form, returning the reference
|
||
|
* to the element object. If several elements named $elementName exist,
|
||
|
* it removes the first one, leaving the others intact.
|
||
|
*
|
||
|
* @param string $elementName The element name
|
||
|
* @param boolean $removeRules True if rules for this element are to be removed too
|
||
|
* @access public
|
||
|
* @since 2.0
|
||
|
* @return object HTML_QuickForm_element a reference to the removed element
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function &removeElement($elementName, $removeRules = true)
|
||
|
{
|
||
|
if (!isset($this->_elementIndex[$elementName])) {
|
||
|
$error = self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
|
||
|
return $error;
|
||
|
}
|
||
|
$el =& $this->_elements[$this->_elementIndex[$elementName]];
|
||
|
unset($this->_elements[$this->_elementIndex[$elementName]]);
|
||
|
if (empty($this->_duplicateIndex[$elementName])) {
|
||
|
unset($this->_elementIndex[$elementName]);
|
||
|
} else {
|
||
|
$this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
|
||
|
}
|
||
|
if ($removeRules) {
|
||
|
unset($this->_rules[$elementName], $this->_errors[$elementName]);
|
||
|
}
|
||
|
return $el;
|
||
|
} // end func removeElement
|
||
|
|
||
|
// }}}
|
||
|
// {{{ addRule()
|
||
|
|
||
|
/**
|
||
|
* Adds a validation rule for the given field
|
||
|
*
|
||
|
* If the element is in fact a group, it will be considered as a whole.
|
||
|
* To validate grouped elements as separated entities,
|
||
|
* use addGroupRule instead of addRule.
|
||
|
*
|
||
|
* @param string $element Form element name
|
||
|
* @param string $message Message to display for invalid data
|
||
|
* @param string $type Rule type, use getRegisteredRules() to get types
|
||
|
* @param string $format (optional)Required for extra rule data
|
||
|
* @param string $validation (optional)Where to perform validation: "server", "client"
|
||
|
* @param boolean $reset Client-side validation: reset the form element to its original value if there is an error?
|
||
|
* @param boolean $force Force the rule to be applied, even if the target form element does not exist
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
|
||
|
{
|
||
|
if (!$force) {
|
||
|
if (!is_array($element) && !$this->elementExists($element)) {
|
||
|
return self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
|
||
|
} elseif (is_array($element)) {
|
||
|
foreach ($element as $el) {
|
||
|
if (!$this->elementExists($el)) {
|
||
|
return self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (false === ($newName = $this->isRuleRegistered($type, true))) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
|
||
|
} elseif (is_string($newName)) {
|
||
|
$type = $newName;
|
||
|
}
|
||
|
if (is_array($element)) {
|
||
|
$dependent = $element;
|
||
|
$element = array_shift($dependent);
|
||
|
} else {
|
||
|
$dependent = null;
|
||
|
}
|
||
|
if ($type == 'required' || $type == 'uploadedfile') {
|
||
|
$this->_required[] = $element;
|
||
|
}
|
||
|
if (!isset($this->_rules[$element])) {
|
||
|
$this->_rules[$element] = array();
|
||
|
}
|
||
|
$this->_rules[$element][] = array(
|
||
|
'type' => $type,
|
||
|
'format' => $format,
|
||
|
'message' => $message,
|
||
|
'validation' => $validation,
|
||
|
'reset' => $reset,
|
||
|
'dependent' => $dependent
|
||
|
);
|
||
|
} // end func addRule
|
||
|
|
||
|
// }}}
|
||
|
// {{{ addGroupRule()
|
||
|
|
||
|
/**
|
||
|
* Adds a validation rule for the given group of elements
|
||
|
*
|
||
|
* Only groups with a name can be assigned a validation rule
|
||
|
* Use addGroupRule when you need to validate elements inside the group.
|
||
|
* Use addRule if you need to validate the group as a whole. In this case,
|
||
|
* the same rule will be applied to all elements in the group.
|
||
|
* Use addRule if you need to validate the group against a function.
|
||
|
*
|
||
|
* @param string $group Form group name
|
||
|
* @param mixed $arg1 Array for multiple elements or error message string for one element
|
||
|
* @param string $type (optional)Rule type use getRegisteredRules() to get types
|
||
|
* @param string $format (optional)Required for extra rule data
|
||
|
* @param int $howmany (optional)How many valid elements should be in the group
|
||
|
* @param string $validation (optional)Where to perform validation: "server", "client"
|
||
|
* @param bool $reset Client-side: whether to reset the element's value to its original state if validation failed.
|
||
|
* @since 2.5
|
||
|
* @access public
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
|
||
|
{
|
||
|
if (!$this->elementExists($group)) {
|
||
|
return self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
|
||
|
$groupObj =& $this->getElement($group);
|
||
|
if (is_array($arg1)) {
|
||
|
$required = 0;
|
||
|
foreach ($arg1 as $elementIndex => $rules) {
|
||
|
$elementName = $groupObj->getElementName($elementIndex);
|
||
|
foreach ($rules as $rule) {
|
||
|
$format = (isset($rule[2])) ? $rule[2] : null;
|
||
|
$validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
|
||
|
$reset = isset($rule[4]) && $rule[4];
|
||
|
$type = $rule[1];
|
||
|
if (false === ($newName = $this->isRuleRegistered($type, true))) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
|
||
|
} elseif (is_string($newName)) {
|
||
|
$type = $newName;
|
||
|
}
|
||
|
|
||
|
$this->_rules[$elementName][] = array(
|
||
|
'type' => $type,
|
||
|
'format' => $format,
|
||
|
'message' => $rule[0],
|
||
|
'validation' => $validation,
|
||
|
'reset' => $reset,
|
||
|
'group' => $group);
|
||
|
|
||
|
if ('required' == $type || 'uploadedfile' == $type) {
|
||
|
$groupObj->_required[] = $elementName;
|
||
|
$this->_required[] = $elementName;
|
||
|
$required++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($required > 0 && count($groupObj->getElements()) == $required) {
|
||
|
$this->_required[] = $group;
|
||
|
}
|
||
|
} elseif (is_string($arg1)) {
|
||
|
if (false === ($newName = $this->isRuleRegistered($type, true))) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
|
||
|
} elseif (is_string($newName)) {
|
||
|
$type = $newName;
|
||
|
}
|
||
|
|
||
|
// addGroupRule() should also handle <select multiple>
|
||
|
if (is_a($groupObj, 'html_quickform_group')) {
|
||
|
// Radios need to be handled differently when required
|
||
|
if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
|
||
|
$howmany = ($howmany == 0) ? 1 : $howmany;
|
||
|
} else {
|
||
|
$howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$this->_rules[$group][] = array('type' => $type,
|
||
|
'format' => $format,
|
||
|
'message' => $arg1,
|
||
|
'validation' => $validation,
|
||
|
'howmany' => $howmany,
|
||
|
'reset' => $reset);
|
||
|
if ($type == 'required') {
|
||
|
$this->_required[] = $group;
|
||
|
}
|
||
|
}
|
||
|
} // end func addGroupRule
|
||
|
|
||
|
// }}}
|
||
|
// {{{ addFormRule()
|
||
|
|
||
|
/**
|
||
|
* Adds a global validation rule
|
||
|
*
|
||
|
* This should be used when for a rule involving several fields or if
|
||
|
* you want to use some completely custom validation for your form.
|
||
|
* The rule function/method should return true in case of successful
|
||
|
* validation and array('element name' => 'error') when there were errors.
|
||
|
*
|
||
|
* @access public
|
||
|
* @param mixed Callback, either function name or array(&$object, 'method')
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function addFormRule($rule)
|
||
|
{
|
||
|
if (!is_callable($rule)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
$this->_formRules[] = $rule;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ applyFilter()
|
||
|
|
||
|
/**
|
||
|
* Applies a data filter for the given field(s)
|
||
|
*
|
||
|
* @param mixed $element Form element name or array of such names
|
||
|
* @param mixed $filter Callback, either function name or array(&$object, 'method')
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
*/
|
||
|
function applyFilter($element, $filter)
|
||
|
{
|
||
|
if (!is_callable($filter)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
if ($element == '__ALL__') {
|
||
|
$this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
|
||
|
} else {
|
||
|
if (!is_array($element)) {
|
||
|
$element = array($element);
|
||
|
}
|
||
|
foreach ($element as $elName) {
|
||
|
$value = $this->getSubmitValue($elName);
|
||
|
if (null !== $value) {
|
||
|
if (false === strpos($elName, '[')) {
|
||
|
$this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
|
||
|
} else {
|
||
|
$idx = "['" . str_replace(array(']', '['), array('', "']['"), $elName) . "']";
|
||
|
eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} // end func applyFilter
|
||
|
|
||
|
// }}}
|
||
|
// {{{ _recursiveFilter()
|
||
|
|
||
|
/**
|
||
|
* Recursively apply a filter function
|
||
|
*
|
||
|
* @param string $filter filter to apply
|
||
|
* @param mixed $value submitted values
|
||
|
* @since 2.0
|
||
|
* @access private
|
||
|
* @return cleaned values
|
||
|
*/
|
||
|
function _recursiveFilter($filter, $value)
|
||
|
{
|
||
|
if (is_array($value)) {
|
||
|
$cleanValues = array();
|
||
|
foreach ($value as $k => $v) {
|
||
|
$cleanValues[$k] = $this->_recursiveFilter($filter, $v);
|
||
|
}
|
||
|
return $cleanValues;
|
||
|
} else {
|
||
|
return call_user_func($filter, $value);
|
||
|
}
|
||
|
} // end func _recursiveFilter
|
||
|
|
||
|
// }}}
|
||
|
// {{{ arrayMerge()
|
||
|
|
||
|
/**
|
||
|
* Merges two arrays
|
||
|
*
|
||
|
* Merges two array like the PHP function array_merge but recursively.
|
||
|
* The main difference is that existing keys will not be renumbered
|
||
|
* if they are integers.
|
||
|
*
|
||
|
* @access puplic
|
||
|
* @param array $a original array
|
||
|
* @param array $b array which will be merged into first one
|
||
|
* @return array merged array
|
||
|
*/
|
||
|
static function arrayMerge($a, $b)
|
||
|
{
|
||
|
if (is_null($a)) {$a = array();}
|
||
|
if (is_null($b)) {$b = array();}
|
||
|
foreach ($b as $k => $v) {
|
||
|
if (is_array($v)) {
|
||
|
if (isset($a[$k]) && !is_array($a[$k])) {
|
||
|
$a[$k] = $v;
|
||
|
} else {
|
||
|
if (!isset($a[$k])) {
|
||
|
$a[$k] = array();
|
||
|
}
|
||
|
$a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
|
||
|
}
|
||
|
} else {
|
||
|
$a[$k] = $v;
|
||
|
}
|
||
|
}
|
||
|
return $a;
|
||
|
} // end func arrayMerge
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isTypeRegistered()
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the form element type is supported
|
||
|
*
|
||
|
* @param string $type Form element type
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return boolean
|
||
|
*/
|
||
|
function isTypeRegistered($type)
|
||
|
{
|
||
|
return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($type)]);
|
||
|
} // end func isTypeRegistered
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getRegisteredTypes()
|
||
|
|
||
|
/**
|
||
|
* Returns an array of registered element types
|
||
|
*
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return array
|
||
|
*/
|
||
|
function getRegisteredTypes()
|
||
|
{
|
||
|
return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
|
||
|
} // end func getRegisteredTypes
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isRuleRegistered()
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the given rule is supported
|
||
|
*
|
||
|
* @param string $name Validation rule name
|
||
|
* @param bool Whether to automatically register subclasses of HTML_QuickForm_Rule
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return mixed true if previously registered, false if not, new rule name if auto-registering worked
|
||
|
*/
|
||
|
function isRuleRegistered($name, $autoRegister = false)
|
||
|
{
|
||
|
if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
|
||
|
return true;
|
||
|
} elseif (!$autoRegister) {
|
||
|
return false;
|
||
|
}
|
||
|
// automatically register the rule if requested
|
||
|
include_once 'HTML/QuickForm/RuleRegistry.php';
|
||
|
$ruleName = false;
|
||
|
if (is_object($name) && is_a($name, 'html_quickform_rule')) {
|
||
|
$ruleName = !empty($name->name)? $name->name: strtolower(get_class($name));
|
||
|
} elseif (is_string($name) && class_exists($name)) {
|
||
|
$parent = strtolower($name);
|
||
|
do {
|
||
|
if ('html_quickform_rule' == strtolower($parent)) {
|
||
|
$ruleName = strtolower($name);
|
||
|
break;
|
||
|
}
|
||
|
} while ($parent = get_parent_class($parent));
|
||
|
}
|
||
|
if ($ruleName) {
|
||
|
$registry =& HTML_QuickForm_RuleRegistry::singleton();
|
||
|
$registry->registerRule($ruleName, null, $name);
|
||
|
}
|
||
|
return $ruleName;
|
||
|
} // end func isRuleRegistered
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getRegisteredRules()
|
||
|
|
||
|
/**
|
||
|
* Returns an array of registered validation rules
|
||
|
*
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return array
|
||
|
*/
|
||
|
function getRegisteredRules()
|
||
|
{
|
||
|
return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
|
||
|
} // end func getRegisteredRules
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isElementRequired()
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the form element is required
|
||
|
*
|
||
|
* @param string $element Form element name
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return boolean
|
||
|
*/
|
||
|
function isElementRequired($element)
|
||
|
{
|
||
|
return in_array($element, $this->_required, true);
|
||
|
} // end func isElementRequired
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isElementFrozen()
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the form element is frozen
|
||
|
*
|
||
|
* @param string $element Form element name
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @return boolean
|
||
|
*/
|
||
|
function isElementFrozen($element)
|
||
|
{
|
||
|
if (isset($this->_elementIndex[$element])) {
|
||
|
return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
|
||
|
}
|
||
|
return false;
|
||
|
} // end func isElementFrozen
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setJsWarnings()
|
||
|
|
||
|
/**
|
||
|
* Sets JavaScript warning messages
|
||
|
*
|
||
|
* @param string $pref Prefix warning
|
||
|
* @param string $post Postfix warning
|
||
|
* @since 1.1
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setJsWarnings($pref, $post)
|
||
|
{
|
||
|
$this->_jsPrefix = $pref;
|
||
|
$this->_jsPostfix = $post;
|
||
|
} // end func setJsWarnings
|
||
|
|
||
|
// }}}
|
||
|
// {{{ setRequiredNote()
|
||
|
|
||
|
/**
|
||
|
* Sets required-note
|
||
|
*
|
||
|
* @param string $note Message indicating some elements are required
|
||
|
* @since 1.1
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function setRequiredNote($note)
|
||
|
{
|
||
|
$this->_requiredNote = $note;
|
||
|
} // end func setRequiredNote
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getRequiredNote()
|
||
|
|
||
|
/**
|
||
|
* Returns the required note
|
||
|
*
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return string
|
||
|
*/
|
||
|
function getRequiredNote()
|
||
|
{
|
||
|
return $this->_requiredNote;
|
||
|
} // end func getRequiredNote
|
||
|
|
||
|
// }}}
|
||
|
// {{{ validate()
|
||
|
|
||
|
/**
|
||
|
* Performs the server side validation
|
||
|
* @access public
|
||
|
* @since 1.0
|
||
|
* @return boolean true if no error found
|
||
|
*/
|
||
|
function validate()
|
||
|
{
|
||
|
if (count($this->_rules) == 0 && count($this->_formRules) == 0 &&
|
||
|
$this->isSubmitted()) {
|
||
|
return (0 == count($this->_errors));
|
||
|
} elseif (!$this->isSubmitted()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
include_once('HTML/QuickForm/RuleRegistry.php');
|
||
|
$registry =& HTML_QuickForm_RuleRegistry::singleton();
|
||
|
|
||
|
foreach ($this->_rules as $target => $rules) {
|
||
|
$submitValue = $this->getSubmitValue($target);
|
||
|
|
||
|
foreach ($rules as $rule) {
|
||
|
if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
|
||
|
isset($this->_errors[$target])) {
|
||
|
continue 2;
|
||
|
}
|
||
|
// If element is not required and is empty, we shouldn't validate it
|
||
|
if (!$this->isElementRequired($target)) {
|
||
|
if (!isset($submitValue) || '' == $submitValue) {
|
||
|
continue 2;
|
||
|
// Fix for bug #3501: we shouldn't validate not uploaded files, either.
|
||
|
// Unfortunately, we can't just use $element->isUploadedFile() since
|
||
|
// the element in question can be buried in group. Thus this hack.
|
||
|
} elseif (is_array($submitValue)) {
|
||
|
if (false === ($pos = strpos($target, '['))) {
|
||
|
$isUpload = !empty($this->_submitFiles[$target]);
|
||
|
} else {
|
||
|
$base = substr($target, 0, $pos);
|
||
|
$idx = "['" . str_replace(array(']', '['), array('', "']['"), substr($target, $pos + 1, -1)) . "']";
|
||
|
eval("\$isUpload = isset(\$this->_submitFiles['{$base}']['name']{$idx});");
|
||
|
}
|
||
|
if ($isUpload && (!isset($submitValue['error']) || 0 != $submitValue['error'])) {
|
||
|
continue 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (isset($rule['dependent']) && is_array($rule['dependent'])) {
|
||
|
$values = array($submitValue);
|
||
|
foreach ($rule['dependent'] as $elName) {
|
||
|
$values[] = $this->getSubmitValue($elName);
|
||
|
}
|
||
|
$result = $registry->validate($rule['type'], $values, $rule['format'], true);
|
||
|
} elseif (is_array($submitValue) && !isset($rule['howmany'])) {
|
||
|
$result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
|
||
|
} else {
|
||
|
$result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
|
||
|
}
|
||
|
|
||
|
if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
|
||
|
if (isset($rule['group'])) {
|
||
|
$this->_errors[$rule['group']] = $rule['message'];
|
||
|
} else {
|
||
|
$this->_errors[$target] = $rule['message'];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// process the global rules now
|
||
|
foreach ($this->_formRules as $rule) {
|
||
|
if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
|
||
|
if (is_array($res)) {
|
||
|
$this->_errors += $res;
|
||
|
} else {
|
||
|
return self::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (0 == count($this->_errors));
|
||
|
} // end func validate
|
||
|
|
||
|
// }}}
|
||
|
// {{{ freeze()
|
||
|
|
||
|
/**
|
||
|
* Displays elements without HTML input tags
|
||
|
*
|
||
|
* @param mixed $elementList array or string of element(s) to be frozen
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function freeze($elementList=null)
|
||
|
{
|
||
|
if (!isset($elementList)) {
|
||
|
$this->_freezeAll = true;
|
||
|
$elementList = array();
|
||
|
} else {
|
||
|
if (!is_array($elementList)) {
|
||
|
$elementList = preg_split('/[ ]*,[ ]*/', $elementList);
|
||
|
}
|
||
|
$elementList = array_flip($elementList);
|
||
|
}
|
||
|
|
||
|
foreach (array_keys($this->_elements) as $key) {
|
||
|
$name = $this->_elements[$key]->getName();
|
||
|
if ($this->_freezeAll || isset($elementList[$name])) {
|
||
|
$this->_elements[$key]->freeze();
|
||
|
unset($elementList[$name]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!empty($elementList)) {
|
||
|
return self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Nonexistant element(s): '" . implode("', '", array_keys($elementList)) . "' in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
return true;
|
||
|
} // end func freeze
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isFrozen()
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the whole form is frozen
|
||
|
*
|
||
|
* @since 3.0
|
||
|
* @access public
|
||
|
* @return boolean
|
||
|
*/
|
||
|
function isFrozen()
|
||
|
{
|
||
|
return $this->_freezeAll;
|
||
|
} // end func isFrozen
|
||
|
|
||
|
// }}}
|
||
|
// {{{ process()
|
||
|
|
||
|
/**
|
||
|
* Performs the form data processing
|
||
|
*
|
||
|
* @param mixed $callback Callback, either function name or array(&$object, 'method')
|
||
|
* @param bool $mergeFiles Whether uploaded files should be processed too
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function process($callback, $mergeFiles = true)
|
||
|
{
|
||
|
if (!is_callable($callback)) {
|
||
|
return self::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
$values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
|
||
|
return call_user_func($callback, $values);
|
||
|
} // end func process
|
||
|
|
||
|
// }}}
|
||
|
// {{{ accept()
|
||
|
|
||
|
/**
|
||
|
* Accepts a renderer
|
||
|
*
|
||
|
* @param object An HTML_QuickForm_Renderer object
|
||
|
* @since 3.0
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
function accept(&$renderer)
|
||
|
{
|
||
|
$renderer->startForm($this);
|
||
|
foreach (array_keys($this->_elements) as $key) {
|
||
|
$element =& $this->_elements[$key];
|
||
|
$elementName = $element->getName();
|
||
|
$required = ($this->isElementRequired($elementName) && !$element->isFrozen());
|
||
|
$error = $this->getElementError($elementName);
|
||
|
$element->accept($renderer, $required, $error);
|
||
|
}
|
||
|
$renderer->finishForm($this);
|
||
|
} // end func accept
|
||
|
|
||
|
// }}}
|
||
|
// {{{ defaultRenderer()
|
||
|
|
||
|
/**
|
||
|
* Returns a reference to default renderer object
|
||
|
*
|
||
|
* @access public
|
||
|
* @since 3.0
|
||
|
* @return object a default renderer object
|
||
|
*/
|
||
|
function &defaultRenderer()
|
||
|
{
|
||
|
if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
|
||
|
include_once('HTML/QuickForm/Renderer/Default.php');
|
||
|
$GLOBALS['_HTML_QuickForm_default_renderer'] = new HTML_QuickForm_Renderer_Default(); //Moodle: PHP 5.3 compatibility
|
||
|
}
|
||
|
return $GLOBALS['_HTML_QuickForm_default_renderer'];
|
||
|
} // end func defaultRenderer
|
||
|
|
||
|
// }}}
|
||
|
// {{{ toHtml ()
|
||
|
|
||
|
/**
|
||
|
* Returns an HTML version of the form
|
||
|
*
|
||
|
* @param string $in_data (optional) Any extra data to insert right
|
||
|
* before form is rendered. Useful when using templates.
|
||
|
*
|
||
|
* @return string Html version of the form
|
||
|
* @since 1.0
|
||
|
* @access public
|
||
|
*/
|
||
|
function toHtml ($in_data = null)
|
||
|
{
|
||
|
if (!is_null($in_data)) {
|
||
|
$this->addElement('html', $in_data);
|
||
|
}
|
||
|
$renderer =& $this->defaultRenderer();
|
||
|
$this->accept($renderer);
|
||
|
return $renderer->toHtml();
|
||
|
} // end func toHtml
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getValidationScript()
|
||
|
|
||
|
/**
|
||
|
* Returns the client side validation script
|
||
|
*
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @return string Javascript to perform validation, empty string if no 'client' rules were added
|
||
|
*/
|
||
|
function getValidationScript()
|
||
|
{
|
||
|
if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
include_once('HTML/QuickForm/RuleRegistry.php');
|
||
|
$registry =& HTML_QuickForm_RuleRegistry::singleton();
|
||
|
$test = array();
|
||
|
$js_escape = array(
|
||
|
"\r" => '\r',
|
||
|
"\n" => '\n',
|
||
|
"\t" => '\t',
|
||
|
"'" => "\\'",
|
||
|
'"' => '\"',
|
||
|
'\\' => '\\\\'
|
||
|
);
|
||
|
|
||
|
foreach ($this->_rules as $elementName => $rules) {
|
||
|
foreach ($rules as $rule) {
|
||
|
if ('client' == $rule['validation']) {
|
||
|
unset($element);
|
||
|
|
||
|
$dependent = isset($rule['dependent']) && is_array($rule['dependent']);
|
||
|
$rule['message'] = strtr($rule['message'], $js_escape);
|
||
|
|
||
|
if (isset($rule['group'])) {
|
||
|
$group =& $this->getElement($rule['group']);
|
||
|
// No JavaScript validation for frozen elements
|
||
|
if ($group->isFrozen()) {
|
||
|
continue 2;
|
||
|
}
|
||
|
$elements =& $group->getElements();
|
||
|
foreach (array_keys($elements) as $key) {
|
||
|
if ($elementName == $group->getElementName($key)) {
|
||
|
$element =& $elements[$key];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} elseif ($dependent) {
|
||
|
$element = array();
|
||
|
$element[] =& $this->getElement($elementName);
|
||
|
foreach ($rule['dependent'] as $elName) {
|
||
|
$element[] =& $this->getElement($elName);
|
||
|
}
|
||
|
} else {
|
||
|
$element =& $this->getElement($elementName);
|
||
|
}
|
||
|
// No JavaScript validation for frozen elements
|
||
|
if (is_object($element) && $element->isFrozen()) {
|
||
|
continue 2;
|
||
|
} elseif (is_array($element)) {
|
||
|
foreach (array_keys($element) as $key) {
|
||
|
if ($element[$key]->isFrozen()) {
|
||
|
continue 3;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$test[] = $registry->getValidationScript($element, $elementName, $rule);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (count($test) > 0) {
|
||
|
return
|
||
|
"\n<script type=\"text/javascript\">\n" .
|
||
|
"//<![CDATA[\n" .
|
||
|
"function validate_" . $this->_attributes['id'] . "(frm) {\n" .
|
||
|
" var value = '';\n" .
|
||
|
" var errFlag = new Array();\n" .
|
||
|
" var _qfGroups = {};\n" .
|
||
|
" _qfMsg = '';\n\n" .
|
||
|
join("\n", $test) .
|
||
|
"\n if (_qfMsg != '') {\n" .
|
||
|
" _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
|
||
|
" _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
|
||
|
" alert(_qfMsg);\n" .
|
||
|
" return false;\n" .
|
||
|
" }\n" .
|
||
|
" return true;\n" .
|
||
|
"}\n" .
|
||
|
"//]]>\n" .
|
||
|
"</script>";
|
||
|
}
|
||
|
return '';
|
||
|
} // end func getValidationScript
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getSubmitValues()
|
||
|
|
||
|
/**
|
||
|
* Returns the values submitted by the form
|
||
|
*
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @param bool Whether uploaded files should be returned too
|
||
|
* @return array
|
||
|
*/
|
||
|
function getSubmitValues($mergeFiles = false)
|
||
|
{
|
||
|
return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
|
||
|
} // end func getSubmitValues
|
||
|
|
||
|
// }}}
|
||
|
// {{{ toArray()
|
||
|
|
||
|
/**
|
||
|
* Returns the form's contents in an array.
|
||
|
*
|
||
|
* The description of the array structure is in HTML_QuickForm_Renderer_Array docs
|
||
|
*
|
||
|
* @since 2.0
|
||
|
* @access public
|
||
|
* @param bool Whether to collect hidden elements (passed to the Renderer's constructor)
|
||
|
* @return array of form contents
|
||
|
*/
|
||
|
function toArray($collectHidden = false)
|
||
|
{
|
||
|
include_once 'HTML/QuickForm/Renderer/Array.php';
|
||
|
$renderer = new HTML_QuickForm_Renderer_Array($collectHidden); //Moodle: PHP 5.3 compatibility
|
||
|
$this->accept($renderer);
|
||
|
return $renderer->toArray();
|
||
|
} // end func toArray
|
||
|
|
||
|
// }}}
|
||
|
// {{{ exportValue()
|
||
|
|
||
|
/**
|
||
|
* Returns a 'safe' element's value
|
||
|
*
|
||
|
* This method first tries to find a cleaned-up submitted value,
|
||
|
* it will return a value set by setValue()/setDefaults()/setConstants()
|
||
|
* if submitted value does not exist for the given element.
|
||
|
*
|
||
|
* @param string Name of an element
|
||
|
* @access public
|
||
|
* @return mixed
|
||
|
*/
|
||
|
function exportValue($element)
|
||
|
{
|
||
|
if (!isset($this->_elementIndex[$element])) {
|
||
|
return self::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
|
||
|
}
|
||
|
$value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
|
||
|
if (isset($this->_duplicateIndex[$element])) {
|
||
|
foreach ($this->_duplicateIndex[$element] as $index) {
|
||
|
if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
|
||
|
if (is_array($value)) {
|
||
|
$value[] = $v;
|
||
|
} else {
|
||
|
$value = (null === $value)? $v: array($value, $v);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ exportValues()
|
||
|
|
||
|
/**
|
||
|
* Returns 'safe' elements' values
|
||
|
*
|
||
|
* Unlike getSubmitValues(), this will return only the values
|
||
|
* corresponding to the elements present in the form.
|
||
|
*
|
||
|
* @param mixed Array/string of element names, whose values we want. If not set then return all elements.
|
||
|
* @access public
|
||
|
* @return array An assoc array of elements' values
|
||
|
* @throws HTML_QuickForm_Error
|
||
|
*/
|
||
|
function exportValues($elementList = null)
|
||
|
{
|
||
|
$values = array();
|
||
|
if (null === $elementList) {
|
||
|
// iterate over all elements, calling their exportValue() methods
|
||
|
foreach (array_keys($this->_elements) as $key) {
|
||
|
$value = $this->_elements[$key]->exportValue($this->_submitValues, true);
|
||
|
if (is_array($value)) {
|
||
|
// This shit throws a bogus warning in PHP 4.3.x
|
||
|
$values = HTML_QuickForm::arrayMerge($values, $value);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (!is_array($elementList)) {
|
||
|
$elementList = array_map('trim', explode(',', $elementList));
|
||
|
}
|
||
|
foreach ($elementList as $elementName) {
|
||
|
$value = $this->exportValue($elementName);
|
||
|
$pear = new PEAR();
|
||
|
if ($pear->isError($value)) {
|
||
|
return $value;
|
||
|
}
|
||
|
$values[$elementName] = $value;
|
||
|
}
|
||
|
}
|
||
|
return $values;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isSubmitted()
|
||
|
|
||
|
/**
|
||
|
* Tells whether the form was already submitted
|
||
|
*
|
||
|
* This is useful since the _submitFiles and _submitValues arrays
|
||
|
* may be completely empty after the trackSubmit value is removed.
|
||
|
*
|
||
|
* @access public
|
||
|
* @return bool
|
||
|
*/
|
||
|
function isSubmitted()
|
||
|
{
|
||
|
return $this->_flagSubmitted;
|
||
|
}
|
||
|
|
||
|
|
||
|
// }}}
|
||
|
// {{{ isError()
|
||
|
|
||
|
/**
|
||
|
* Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
|
||
|
*
|
||
|
* @access public
|
||
|
* @param mixed result code
|
||
|
* @return bool whether $value is an error
|
||
|
*/
|
||
|
static function isError($value)
|
||
|
{
|
||
|
return (is_object($value) && is_a($value, 'html_quickform_error'));
|
||
|
} // end func isError
|
||
|
|
||
|
// }}}
|
||
|
// {{{ errorMessage()
|
||
|
|
||
|
/**
|
||
|
* Return a textual error message for an QuickForm error code
|
||
|
*
|
||
|
* @access public
|
||
|
* @param int error code
|
||
|
* @return string error message
|
||
|
*/
|
||
|
static function errorMessage($value)
|
||
|
{
|
||
|
// make the variable static so that it only has to do the defining on the first call
|
||
|
static $errorMessages;
|
||
|
|
||
|
// define the varies error messages
|
||
|
if (!isset($errorMessages)) {
|
||
|
$errorMessages = array(
|
||
|
QUICKFORM_OK => 'no error',
|
||
|
QUICKFORM_ERROR => 'unknown error',
|
||
|
QUICKFORM_INVALID_RULE => 'the rule does not exist as a registered rule',
|
||
|
QUICKFORM_NONEXIST_ELEMENT => 'nonexistent html element',
|
||
|
QUICKFORM_INVALID_FILTER => 'invalid filter',
|
||
|
QUICKFORM_UNREGISTERED_ELEMENT => 'unregistered element',
|
||
|
QUICKFORM_INVALID_ELEMENT_NAME => 'element already exists',
|
||
|
QUICKFORM_INVALID_PROCESS => 'process callback does not exist',
|
||
|
QUICKFORM_DEPRECATED => 'method is deprecated',
|
||
|
QUICKFORM_INVALID_DATASOURCE => 'datasource is not an object'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// If this is an error object, then grab the corresponding error code
|
||
|
if (HTML_QuickForm::isError($value)) {
|
||
|
$value = $value->getCode();
|
||
|
}
|
||
|
|
||
|
// return the textual error message corresponding to the code
|
||
|
return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
|
||
|
} // end func errorMessage
|
||
|
|
||
|
// }}}
|
||
|
} // end class HTML_QuickForm
|
||
|
|
||
|
class HTML_QuickForm_Error extends PEAR_Error {
|
||
|
|
||
|
// {{{ properties
|
||
|
|
||
|
/**
|
||
|
* Prefix for all error messages
|
||
|
* @var string
|
||
|
*/
|
||
|
var $error_message_prefix = 'QuickForm Error: ';
|
||
|
|
||
|
// }}}
|
||
|
// {{{ constructor
|
||
|
|
||
|
/**
|
||
|
* Creates a quickform error object, extending the PEAR_Error class
|
||
|
*
|
||
|
* @param int $code the error code
|
||
|
* @param int $mode the reaction to the error, either return, die or trigger/callback
|
||
|
* @param int $level intensity of the error (PHP error code)
|
||
|
* @param mixed $debuginfo any information that can inform user as to nature of the error
|
||
|
*/
|
||
|
public function __construct($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
|
||
|
$level = E_USER_NOTICE, $debuginfo = null)
|
||
|
{
|
||
|
if (is_int($code)) {
|
||
|
parent::__construct(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
|
||
|
} else {
|
||
|
parent::__construct("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Old syntax of class constructor. Deprecated in PHP7.
|
||
|
*
|
||
|
* @deprecated since Moodle 3.1
|
||
|
*/
|
||
|
public function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
|
||
|
$level = E_USER_NOTICE, $debuginfo = null) {
|
||
|
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
|
||
|
self::__construct($code, $mode, $level, $debuginfo);
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
} // end class HTML_QuickForm_Error
|
||
|
?>
|