home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / HTML / QuickForm.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  78.3 KB  |  2,059 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * Create, validate and process HTML forms
  6.  * 
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: This source file is subject to version 3.01 of the PHP license
  10.  * that is available through the world-wide-web at the following URI:
  11.  * http://www.php.net/license/3_01.txt If you did not receive a copy of
  12.  * the PHP License and are unable to obtain it through the web, please
  13.  * send a note to license@php.net so we can mail you a copy immediately.
  14.  *
  15.  * @category    HTML
  16.  * @package     HTML_QuickForm
  17.  * @author      Adam Daniel <adaniel1@eesus.jnj.com>
  18.  * @author      Bertrand Mansion <bmansion@mamasam.com>
  19.  * @author      Alexey Borzov <avb@php.net>
  20.  * @copyright   2001-2007 The PHP Group
  21.  * @license     http://www.php.net/license/3_01.txt PHP License 3.01
  22.  * @version     CVS: $Id: QuickForm.php,v 1.164 2007/10/05 19:57:32 avb Exp $
  23.  * @link        http://pear.php.net/package/HTML_QuickForm
  24.  */
  25.  
  26. /**
  27.  * PEAR and PEAR_Error classes, for error handling
  28.  */
  29. require_once 'PEAR.php';
  30. /**
  31.  * Base class for all HTML classes
  32.  */
  33. require_once 'HTML/Common.php';
  34.  
  35. /**
  36.  * Element types known to HTML_QuickForm
  37.  * @see HTML_QuickForm::registerElementType(), HTML_QuickForm::getRegisteredTypes(),
  38.  *      HTML_QuickForm::isTypeRegistered()
  39.  * @global array $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']
  40.  */ 
  41. $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] = 
  42.         array(
  43.             'group'         =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
  44.             'hidden'        =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
  45.             'reset'         =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
  46.             'checkbox'      =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
  47.             'file'          =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
  48.             'image'         =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
  49.             'password'      =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
  50.             'radio'         =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
  51.             'button'        =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
  52.             'submit'        =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
  53.             'select'        =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
  54.             'hiddenselect'  =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
  55.             'text'          =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
  56.             'textarea'      =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
  57.             'link'          =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
  58.             'advcheckbox'   =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
  59.             'date'          =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
  60.             'static'        =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
  61.             'header'        =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
  62.             'html'          =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
  63.             'hierselect'    =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
  64.             'autocomplete'  =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
  65.             'xbutton'       =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
  66.         );
  67.  
  68. /**
  69.  * Validation rules known to HTML_QuickForm 
  70.  * @see HTML_QuickForm::registerRule(), HTML_QuickForm::getRegisteredRules(),
  71.  *      HTML_QuickForm::isRuleRegistered()
  72.  * @global array $GLOBALS['_HTML_QuickForm_registered_rules']
  73.  */
  74. $GLOBALS['_HTML_QuickForm_registered_rules'] = array(
  75.     'required'      => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
  76.     'maxlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  77.     'minlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  78.     'rangelength'   => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  79.     'email'         => array('html_quickform_rule_email',    'HTML/QuickForm/Rule/Email.php'),
  80.     'regex'         => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  81.     'lettersonly'   => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  82.     'alphanumeric'  => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  83.     'numeric'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  84.     'nopunctuation' => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  85.     'nonzero'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  86.     'callback'      => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
  87.     'compare'       => array('html_quickform_rule_compare',  'HTML/QuickForm/Rule/Compare.php')
  88. );
  89.  
  90. // {{{ error codes
  91.  
  92. /**#@+
  93.  * Error codes for HTML_QuickForm
  94.  *
  95.  * Codes are mapped to textual messages by errorMessage() method, if you add a 
  96.  * new code be sure to add a new message for it to errorMessage()
  97.  *
  98.  * @see HTML_QuickForm::errorMessage()
  99.  */ 
  100. define('QUICKFORM_OK',                      1);
  101. define('QUICKFORM_ERROR',                  -1);
  102. define('QUICKFORM_INVALID_RULE',           -2);
  103. define('QUICKFORM_NONEXIST_ELEMENT',       -3);
  104. define('QUICKFORM_INVALID_FILTER',         -4);
  105. define('QUICKFORM_UNREGISTERED_ELEMENT',   -5);
  106. define('QUICKFORM_INVALID_ELEMENT_NAME',   -6);
  107. define('QUICKFORM_INVALID_PROCESS',        -7);
  108. define('QUICKFORM_DEPRECATED',             -8);
  109. define('QUICKFORM_INVALID_DATASOURCE',     -9);
  110. /**#@-*/
  111.  
  112. // }}}
  113.  
  114. /**
  115.  * Create, validate and process HTML forms
  116.  *
  117.  * @category    HTML
  118.  * @package     HTML_QuickForm
  119.  * @author      Adam Daniel <adaniel1@eesus.jnj.com>
  120.  * @author      Bertrand Mansion <bmansion@mamasam.com>
  121.  * @author      Alexey Borzov <avb@php.net>
  122.  * @version     Release: 3.2.10
  123.  */
  124. class HTML_QuickForm extends HTML_Common
  125. {
  126.     // {{{ properties
  127.  
  128.     /**
  129.      * Array containing the form fields
  130.      * @since     1.0
  131.      * @var  array
  132.      * @access   private
  133.      */
  134.     var $_elements = array();
  135.  
  136.     /**
  137.      * Array containing element name to index map
  138.      * @since     1.1
  139.      * @var  array
  140.      * @access   private
  141.      */
  142.     var $_elementIndex = array();
  143.  
  144.     /**
  145.      * Array containing indexes of duplicate elements
  146.      * @since     2.10
  147.      * @var  array
  148.      * @access   private
  149.      */
  150.     var $_duplicateIndex = array();
  151.  
  152.     /**
  153.      * Array containing required field IDs
  154.      * @since     1.0
  155.      * @var  array
  156.      * @access   private
  157.      */ 
  158.     var $_required = array();
  159.  
  160.     /**
  161.      * Prefix message in javascript alert if error
  162.      * @since     1.0
  163.      * @var  string
  164.      * @access   public
  165.      */ 
  166.     var $_jsPrefix = 'Invalid information entered.';
  167.  
  168.     /**
  169.      * Postfix message in javascript alert if error
  170.      * @since     1.0
  171.      * @var  string
  172.      * @access   public
  173.      */ 
  174.     var $_jsPostfix = 'Please correct these fields.';
  175.  
  176.     /**
  177.      * Datasource object implementing the informal
  178.      * datasource protocol
  179.      * @since     3.3
  180.      * @var  object
  181.      * @access   private
  182.      */
  183.     var $_datasource;
  184.  
  185.     /**
  186.      * Array of default form values
  187.      * @since     2.0
  188.      * @var  array
  189.      * @access   private
  190.      */
  191.     var $_defaultValues = array();
  192.  
  193.     /**
  194.      * Array of constant form values
  195.      * @since     2.0
  196.      * @var  array
  197.      * @access   private
  198.      */
  199.     var $_constantValues = array();
  200.  
  201.     /**
  202.      * Array of submitted form values
  203.      * @since     1.0
  204.      * @var  array
  205.      * @access   private
  206.      */
  207.     var $_submitValues = array();
  208.  
  209.     /**
  210.      * Array of submitted form files
  211.      * @since     1.0
  212.      * @var  integer
  213.      * @access   public
  214.      */
  215.     var $_submitFiles = array();
  216.  
  217.     /**
  218.      * Value for maxfilesize hidden element if form contains file input
  219.      * @since     1.0
  220.      * @var  integer
  221.      * @access   public
  222.      */
  223.     var $_maxFileSize = 1048576; // 1 Mb = 1048576
  224.  
  225.     /**
  226.      * Flag to know if all fields are frozen
  227.      * @since     1.0
  228.      * @var  boolean
  229.      * @access   private
  230.      */
  231.     var $_freezeAll = false;
  232.  
  233.     /**
  234.      * Array containing the form rules
  235.      * @since     1.0
  236.      * @var  array
  237.      * @access   private
  238.      */
  239.     var $_rules = array();
  240.  
  241.     /**
  242.      * Form rules, global variety
  243.      * @var     array
  244.      * @access  private
  245.      */
  246.     var $_formRules = array();
  247.  
  248.     /**
  249.      * Array containing the validation errors
  250.      * @since     1.0
  251.      * @var  array
  252.      * @access   private
  253.      */
  254.     var $_errors = array();
  255.  
  256.     /**
  257.      * Note for required fields in the form
  258.      * @var       string
  259.      * @since     1.0
  260.      * @access    private
  261.      */
  262.     var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
  263.  
  264.     /**
  265.      * Whether the form was submitted
  266.      * @var       boolean
  267.      * @access    private
  268.      */
  269.     var $_flagSubmitted = false;
  270.  
  271.     // }}}
  272.     // {{{ constructor
  273.  
  274.     /**
  275.      * Class constructor
  276.      * @param    string      $formName          Form's name.
  277.      * @param    string      $method            (optional)Form's method defaults to 'POST'
  278.      * @param    string      $action            (optional)Form's action
  279.      * @param    string      $target            (optional)Form's target defaults to '_self'
  280.      * @param    mixed       $attributes        (optional)Extra attributes for <form> tag
  281.      * @param    bool        $trackSubmit       (optional)Whether to track if the form was submitted by adding a special hidden field
  282.      * @access   public
  283.      */
  284.     function HTML_QuickForm($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false)
  285.     {
  286.         HTML_Common::HTML_Common($attributes);
  287.         $method = (strtoupper($method) == 'GET') ? 'get' : 'post';
  288.         $action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
  289.         $target = empty($target) ? array() : array('target' => $target);
  290.         $attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
  291.         $this->updateAttributes($attributes);
  292.         if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
  293.             if (1 == get_magic_quotes_gpc()) {
  294.                 $this->_submitValues = $this->_recursiveFilter('stripslashes', 'get' == $method? $_GET: $_POST);
  295.                 foreach ($_FILES as $keyFirst => $valFirst) {
  296.                     foreach ($valFirst as $keySecond => $valSecond) {
  297.                         if ('name' == $keySecond) {
  298.                             $this->_submitFiles[$keyFirst][$keySecond] = $this->_recursiveFilter('stripslashes', $valSecond);
  299.                         } else {
  300.                             $this->_submitFiles[$keyFirst][$keySecond] = $valSecond;
  301.                         }
  302.                     }
  303.                 }
  304.             } else {
  305.                 $this->_submitValues = 'get' == $method? $_GET: $_POST;
  306.                 $this->_submitFiles  = $_FILES;
  307.             }
  308.             $this->_flagSubmitted = count($this->_submitValues) > 0 || count($this->_submitFiles) > 0;
  309.         }
  310.         if ($trackSubmit) {
  311.             unset($this->_submitValues['_qf__' . $formName]);
  312.             $this->addElement('hidden', '_qf__' . $formName, null);
  313.         }
  314.         if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', ini_get('upload_max_filesize'), $matches)) {
  315.             // see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
  316.             switch (strtoupper($matches['2'])) {
  317.                 case 'G':
  318.                     $this->_maxFileSize = $matches['1'] * 1073741824;
  319.                     break;
  320.                 case 'M':
  321.                     $this->_maxFileSize = $matches['1'] * 1048576;
  322.                     break;
  323.                 case 'K':
  324.                     $this->_maxFileSize = $matches['1'] * 1024;
  325.                     break;
  326.                 default:
  327.                     $this->_maxFileSize = $matches['1'];
  328.             }
  329.         }    
  330.     } // end constructor
  331.  
  332.     // }}}
  333.     // {{{ apiVersion()
  334.  
  335.     /**
  336.      * Returns the current API version
  337.      *
  338.      * @since     1.0
  339.      * @access    public
  340.      * @return    float
  341.      */
  342.     function apiVersion()
  343.     {
  344.         return 3.2;
  345.     } // end func apiVersion
  346.  
  347.     // }}}
  348.     // {{{ registerElementType()
  349.  
  350.     /**
  351.      * Registers a new element type
  352.      *
  353.      * @param     string    $typeName   Name of element type
  354.      * @param     string    $include    Include path for element type
  355.      * @param     string    $className  Element class name
  356.      * @since     1.0
  357.      * @access    public
  358.      * @return    void
  359.      */
  360.     function registerElementType($typeName, $include, $className)
  361.     {
  362.         $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
  363.     } // end func registerElementType
  364.  
  365.     // }}}
  366.     // {{{ registerRule()
  367.  
  368.     /**
  369.      * Registers a new validation rule
  370.      *
  371.      * @param     string    $ruleName   Name of validation rule
  372.      * @param     string    $type       Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
  373.      * @param     string    $data1      Name of function, regular expression or HTML_QuickForm_Rule classname
  374.      * @param     string    $data2      Object parent of above function or HTML_QuickForm_Rule file path
  375.      * @since     1.0
  376.      * @access    public
  377.      * @return    void
  378.      */
  379.     function registerRule($ruleName, $type, $data1, $data2 = null)
  380.     {
  381.         include_once('HTML/QuickForm/RuleRegistry.php');
  382.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  383.         $registry->registerRule($ruleName, $type, $data1, $data2);
  384.     } // end func registerRule
  385.  
  386.     // }}}
  387.     // {{{ elementExists()
  388.  
  389.     /**
  390.      * Returns true if element is in the form
  391.      *
  392.      * @param     string   $element         form name of element to check
  393.      * @since     1.0
  394.      * @access    public
  395.      * @return    boolean
  396.      */
  397.     function elementExists($element=null)
  398.     {
  399.         return isset($this->_elementIndex[$element]);
  400.     } // end func elementExists
  401.  
  402.     // }}}
  403.     // {{{ setDatasource()
  404.  
  405.     /**
  406.      * Sets a datasource object for this form object
  407.      *
  408.      * Datasource default and constant values will feed the QuickForm object if
  409.      * the datasource implements defaultValues() and constantValues() methods.
  410.      *
  411.      * @param     object   $datasource          datasource object implementing the informal datasource protocol
  412.      * @param     mixed    $defaultsFilter      string or array of filter(s) to apply to default values
  413.      * @param     mixed    $constantsFilter     string or array of filter(s) to apply to constants values
  414.      * @since     3.3
  415.      * @access    public
  416.      * @return    void
  417.      * @throws    HTML_QuickForm_Error
  418.      */
  419.     function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
  420.     {
  421.         if (is_object($datasource)) {
  422.             $this->_datasource =& $datasource;
  423.             if (is_callable(array($datasource, 'defaultValues'))) {
  424.                 $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
  425.             }
  426.             if (is_callable(array($datasource, 'constantValues'))) {
  427.                 $this->setConstants($datasource->constantValues($this), $constantsFilter);
  428.             }
  429.         } else {
  430.             return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
  431.         }
  432.     } // end func setDatasource
  433.  
  434.     // }}}
  435.     // {{{ setDefaults()
  436.  
  437.     /**
  438.      * Initializes default form values
  439.      *
  440.      * @param     array    $defaultValues       values used to fill the form
  441.      * @param     mixed    $filter              (optional) filter(s) to apply to all default values
  442.      * @since     1.0
  443.      * @access    public
  444.      * @return    void
  445.      * @throws    HTML_QuickForm_Error
  446.      */
  447.     function setDefaults($defaultValues = null, $filter = null)
  448.     {
  449.         if (is_array($defaultValues)) {
  450.             if (isset($filter)) {
  451.                 if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  452.                     foreach ($filter as $val) {
  453.                         if (!is_callable($val)) {
  454.                             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  455.                         } else {
  456.                             $defaultValues = $this->_recursiveFilter($val, $defaultValues);
  457.                         }
  458.                     }
  459.                 } elseif (!is_callable($filter)) {
  460.                     return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  461.                 } else {
  462.                     $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
  463.                 }
  464.             }
  465.             $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
  466.             foreach (array_keys($this->_elements) as $key) {
  467.                 $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  468.             }
  469.         }
  470.     } // end func setDefaults
  471.  
  472.     // }}}
  473.     // {{{ setConstants()
  474.  
  475.     /**
  476.      * Initializes constant form values.
  477.      * These values won't get overridden by POST or GET vars
  478.      *
  479.      * @param     array   $constantValues        values used to fill the form    
  480.      * @param     mixed    $filter              (optional) filter(s) to apply to all default values    
  481.      *
  482.      * @since     2.0
  483.      * @access    public
  484.      * @return    void
  485.      * @throws    HTML_QuickForm_Error
  486.      */
  487.     function setConstants($constantValues = null, $filter = null)
  488.     {
  489.         if (is_array($constantValues)) {
  490.             if (isset($filter)) {
  491.                 if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  492.                     foreach ($filter as $val) {
  493.                         if (!is_callable($val)) {
  494.                             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  495.                         } else {
  496.                             $constantValues = $this->_recursiveFilter($val, $constantValues);
  497.                         }
  498.                     }
  499.                 } elseif (!is_callable($filter)) {
  500.                     return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  501.                 } else {
  502.                     $constantValues = $this->_recursiveFilter($filter, $constantValues);
  503.                 }
  504.             }
  505.             $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
  506.             foreach (array_keys($this->_elements) as $key) {
  507.                 $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  508.             }
  509.         }
  510.     } // end func setConstants
  511.  
  512.     // }}}
  513.     // {{{ setMaxFileSize()
  514.  
  515.     /**
  516.      * Sets the value of MAX_FILE_SIZE hidden element
  517.      *
  518.      * @param     int    $bytes    Size in bytes
  519.      * @since     3.0
  520.      * @access    public
  521.      * @return    void
  522.      */
  523.     function setMaxFileSize($bytes = 0)
  524.     {
  525.         if ($bytes > 0) {
  526.             $this->_maxFileSize = $bytes;
  527.         }
  528.         if (!$this->elementExists('MAX_FILE_SIZE')) {
  529.             $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
  530.         } else {
  531.             $el =& $this->getElement('MAX_FILE_SIZE');
  532.             $el->updateAttributes(array('value' => $this->_maxFileSize));
  533.         }
  534.     } // end func setMaxFileSize
  535.  
  536.     // }}}
  537.     // {{{ getMaxFileSize()
  538.  
  539.     /**
  540.      * Returns the value of MAX_FILE_SIZE hidden element
  541.      *
  542.      * @since     3.0
  543.      * @access    public
  544.      * @return    int   max file size in bytes
  545.      */
  546.     function getMaxFileSize()
  547.     {
  548.         return $this->_maxFileSize;
  549.     } // end func getMaxFileSize
  550.  
  551.     // }}}
  552.     // {{{ &createElement()
  553.  
  554.     /**
  555.      * Creates a new form element of the given type.
  556.      * 
  557.      * This method accepts variable number of parameters, their 
  558.      * meaning and count depending on $elementType
  559.      *
  560.      * @param     string     $elementType    type of element to add (text, textarea, file...)
  561.      * @since     1.0
  562.      * @access    public
  563.      * @return    HTML_QuickForm_Element
  564.      * @throws    HTML_QuickForm_Error
  565.      */
  566.     function &createElement($elementType)
  567.     {
  568.         $args    =  func_get_args();
  569.         $element =& HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1));
  570.         return $element;
  571.     } // end func createElement
  572.  
  573.     // }}}
  574.     // {{{ _loadElement()
  575.  
  576.     /**
  577.      * Returns a form element of the given type
  578.      *
  579.      * @param     string   $event   event to send to newly created element ('createElement' or 'addElement')
  580.      * @param     string   $type    element type
  581.      * @param     array    $args    arguments for event
  582.      * @since     2.0
  583.      * @access    private
  584.      * @return    HTML_QuickForm_Element
  585.      * @throws    HTML_QuickForm_Error
  586.      */
  587.     function &_loadElement($event, $type, $args)
  588.     {
  589.         $type = strtolower($type);
  590.         if (!HTML_QuickForm::isTypeRegistered($type)) {
  591.             $error = PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
  592.             return $error;
  593.         }
  594.         $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
  595.         $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
  596.         include_once($includeFile);
  597.         $elementObject =& new $className();
  598.         for ($i = 0; $i < 5; $i++) {
  599.             if (!isset($args[$i])) {
  600.                 $args[$i] = null;
  601.             }
  602.         }
  603.         $err = $elementObject->onQuickFormEvent($event, $args, $this);
  604.         if ($err !== true) {
  605.             return $err;
  606.         }
  607.         return $elementObject;
  608.     } // end func _loadElement
  609.  
  610.     // }}}
  611.     // {{{ addElement()
  612.  
  613.     /**
  614.      * Adds an element into the form
  615.      * 
  616.      * If $element is a string representing element type, then this 
  617.      * method accepts variable number of parameters, their meaning 
  618.      * and count depending on $element
  619.      *
  620.      * @param    mixed      $element        element object or type of element to add (text, textarea, file...)
  621.      * @since    1.0
  622.      * @return   HTML_QuickForm_Element     a reference to newly added element
  623.      * @access   public
  624.      * @throws   HTML_QuickForm_Error
  625.      */
  626.     function &addElement($element)
  627.     {
  628.         if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
  629.            $elementObject = &$element;
  630.            $elementObject->onQuickFormEvent('updateValue', null, $this);
  631.         } else {
  632.             $args = func_get_args();
  633.             $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1));
  634.             if (PEAR::isError($elementObject)) {
  635.                 return $elementObject;
  636.             }
  637.         }
  638.         $elementName = $elementObject->getName();
  639.  
  640.         // Add the element if it is not an incompatible duplicate
  641.         if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  642.             if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
  643.                 $elementObject->getType()) {
  644.                 $this->_elements[] =& $elementObject;
  645.                 $elKeys = array_keys($this->_elements);
  646.                 $this->_duplicateIndex[$elementName][] = end($elKeys);
  647.             } else {
  648.                 $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
  649.                 return $error;
  650.             }
  651.         } else {
  652.             $this->_elements[] =& $elementObject;
  653.             $elKeys = array_keys($this->_elements);
  654.             $this->_elementIndex[$elementName] = end($elKeys);
  655.         }
  656.         if ($this->_freezeAll) {
  657.             $elementObject->freeze();
  658.         }
  659.  
  660.         return $elementObject;
  661.     } // end func addElement
  662.     
  663.     // }}}
  664.     // {{{ insertElementBefore()
  665.  
  666.    /**
  667.     * Inserts a new element right before the other element
  668.     *
  669.     * Warning: it is not possible to check whether the $element is already
  670.     * added to the form, therefore if you want to move the existing form
  671.     * element to a new position, you'll have to use removeElement():
  672.     * $form->insertElementBefore($form->removeElement('foo', false), 'bar');
  673.     *
  674.     * @access   public
  675.     * @since    3.2.4
  676.     * @param    HTML_QuickForm_element  Element to insert
  677.     * @param    string                  Name of the element before which the new
  678.     *                                   one is inserted
  679.     * @return   HTML_QuickForm_element  reference to inserted element
  680.     * @throws   HTML_QuickForm_Error
  681.     */
  682.     function &insertElementBefore(&$element, $nameAfter)
  683.     {
  684.         if (!empty($this->_duplicateIndex[$nameAfter])) {
  685.             $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, 'Several elements named "' . $nameAfter . '" exist in HTML_QuickForm::insertElementBefore().', 'HTML_QuickForm_Error', true);
  686.             return $error;
  687.         } elseif (!$this->elementExists($nameAfter)) {
  688.             $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  689.             return $error;
  690.         }
  691.         $elementName = $element->getName();
  692.         $targetIdx   = $this->_elementIndex[$nameAfter];
  693.         $duplicate   = false;
  694.         // Like in addElement(), check that it's not an incompatible duplicate
  695.         if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  696.             if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
  697.                 $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  698.                 return $error;
  699.             }
  700.             $duplicate = true;
  701.         }
  702.         // Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
  703.         $elKeys = array_keys($this->_elements);
  704.         for ($i = end($elKeys); $i >= $targetIdx; $i--) {
  705.             if (isset($this->_elements[$i])) {
  706.                 $currentName = $this->_elements[$i]->getName();
  707.                 $this->_elements[$i + 1] =& $this->_elements[$i];
  708.                 if ($this->_elementIndex[$currentName] == $i) {
  709.                     $this->_elementIndex[$currentName] = $i + 1;
  710.                 } else {
  711.                     $dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
  712.                     $this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
  713.                 }
  714.                 unset($this->_elements[$i]);
  715.             }
  716.         }
  717.         // Put the element in place finally
  718.         $this->_elements[$targetIdx] =& $element;
  719.         if (!$duplicate) {
  720.             $this->_elementIndex[$elementName] = $targetIdx;
  721.         } else {
  722.             $this->_duplicateIndex[$elementName][] = $targetIdx;
  723.         }
  724.         $element->onQuickFormEvent('updateValue', null, $this);
  725.         if ($this->_freezeAll) {
  726.             $element->freeze();
  727.         }
  728.         // If not done, the elements will appear in reverse order
  729.         ksort($this->_elements);
  730.         return $element;
  731.     }
  732.  
  733.     // }}}
  734.     // {{{ addGroup()
  735.  
  736.     /**
  737.      * Adds an element group
  738.      * @param    array      $elements       array of elements composing the group
  739.      * @param    string     $name           (optional)group name
  740.      * @param    string     $groupLabel     (optional)group label
  741.      * @param    string     $separator      (optional)string to separate elements
  742.      * @param    string     $appendName     (optional)specify whether the group name should be
  743.      *                                      used in the form element name ex: group[element]
  744.      * @return   HTML_QuickForm_group       reference to a newly added group
  745.      * @since    2.8
  746.      * @access   public
  747.      * @throws   HTML_QuickForm_Error
  748.      */
  749.     function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
  750.     {
  751.         static $anonGroups = 1;
  752.  
  753.         if (0 == strlen($name)) {
  754.             $name       = 'qf_group_' . $anonGroups++;
  755.             $appendName = false;
  756.         }
  757.         $group =& $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
  758.         return $group;
  759.     } // end func addGroup
  760.     
  761.     // }}}
  762.     // {{{ &getElement()
  763.  
  764.     /**
  765.      * Returns a reference to the element
  766.      *
  767.      * @param     string     $element    Element name
  768.      * @since     2.0
  769.      * @access    public
  770.      * @return    HTML_QuickForm_element    reference to element
  771.      * @throws    HTML_QuickForm_Error
  772.      */
  773.     function &getElement($element)
  774.     {
  775.         if (isset($this->_elementIndex[$element])) {
  776.             return $this->_elements[$this->_elementIndex[$element]];
  777.         } else {
  778.             $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
  779.             return $error;
  780.         }
  781.     } // end func getElement
  782.  
  783.     // }}}
  784.     // {{{ &getElementValue()
  785.  
  786.     /**
  787.      * Returns the element's raw value
  788.      * 
  789.      * This returns the value as submitted by the form (not filtered) 
  790.      * or set via setDefaults() or setConstants()
  791.      *
  792.      * @param     string     $element    Element name
  793.      * @since     2.0
  794.      * @access    public
  795.      * @return    mixed     element value
  796.      * @throws    HTML_QuickForm_Error
  797.      */
  798.     function &getElementValue($element)
  799.     {
  800.         if (!isset($this->_elementIndex[$element])) {
  801.             $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  802.             return $error;
  803.         }
  804.         $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
  805.         if (isset($this->_duplicateIndex[$element])) {
  806.             foreach ($this->_duplicateIndex[$element] as $index) {
  807.                 if (null !== ($v = $this->_elements[$index]->getValue())) {
  808.                     if (is_array($value)) {
  809.                         $value[] = $v;
  810.                     } else {
  811.                         $value = (null === $value)? $v: array($value, $v);
  812.                     }
  813.                 }
  814.             }
  815.         }
  816.         return $value;
  817.     } // end func getElementValue
  818.  
  819.     // }}}
  820.     // {{{ getSubmitValue()
  821.  
  822.     /**
  823.      * Returns the elements value after submit and filter
  824.      *
  825.      * @param     string     Element name
  826.      * @since     2.0
  827.      * @access    public
  828.      * @return    mixed     submitted element value or null if not set
  829.      */    
  830.     function getSubmitValue($elementName)
  831.     {
  832.         $value = null;
  833.         if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
  834.             $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
  835.             if (is_array($value) && isset($this->_submitFiles[$elementName])) {
  836.                 foreach ($this->_submitFiles[$elementName] as $k => $v) {
  837.                     $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
  838.                 }
  839.             }
  840.  
  841.         } elseif ('file' == $this->getElementType($elementName)) {
  842.             return $this->getElementValue($elementName);
  843.  
  844.         } elseif (false !== ($pos = strpos($elementName, '['))) {
  845.             $base = str_replace(
  846.                         array('\\', '\''), array('\\\\', '\\\''), 
  847.                         substr($elementName, 0, $pos)
  848.                     );
  849.             $idx  = "['" . str_replace(
  850.                         array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"), 
  851.                         substr($elementName, $pos + 1, -1)
  852.                     ) . "']";
  853.             if (isset($this->_submitValues[$base])) {
  854.                 $value = eval("return (isset(\$this->_submitValues['{$base}']{$idx})) ? \$this->_submitValues['{$base}']{$idx} : null;");
  855.             }
  856.  
  857.             if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
  858.                 $props = array('name', 'type', 'size', 'tmp_name', 'error');
  859.                 $code  = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
  860.                          "    return null;\n" .
  861.                          "} else {\n" .
  862.                          "    \$v = array();\n";
  863.                 foreach ($props as $prop) {
  864.                     $code .= "    \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
  865.                 }
  866.                 $fileValue = eval($code . "    return \$v;\n}\n");
  867.                 if (null !== $fileValue) {
  868.                     $value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
  869.                 }
  870.             }
  871.         }
  872.         
  873.         // This is only supposed to work for groups with appendName = false
  874.         if (null === $value && 'group' == $this->getElementType($elementName)) {
  875.             $group    =& $this->getElement($elementName);
  876.             $elements =& $group->getElements();
  877.             foreach (array_keys($elements) as $key) {
  878.                 $name = $group->getElementName($key);
  879.                 // prevent endless recursion in case of radios and such
  880.                 if ($name != $elementName) {
  881.                     if (null !== ($v = $this->getSubmitValue($name))) {
  882.                         $value[$name] = $v;
  883.                     }
  884.                 }
  885.             }
  886.         }
  887.         return $value;
  888.     } // end func getSubmitValue
  889.  
  890.     // }}}
  891.     // {{{ _reindexFiles()
  892.  
  893.    /**
  894.     * A helper function to change the indexes in $_FILES array
  895.     *
  896.     * @param  mixed   Some value from the $_FILES array
  897.     * @param  string  The key from the $_FILES array that should be appended
  898.     * @return array
  899.     */
  900.     function _reindexFiles($value, $key)
  901.     {
  902.         if (!is_array($value)) {
  903.             return array($key => $value);
  904.         } else {
  905.             $ret = array();
  906.             foreach ($value as $k => $v) {
  907.                 $ret[$k] = $this->_reindexFiles($v, $key);
  908.             }
  909.             return $ret;
  910.         }
  911.     }
  912.  
  913.     // }}}
  914.     // {{{ getElementError()
  915.  
  916.     /**
  917.      * Returns error corresponding to validated element
  918.      *
  919.      * @param     string    $element        Name of form element to check
  920.      * @since     1.0
  921.      * @access    public
  922.      * @return    string    error message corresponding to checked element
  923.      */
  924.     function getElementError($element)
  925.     {
  926.         if (isset($this->_errors[$element])) {
  927.             return $this->_errors[$element];
  928.         }
  929.     } // end func getElementError
  930.     
  931.     // }}}
  932.     // {{{ setElementError()
  933.  
  934.     /**
  935.      * Set error message for a form element
  936.      *
  937.      * @param     string    $element    Name of form element to set error for
  938.      * @param     string    $message    Error message, if empty then removes the current error message
  939.      * @since     1.0       
  940.      * @access    public
  941.      * @return    void
  942.      */
  943.     function setElementError($element, $message = null)
  944.     {
  945.         if (!empty($message)) {
  946.             $this->_errors[$element] = $message;
  947.         } else {
  948.             unset($this->_errors[$element]);
  949.         }
  950.     } // end func setElementError
  951.          
  952.      // }}}
  953.      // {{{ getElementType()
  954.  
  955.      /**
  956.       * Returns the type of the given element
  957.       *
  958.       * @param      string    $element    Name of form element
  959.       * @since      1.1
  960.       * @access     public
  961.       * @return     string    Type of the element, false if the element is not found
  962.       */
  963.      function getElementType($element)
  964.      {
  965.          if (isset($this->_elementIndex[$element])) {
  966.              return $this->_elements[$this->_elementIndex[$element]]->getType();
  967.          }
  968.          return false;
  969.      } // end func getElementType
  970.  
  971.      // }}}
  972.      // {{{ updateElementAttr()
  973.  
  974.     /**
  975.      * Updates Attributes for one or more elements
  976.      *
  977.      * @param      mixed    $elements   Array of element names/objects or string of elements to be updated
  978.      * @param      mixed    $attrs      Array or sting of html attributes
  979.      * @since      2.10
  980.      * @access     public
  981.      * @return     void
  982.      */
  983.     function updateElementAttr($elements, $attrs)
  984.     {
  985.         if (is_string($elements)) {
  986.             $elements = split('[ ]?,[ ]?', $elements);
  987.         }
  988.         foreach (array_keys($elements) as $key) {
  989.             if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
  990.                 $elements[$key]->updateAttributes($attrs);
  991.             } elseif (isset($this->_elementIndex[$elements[$key]])) {
  992.                 $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
  993.                 if (isset($this->_duplicateIndex[$elements[$key]])) {
  994.                     foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
  995.                         $this->_elements[$index]->updateAttributes($attrs);
  996.                     }
  997.                 }
  998.             }
  999.         }
  1000.     } // end func updateElementAttr
  1001.  
  1002.     // }}}
  1003.     // {{{ removeElement()
  1004.  
  1005.     /**
  1006.      * Removes an element
  1007.      *
  1008.      * The method "unlinks" an element from the form, returning the reference
  1009.      * to the element object. If several elements named $elementName exist, 
  1010.      * it removes the first one, leaving the others intact.
  1011.      * 
  1012.      * @param string    $elementName The element name
  1013.      * @param boolean   $removeRules True if rules for this element are to be removed too                     
  1014.      * @access public
  1015.      * @since 2.0
  1016.      * @return HTML_QuickForm_element    a reference to the removed element
  1017.      * @throws HTML_QuickForm_Error
  1018.      */
  1019.     function &removeElement($elementName, $removeRules = true)
  1020.     {
  1021.         if (!isset($this->_elementIndex[$elementName])) {
  1022.             $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
  1023.             return $error;
  1024.         }
  1025.         $el =& $this->_elements[$this->_elementIndex[$elementName]];
  1026.         unset($this->_elements[$this->_elementIndex[$elementName]]);
  1027.         if (empty($this->_duplicateIndex[$elementName])) {
  1028.             unset($this->_elementIndex[$elementName]);
  1029.         } else {
  1030.             $this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
  1031.         }
  1032.         if ($removeRules) {
  1033.             unset($this->_rules[$elementName], $this->_errors[$elementName]);
  1034.         }
  1035.         return $el;
  1036.     } // end func removeElement
  1037.  
  1038.     // }}}
  1039.     // {{{ addRule()
  1040.  
  1041.     /**
  1042.      * Adds a validation rule for the given field
  1043.      *
  1044.      * If the element is in fact a group, it will be considered as a whole.
  1045.      * To validate grouped elements as separated entities, 
  1046.      * use addGroupRule instead of addRule.
  1047.      *
  1048.      * @param    string     $element       Form element name
  1049.      * @param    string     $message       Message to display for invalid data
  1050.      * @param    string     $type          Rule type, use getRegisteredRules() to get types
  1051.      * @param    string     $format        (optional)Required for extra rule data
  1052.      * @param    string     $validation    (optional)Where to perform validation: "server", "client"
  1053.      * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?
  1054.      * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist
  1055.      * @since    1.0
  1056.      * @access   public
  1057.      * @throws   HTML_QuickForm_Error
  1058.      */
  1059.     function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
  1060.     {
  1061.         if (!$force) {
  1062.             if (!is_array($element) && !$this->elementExists($element)) {
  1063.                 return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1064.             } elseif (is_array($element)) {
  1065.                 foreach ($element as $el) {
  1066.                     if (!$this->elementExists($el)) {
  1067.                         return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1068.                     }
  1069.                 }
  1070.             }
  1071.         }
  1072.         if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1073.             return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1074.         } elseif (is_string($newName)) {
  1075.             $type = $newName;
  1076.         }
  1077.         if (is_array($element)) {
  1078.             $dependent = $element;
  1079.             $element   = array_shift($dependent);
  1080.         } else {
  1081.             $dependent = null;
  1082.         }
  1083.         if ($type == 'required' || $type == 'uploadedfile') {
  1084.             $this->_required[] = $element;
  1085.         }
  1086.         if (!isset($this->_rules[$element])) {
  1087.             $this->_rules[$element] = array();
  1088.         }
  1089.         if ($validation == 'client') {
  1090.             $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1091.         }
  1092.         $this->_rules[$element][] = array(
  1093.             'type'        => $type,
  1094.             'format'      => $format,
  1095.             'message'     => $message,
  1096.             'validation'  => $validation,
  1097.             'reset'       => $reset,
  1098.             'dependent'   => $dependent
  1099.         );
  1100.     } // end func addRule
  1101.  
  1102.     // }}}
  1103.     // {{{ addGroupRule()
  1104.  
  1105.     /**
  1106.      * Adds a validation rule for the given group of elements
  1107.      *
  1108.      * Only groups with a name can be assigned a validation rule
  1109.      * Use addGroupRule when you need to validate elements inside the group.
  1110.      * Use addRule if you need to validate the group as a whole. In this case,
  1111.      * the same rule will be applied to all elements in the group.
  1112.      * Use addRule if you need to validate the group against a function.
  1113.      *
  1114.      * @param    string     $group         Form group name
  1115.      * @param    mixed      $arg1          Array for multiple elements or error message string for one element
  1116.      * @param    string     $type          (optional)Rule type use getRegisteredRules() to get types
  1117.      * @param    string     $format        (optional)Required for extra rule data
  1118.      * @param    int        $howmany       (optional)How many valid elements should be in the group
  1119.      * @param    string     $validation    (optional)Where to perform validation: "server", "client"
  1120.      * @param    bool       $reset         Client-side: whether to reset the element's value to its original state if validation failed.
  1121.      * @since    2.5
  1122.      * @access   public
  1123.      * @throws   HTML_QuickForm_Error
  1124.      */
  1125.     function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
  1126.     {
  1127.         if (!$this->elementExists($group)) {
  1128.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1129.         }
  1130.  
  1131.         $groupObj =& $this->getElement($group);
  1132.         if (is_array($arg1)) {
  1133.             $required = 0;
  1134.             foreach ($arg1 as $elementIndex => $rules) {
  1135.                 $elementName = $groupObj->getElementName($elementIndex);
  1136.                 foreach ($rules as $rule) {
  1137.                     $format = (isset($rule[2])) ? $rule[2] : null;
  1138.                     $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
  1139.                     $reset = isset($rule[4]) && $rule[4];
  1140.                     $type = $rule[1];
  1141.                     if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1142.                         return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1143.                     } elseif (is_string($newName)) {
  1144.                         $type = $newName;
  1145.                     }
  1146.  
  1147.                     $this->_rules[$elementName][] = array(
  1148.                                                         'type'        => $type,
  1149.                                                         'format'      => $format, 
  1150.                                                         'message'     => $rule[0],
  1151.                                                         'validation'  => $validation,
  1152.                                                         'reset'       => $reset,
  1153.                                                         'group'       => $group);
  1154.  
  1155.                     if ('required' == $type || 'uploadedfile' == $type) {
  1156.                         $groupObj->_required[] = $elementName;
  1157.                         $this->_required[] = $elementName;
  1158.                         $required++;
  1159.                     }
  1160.                     if ('client' == $validation) {
  1161.                         $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1162.                     }
  1163.                 }
  1164.             }
  1165.             if ($required > 0 && count($groupObj->getElements()) == $required) {
  1166.                 $this->_required[] = $group;
  1167.             }
  1168.         } elseif (is_string($arg1)) {
  1169.             if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1170.                 return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1171.             } elseif (is_string($newName)) {
  1172.                 $type = $newName;
  1173.             }
  1174.  
  1175.             // addGroupRule() should also handle <select multiple>
  1176.             if (is_a($groupObj, 'html_quickform_group')) {
  1177.                 // Radios need to be handled differently when required
  1178.                 if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
  1179.                     $howmany = ($howmany == 0) ? 1 : $howmany;
  1180.                 } else {
  1181.                     $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
  1182.                 }
  1183.             }
  1184.  
  1185.             $this->_rules[$group][] = array('type'       => $type,
  1186.                                             'format'     => $format, 
  1187.                                             'message'    => $arg1,
  1188.                                             'validation' => $validation,
  1189.                                             'howmany'    => $howmany,
  1190.                                             'reset'      => $reset);
  1191.             if ($type == 'required') {
  1192.                 $this->_required[] = $group;
  1193.             }
  1194.             if ($validation == 'client') {
  1195.                 $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1196.             }
  1197.         }
  1198.     } // end func addGroupRule
  1199.  
  1200.     // }}}
  1201.     // {{{ addFormRule()
  1202.  
  1203.    /**
  1204.     * Adds a global validation rule 
  1205.     * 
  1206.     * This should be used when for a rule involving several fields or if
  1207.     * you want to use some completely custom validation for your form.
  1208.     * The rule function/method should return true in case of successful 
  1209.     * validation and array('element name' => 'error') when there were errors.
  1210.     * 
  1211.     * @access   public
  1212.     * @param    mixed   Callback, either function name or array(&$object, 'method')
  1213.     * @throws   HTML_QuickForm_Error
  1214.     */
  1215.     function addFormRule($rule)
  1216.     {
  1217.         if (!is_callable($rule)) {
  1218.             return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
  1219.         }
  1220.         $this->_formRules[] = $rule;
  1221.     }
  1222.     
  1223.     // }}}
  1224.     // {{{ applyFilter()
  1225.  
  1226.     /**
  1227.      * Applies a data filter for the given field(s)
  1228.      *
  1229.      * @param    mixed     $element       Form element name or array of such names
  1230.      * @param    mixed     $filter        Callback, either function name or array(&$object, 'method')
  1231.      * @since    2.0
  1232.      * @access   public
  1233.      * @throws   HTML_QuickForm_Error
  1234.      */
  1235.     function applyFilter($element, $filter)
  1236.     {
  1237.         if (!is_callable($filter)) {
  1238.             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
  1239.         }
  1240.         if ($element == '__ALL__') {
  1241.             $this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
  1242.         } else {
  1243.             if (!is_array($element)) {
  1244.                 $element = array($element);
  1245.             }
  1246.             foreach ($element as $elName) {
  1247.                 $value = $this->getSubmitValue($elName);
  1248.                 if (null !== $value) {
  1249.                     if (false === strpos($elName, '[')) {
  1250.                         $this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
  1251.                     } else {
  1252.                         $idx  = "['" . str_replace(
  1253.                                     array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"), 
  1254.                                     $elName
  1255.                                 ) . "']";
  1256.                         eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
  1257.                     }
  1258.                 }
  1259.             }
  1260.         }
  1261.     } // end func applyFilter
  1262.  
  1263.     // }}}
  1264.     // {{{ _recursiveFilter()
  1265.  
  1266.     /**
  1267.      * Recursively apply a filter function
  1268.      *
  1269.      * @param     string   $filter    filter to apply
  1270.      * @param     mixed    $value     submitted values
  1271.      * @since     2.0
  1272.      * @access    private
  1273.      * @return    cleaned values
  1274.      */
  1275.     function _recursiveFilter($filter, $value)
  1276.     {
  1277.         if (is_array($value)) {
  1278.             $cleanValues = array();
  1279.             foreach ($value as $k => $v) {
  1280.                 $cleanValues[$k] = $this->_recursiveFilter($filter, $v);
  1281.             }
  1282.             return $cleanValues;
  1283.         } else {
  1284.             return call_user_func($filter, $value);
  1285.         }
  1286.     } // end func _recursiveFilter
  1287.  
  1288.     // }}}
  1289.     // {{{ arrayMerge()
  1290.  
  1291.    /**
  1292.     * Merges two arrays
  1293.     *
  1294.     * Merges two array like the PHP function array_merge but recursively.
  1295.     * The main difference is that existing keys will not be renumbered
  1296.     * if they are integers.
  1297.     *
  1298.     * @access   public
  1299.     * @param    array   $a  original array
  1300.     * @param    array   $b  array which will be merged into first one
  1301.     * @return   array   merged array
  1302.     */
  1303.     function arrayMerge($a, $b)
  1304.     {
  1305.         foreach ($b as $k => $v) {
  1306.             if (is_array($v)) {
  1307.                 if (isset($a[$k]) && !is_array($a[$k])) {
  1308.                     $a[$k] = $v;
  1309.                 } else {
  1310.                     if (!isset($a[$k])) {
  1311.                         $a[$k] = array();
  1312.                     }
  1313.                     $a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
  1314.                 }
  1315.             } else {
  1316.                 $a[$k] = $v;
  1317.             }
  1318.         }
  1319.         return $a;
  1320.     } // end func arrayMerge
  1321.  
  1322.     // }}}
  1323.     // {{{ isTypeRegistered()
  1324.  
  1325.     /**
  1326.      * Returns whether or not the form element type is supported
  1327.      *
  1328.      * @param     string   $type     Form element type
  1329.      * @since     1.0
  1330.      * @access    public
  1331.      * @return    boolean
  1332.      */
  1333.     function isTypeRegistered($type)
  1334.     {
  1335.         return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($type)]);
  1336.     } // end func isTypeRegistered
  1337.  
  1338.     // }}}
  1339.     // {{{ getRegisteredTypes()
  1340.  
  1341.     /**
  1342.      * Returns an array of registered element types
  1343.      *
  1344.      * @since     1.0
  1345.      * @access    public
  1346.      * @return    array
  1347.      */
  1348.     function getRegisteredTypes()
  1349.     {
  1350.         return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
  1351.     } // end func getRegisteredTypes
  1352.  
  1353.     // }}}
  1354.     // {{{ isRuleRegistered()
  1355.  
  1356.     /**
  1357.      * Returns whether or not the given rule is supported
  1358.      *
  1359.      * @param     string   $name    Validation rule name
  1360.      * @param     bool     Whether to automatically register subclasses of HTML_QuickForm_Rule
  1361.      * @since     1.0
  1362.      * @access    public
  1363.      * @return    mixed    true if previously registered, false if not, new rule name if auto-registering worked
  1364.      */
  1365.     function isRuleRegistered($name, $autoRegister = false)
  1366.     {
  1367.         if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
  1368.             return true;
  1369.         } elseif (!$autoRegister) {
  1370.             return false;
  1371.         }
  1372.         // automatically register the rule if requested
  1373.         include_once 'HTML/QuickForm/RuleRegistry.php';
  1374.         $ruleName = false;
  1375.         if (is_object($name) && is_a($name, 'html_quickform_rule')) {
  1376.             $ruleName = !empty($name->name)? $name->name: strtolower(get_class($name));
  1377.         } elseif (is_string($name) && class_exists($name)) {
  1378.             $parent = strtolower($name);
  1379.             do {
  1380.                 if ('html_quickform_rule' == strtolower($parent)) {
  1381.                     $ruleName = strtolower($name);
  1382.                     break;
  1383.                 }
  1384.             } while ($parent = get_parent_class($parent));
  1385.         }
  1386.         if ($ruleName) {
  1387.             $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1388.             $registry->registerRule($ruleName, null, $name);
  1389.         }
  1390.         return $ruleName;
  1391.     } // end func isRuleRegistered
  1392.  
  1393.     // }}}
  1394.     // {{{ getRegisteredRules()
  1395.  
  1396.     /**
  1397.      * Returns an array of registered validation rules
  1398.      *
  1399.      * @since     1.0
  1400.      * @access    public
  1401.      * @return    array
  1402.      */
  1403.     function getRegisteredRules()
  1404.     {
  1405.         return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
  1406.     } // end func getRegisteredRules
  1407.  
  1408.     // }}}
  1409.     // {{{ isElementRequired()
  1410.  
  1411.     /**
  1412.      * Returns whether or not the form element is required
  1413.      *
  1414.      * @param     string   $element     Form element name
  1415.      * @since     1.0
  1416.      * @access    public
  1417.      * @return    boolean
  1418.      */
  1419.     function isElementRequired($element)
  1420.     {
  1421.         return in_array($element, $this->_required, true);
  1422.     } // end func isElementRequired
  1423.  
  1424.     // }}}
  1425.     // {{{ isElementFrozen()
  1426.  
  1427.     /**
  1428.      * Returns whether or not the form element is frozen
  1429.      *
  1430.      * @param     string   $element     Form element name
  1431.      * @since     1.0
  1432.      * @access    public
  1433.      * @return    boolean
  1434.      */
  1435.     function isElementFrozen($element)
  1436.     {
  1437.          if (isset($this->_elementIndex[$element])) {
  1438.              return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
  1439.          }
  1440.          return false;
  1441.     } // end func isElementFrozen
  1442.  
  1443.     // }}}
  1444.     // {{{ setJsWarnings()
  1445.  
  1446.     /**
  1447.      * Sets JavaScript warning messages
  1448.      *
  1449.      * @param     string   $pref        Prefix warning
  1450.      * @param     string   $post        Postfix warning
  1451.      * @since     1.1
  1452.      * @access    public
  1453.      * @return    void
  1454.      */
  1455.     function setJsWarnings($pref, $post)
  1456.     {
  1457.         $this->_jsPrefix = $pref;
  1458.         $this->_jsPostfix = $post;
  1459.     } // end func setJsWarnings
  1460.     
  1461.     // }}}
  1462.     // {{{ setRequiredNote()
  1463.  
  1464.     /**
  1465.      * Sets required-note
  1466.      *
  1467.      * @param     string   $note        Message indicating some elements are required
  1468.      * @since     1.1
  1469.      * @access    public
  1470.      * @return    void
  1471.      */
  1472.     function setRequiredNote($note)
  1473.     {
  1474.         $this->_requiredNote = $note;
  1475.     } // end func setRequiredNote
  1476.  
  1477.     // }}}
  1478.     // {{{ getRequiredNote()
  1479.  
  1480.     /**
  1481.      * Returns the required note
  1482.      *
  1483.      * @since     2.0
  1484.      * @access    public
  1485.      * @return    string
  1486.      */
  1487.     function getRequiredNote()
  1488.     {
  1489.         return $this->_requiredNote;
  1490.     } // end func getRequiredNote
  1491.  
  1492.     // }}}
  1493.     // {{{ validate()
  1494.  
  1495.     /**
  1496.      * Performs the server side validation
  1497.      * @access    public
  1498.      * @since     1.0
  1499.      * @return    boolean   true if no error found
  1500.      * @throws    HTML_QuickForm_Error
  1501.      */
  1502.     function validate()
  1503.     {
  1504.         if (count($this->_rules) == 0 && count($this->_formRules) == 0 && 
  1505.             $this->isSubmitted()) {
  1506.             return (0 == count($this->_errors));
  1507.         } elseif (!$this->isSubmitted()) {
  1508.             return false;
  1509.         }
  1510.  
  1511.         include_once('HTML/QuickForm/RuleRegistry.php');
  1512.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1513.  
  1514.         foreach ($this->_rules as $target => $rules) {
  1515.             $submitValue = $this->getSubmitValue($target);
  1516.  
  1517.             foreach ($rules as $rule) {
  1518.                 if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
  1519.                      isset($this->_errors[$target])) {
  1520.                     continue 2;
  1521.                 }
  1522.                 // If element is not required and is empty, we shouldn't validate it
  1523.                 if (!$this->isElementRequired($target)) {
  1524.                     if (!isset($submitValue) || '' == $submitValue) {
  1525.                         continue 2;
  1526.                     // Fix for bug #3501: we shouldn't validate not uploaded files, either.
  1527.                     // Unfortunately, we can't just use $element->isUploadedFile() since
  1528.                     // the element in question can be buried in group. Thus this hack.
  1529.                     // See also bug #12014, we should only consider a file that has
  1530.                     // status UPLOAD_ERR_NO_FILE as not uploaded, in all other cases
  1531.                     // validation should be performed, so that e.g. 'maxfilesize' rule
  1532.                     // will display an error if status is UPLOAD_ERR_INI_SIZE 
  1533.                     // or UPLOAD_ERR_FORM_SIZE
  1534.                     } elseif (is_array($submitValue)) {
  1535.                         if (false === ($pos = strpos($target, '['))) {
  1536.                             $isUpload = !empty($this->_submitFiles[$target]);
  1537.                         } else {
  1538.                             $base = str_replace(
  1539.                                         array('\\', '\''), array('\\\\', '\\\''),
  1540.                                         substr($target, 0, $pos) 
  1541.                                     ); 
  1542.                             $idx  = "['" . str_replace(
  1543.                                         array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"), 
  1544.                                         substr($target, $pos + 1, -1)
  1545.                                     ) . "']";
  1546.                             eval("\$isUpload = isset(\$this->_submitFiles['{$base}']['name']{$idx});");
  1547.                         }
  1548.                         if ($isUpload && (!isset($submitValue['error']) || UPLOAD_ERR_NO_FILE == $submitValue['error'])) {
  1549.                             continue 2;
  1550.                         }
  1551.                     }
  1552.                 }
  1553.                 if (isset($rule['dependent']) && is_array($rule['dependent'])) {
  1554.                     $values = array($submitValue);
  1555.                     foreach ($rule['dependent'] as $elName) {
  1556.                         $values[] = $this->getSubmitValue($elName);
  1557.                     }
  1558.                     $result = $registry->validate($rule['type'], $values, $rule['format'], true);
  1559.                 } elseif (is_array($submitValue) && !isset($rule['howmany'])) {
  1560.                     $result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
  1561.                 } else {
  1562.                     $result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
  1563.                 }
  1564.  
  1565.                 if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
  1566.                     if (isset($rule['group'])) {
  1567.                         $this->_errors[$rule['group']] = $rule['message'];
  1568.                     } else {
  1569.                         $this->_errors[$target] = $rule['message'];
  1570.                     }
  1571.                 }
  1572.             }
  1573.         }
  1574.  
  1575.         // process the global rules now
  1576.         foreach ($this->_formRules as $rule) {
  1577.             if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
  1578.                 if (is_array($res)) {
  1579.                     $this->_errors += $res;
  1580.                 } else {
  1581.                     return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
  1582.                 }
  1583.             }
  1584.         }
  1585.  
  1586.         return (0 == count($this->_errors));
  1587.     } // end func validate
  1588.  
  1589.     // }}}
  1590.     // {{{ freeze()
  1591.  
  1592.     /**
  1593.      * Displays elements without HTML input tags
  1594.      *
  1595.      * @param    mixed   $elementList       array or string of element(s) to be frozen
  1596.      * @since     1.0
  1597.      * @access   public
  1598.      * @throws   HTML_QuickForm_Error
  1599.      */
  1600.     function freeze($elementList=null)
  1601.     {
  1602.         if (!isset($elementList)) {
  1603.             $this->_freezeAll = true;
  1604.             $elementList = array();
  1605.         } else {
  1606.             if (!is_array($elementList)) {
  1607.                 $elementList = preg_split('/[ ]*,[ ]*/', $elementList);
  1608.             }
  1609.             $elementList = array_flip($elementList);
  1610.         }
  1611.  
  1612.         foreach (array_keys($this->_elements) as $key) {
  1613.             $name = $this->_elements[$key]->getName();
  1614.             if ($this->_freezeAll || isset($elementList[$name])) {
  1615.                 $this->_elements[$key]->freeze();
  1616.                 unset($elementList[$name]);
  1617.             }
  1618.         }
  1619.  
  1620.         if (!empty($elementList)) {
  1621.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Nonexistant element(s): '" . implode("', '", array_keys($elementList)) . "' in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true);
  1622.         }
  1623.         return true;
  1624.     } // end func freeze
  1625.         
  1626.     // }}}
  1627.     // {{{ isFrozen()
  1628.  
  1629.     /**
  1630.      * Returns whether or not the whole form is frozen
  1631.      *
  1632.      * @since     3.0
  1633.      * @access    public
  1634.      * @return    boolean
  1635.      */
  1636.     function isFrozen()
  1637.     {
  1638.          return $this->_freezeAll;
  1639.     } // end func isFrozen
  1640.  
  1641.     // }}}
  1642.     // {{{ process()
  1643.  
  1644.     /**
  1645.      * Performs the form data processing
  1646.      *
  1647.      * @param    mixed     $callback        Callback, either function name or array(&$object, 'method')
  1648.      * @param    bool      $mergeFiles      Whether uploaded files should be processed too
  1649.      * @since    1.0
  1650.      * @access   public
  1651.      * @throws   HTML_QuickForm_Error
  1652.      * @return   mixed     Whatever value the $callback function returns
  1653.      */
  1654.     function process($callback, $mergeFiles = true)
  1655.     {
  1656.         if (!is_callable($callback)) {
  1657.             return PEAR::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
  1658.         }
  1659.         $values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
  1660.         return call_user_func($callback, $values);
  1661.     } // end func process
  1662.  
  1663.     // }}}
  1664.     // {{{ accept()
  1665.  
  1666.    /**
  1667.     * Accepts a renderer
  1668.     *
  1669.     * @param object     An HTML_QuickForm_Renderer object
  1670.     * @since 3.0
  1671.     * @access public
  1672.     * @return void
  1673.     */
  1674.     function accept(&$renderer)
  1675.     {
  1676.         $renderer->startForm($this);
  1677.         foreach (array_keys($this->_elements) as $key) {
  1678.             $element =& $this->_elements[$key];
  1679.             $elementName = $element->getName();
  1680.             $required    = ($this->isElementRequired($elementName) && !$element->isFrozen());
  1681.             $error       = $this->getElementError($elementName);
  1682.             $element->accept($renderer, $required, $error);
  1683.         }
  1684.         $renderer->finishForm($this);
  1685.     } // end func accept
  1686.  
  1687.     // }}}
  1688.     // {{{ defaultRenderer()
  1689.  
  1690.    /**
  1691.     * Returns a reference to default renderer object
  1692.     *
  1693.     * @access public
  1694.     * @since 3.0
  1695.     * @return object a default renderer object
  1696.     */
  1697.     function &defaultRenderer()
  1698.     {
  1699.         if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
  1700.             include_once('HTML/QuickForm/Renderer/Default.php');
  1701.             $GLOBALS['_HTML_QuickForm_default_renderer'] =& new HTML_QuickForm_Renderer_Default();
  1702.         }
  1703.         return $GLOBALS['_HTML_QuickForm_default_renderer'];
  1704.     } // end func defaultRenderer
  1705.  
  1706.     // }}}
  1707.     // {{{ toHtml ()
  1708.  
  1709.     /**
  1710.      * Returns an HTML version of the form
  1711.      *
  1712.      * @param string $in_data (optional) Any extra data to insert right
  1713.      *               before form is rendered.  Useful when using templates.
  1714.      *
  1715.      * @return   string     Html version of the form
  1716.      * @since     1.0
  1717.      * @access   public
  1718.      */
  1719.     function toHtml ($in_data = null)
  1720.     {
  1721.         if (!is_null($in_data)) {
  1722.             $this->addElement('html', $in_data);
  1723.         }
  1724.         $renderer =& $this->defaultRenderer();
  1725.         $this->accept($renderer);
  1726.         return $renderer->toHtml();
  1727.     } // end func toHtml
  1728.  
  1729.     // }}}
  1730.     // {{{ getValidationScript()
  1731.  
  1732.     /**
  1733.      * Returns the client side validation script
  1734.      *
  1735.      * @since     2.0
  1736.      * @access    public
  1737.      * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
  1738.      */
  1739.     function getValidationScript()
  1740.     {
  1741.         if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
  1742.             return '';
  1743.         }
  1744.  
  1745.         include_once('HTML/QuickForm/RuleRegistry.php');
  1746.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1747.         $test = array();
  1748.         $js_escape = array(
  1749.             "\r"    => '\r',
  1750.             "\n"    => '\n',
  1751.             "\t"    => '\t',
  1752.             "'"     => "\\'",
  1753.             '"'     => '\"',
  1754.             '\\'    => '\\\\'
  1755.         );
  1756.  
  1757.         foreach ($this->_rules as $elementName => $rules) {
  1758.             foreach ($rules as $rule) {
  1759.                 if ('client' == $rule['validation']) {
  1760.                     unset($element);
  1761.  
  1762.                     $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
  1763.                     $rule['message'] = strtr($rule['message'], $js_escape);
  1764.  
  1765.                     if (isset($rule['group'])) {
  1766.                         $group    =& $this->getElement($rule['group']);
  1767.                         // No JavaScript validation for frozen elements
  1768.                         if ($group->isFrozen()) {
  1769.                             continue 2;
  1770.                         }
  1771.                         $elements =& $group->getElements();
  1772.                         foreach (array_keys($elements) as $key) {
  1773.                             if ($elementName == $group->getElementName($key)) {
  1774.                                 $element =& $elements[$key];
  1775.                                 break;
  1776.                             }
  1777.                         }
  1778.                     } elseif ($dependent) {
  1779.                         $element   =  array();
  1780.                         $element[] =& $this->getElement($elementName);
  1781.                         foreach ($rule['dependent'] as $elName) {
  1782.                             $element[] =& $this->getElement($elName);
  1783.                         }
  1784.                     } else {
  1785.                         $element =& $this->getElement($elementName);
  1786.                     }
  1787.                     // No JavaScript validation for frozen elements
  1788.                     if (is_object($element) && $element->isFrozen()) {
  1789.                         continue 2;
  1790.                     } elseif (is_array($element)) {
  1791.                         foreach (array_keys($element) as $key) {
  1792.                             if ($element[$key]->isFrozen()) {
  1793.                                 continue 3;
  1794.                             }
  1795.                         }
  1796.                     }
  1797.  
  1798.                     $test[] = $registry->getValidationScript($element, $elementName, $rule);
  1799.                 }
  1800.             }
  1801.         }
  1802.         if (count($test) > 0) {
  1803.             return
  1804.                 "\n<script type=\"text/javascript\">\n" .
  1805.                 "//<![CDATA[\n" . 
  1806.                 "function validate_" . $this->_attributes['id'] . "(frm) {\n" .
  1807.                 "  var value = '';\n" .
  1808.                 "  var errFlag = new Array();\n" .
  1809.                 "  var _qfGroups = {};\n" .
  1810.                 "  _qfMsg = '';\n\n" .
  1811.                 join("\n", $test) .
  1812.                 "\n  if (_qfMsg != '') {\n" .
  1813.                 "    _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
  1814.                 "    _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
  1815.                 "    alert(_qfMsg);\n" .
  1816.                 "    return false;\n" .
  1817.                 "  }\n" .
  1818.                 "  return true;\n" .
  1819.                 "}\n" .
  1820.                 "//]]>\n" .
  1821.                 "</script>";
  1822.         }
  1823.         return '';
  1824.     } // end func getValidationScript
  1825.  
  1826.     // }}}
  1827.     // {{{ getSubmitValues()
  1828.  
  1829.     /**
  1830.      * Returns the values submitted by the form
  1831.      *
  1832.      * @since     2.0
  1833.      * @access    public
  1834.      * @param     bool      Whether uploaded files should be returned too
  1835.      * @return    array
  1836.      */
  1837.     function getSubmitValues($mergeFiles = false)
  1838.     {
  1839.         return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
  1840.     } // end func getSubmitValues
  1841.  
  1842.     // }}}
  1843.     // {{{ toArray()
  1844.  
  1845.     /**
  1846.      * Returns the form's contents in an array.
  1847.      *
  1848.      * The description of the array structure is in HTML_QuickForm_Renderer_Array docs
  1849.      * 
  1850.      * @since     2.0
  1851.      * @access    public
  1852.      * @param     bool      Whether to collect hidden elements (passed to the Renderer's constructor)
  1853.      * @return    array of form contents
  1854.      */
  1855.     function toArray($collectHidden = false)
  1856.     {
  1857.         include_once 'HTML/QuickForm/Renderer/Array.php';
  1858.         $renderer =& new HTML_QuickForm_Renderer_Array($collectHidden);
  1859.         $this->accept($renderer);
  1860.         return $renderer->toArray();
  1861.      } // end func toArray
  1862.  
  1863.     // }}}
  1864.     // {{{ exportValue()
  1865.  
  1866.     /**
  1867.      * Returns a 'safe' element's value
  1868.      * 
  1869.      * This method first tries to find a cleaned-up submitted value,
  1870.      * it will return a value set by setValue()/setDefaults()/setConstants()
  1871.      * if submitted value does not exist for the given element.
  1872.      *
  1873.      * @param  string   Name of an element
  1874.      * @access public
  1875.      * @return mixed
  1876.      * @throws HTML_QuickForm_Error
  1877.      */
  1878.     function exportValue($element)
  1879.     {
  1880.         if (!isset($this->_elementIndex[$element])) {
  1881.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  1882.         }
  1883.         $value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
  1884.         if (isset($this->_duplicateIndex[$element])) {
  1885.             foreach ($this->_duplicateIndex[$element] as $index) {
  1886.                 if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
  1887.                     if (is_array($value)) {
  1888.                         $value[] = $v;
  1889.                     } else {
  1890.                         $value = (null === $value)? $v: array($value, $v);
  1891.                     }
  1892.                 }
  1893.             }
  1894.         }
  1895.         return $value;
  1896.     }
  1897.  
  1898.     // }}}
  1899.     // {{{ exportValues()
  1900.  
  1901.     /**
  1902.      * Returns 'safe' elements' values
  1903.      *
  1904.      * Unlike getSubmitValues(), this will return only the values 
  1905.      * corresponding to the elements present in the form.
  1906.      * 
  1907.      * @param   mixed   Array/string of element names, whose values we want. If not set then return all elements.
  1908.      * @access  public
  1909.      * @return  array   An assoc array of elements' values
  1910.      * @throws  HTML_QuickForm_Error
  1911.      */
  1912.     function exportValues($elementList = null)
  1913.     {
  1914.         $values = array();
  1915.         if (null === $elementList) {
  1916.             // iterate over all elements, calling their exportValue() methods
  1917.             foreach (array_keys($this->_elements) as $key) {
  1918.                 $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
  1919.                 if (is_array($value)) {
  1920.                     // This shit throws a bogus warning in PHP 4.3.x
  1921.                     $values = HTML_QuickForm::arrayMerge($values, $value);
  1922.                 }
  1923.             }
  1924.         } else {
  1925.             if (!is_array($elementList)) {
  1926.                 $elementList = array_map('trim', explode(',', $elementList));
  1927.             }
  1928.             foreach ($elementList as $elementName) {
  1929.                 $value = $this->exportValue($elementName);
  1930.                 if (PEAR::isError($value)) {
  1931.                     return $value;
  1932.                 }
  1933.                 $values[$elementName] = $value;
  1934.             }
  1935.         }
  1936.         return $values;
  1937.     }
  1938.  
  1939.     // }}}
  1940.     // {{{ isSubmitted()
  1941.  
  1942.    /**
  1943.     * Tells whether the form was already submitted
  1944.     *
  1945.     * This is useful since the _submitFiles and _submitValues arrays
  1946.     * may be completely empty after the trackSubmit value is removed.
  1947.     *
  1948.     * @access public
  1949.     * @return bool
  1950.     */
  1951.     function isSubmitted()
  1952.     {
  1953.         return $this->_flagSubmitted;
  1954.     }
  1955.  
  1956.  
  1957.     // }}}
  1958.     // {{{ isError()
  1959.  
  1960.     /**
  1961.      * Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
  1962.      *
  1963.      * @access public
  1964.      * @param mixed     result code
  1965.      * @return bool     whether $value is an error
  1966.      * @static
  1967.      */
  1968.     function isError($value)
  1969.     {
  1970.         return (is_object($value) && is_a($value, 'html_quickform_error'));
  1971.     } // end func isError
  1972.  
  1973.     // }}}
  1974.     // {{{ errorMessage()
  1975.  
  1976.     /**
  1977.      * Return a textual error message for an QuickForm error code
  1978.      *
  1979.      * @access  public
  1980.      * @param   int     error code
  1981.      * @return  string  error message
  1982.      * @static
  1983.      */
  1984.     function errorMessage($value)
  1985.     {
  1986.         // make the variable static so that it only has to do the defining on the first call
  1987.         static $errorMessages;
  1988.  
  1989.         // define the varies error messages
  1990.         if (!isset($errorMessages)) {
  1991.             $errorMessages = array(
  1992.                 QUICKFORM_OK                    => 'no error',
  1993.                 QUICKFORM_ERROR                 => 'unknown error',
  1994.                 QUICKFORM_INVALID_RULE          => 'the rule does not exist as a registered rule',
  1995.                 QUICKFORM_NONEXIST_ELEMENT      => 'nonexistent html element',
  1996.                 QUICKFORM_INVALID_FILTER        => 'invalid filter',
  1997.                 QUICKFORM_UNREGISTERED_ELEMENT  => 'unregistered element',
  1998.                 QUICKFORM_INVALID_ELEMENT_NAME  => 'element already exists',
  1999.                 QUICKFORM_INVALID_PROCESS       => 'process callback does not exist',
  2000.                 QUICKFORM_DEPRECATED            => 'method is deprecated',
  2001.                 QUICKFORM_INVALID_DATASOURCE    => 'datasource is not an object'
  2002.             );
  2003.         }
  2004.  
  2005.         // If this is an error object, then grab the corresponding error code
  2006.         if (HTML_QuickForm::isError($value)) {
  2007.             $value = $value->getCode();
  2008.         }
  2009.  
  2010.         // return the textual error message corresponding to the code
  2011.         return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
  2012.     } // end func errorMessage
  2013.  
  2014.     // }}}
  2015. } // end class HTML_QuickForm
  2016.  
  2017. /**
  2018.  * Class for errors thrown by HTML_QuickForm package
  2019.  *
  2020.  * @category    HTML
  2021.  * @package     HTML_QuickForm
  2022.  * @author      Adam Daniel <adaniel1@eesus.jnj.com>
  2023.  * @author      Bertrand Mansion <bmansion@mamasam.com>
  2024.  * @version     Release: 3.2.10
  2025.  */
  2026. class HTML_QuickForm_Error extends PEAR_Error {
  2027.  
  2028.     // {{{ properties
  2029.  
  2030.     /**
  2031.     * Prefix for all error messages
  2032.     * @var string
  2033.     */
  2034.     var $error_message_prefix = 'QuickForm Error: ';
  2035.  
  2036.     // }}}
  2037.     // {{{ constructor
  2038.  
  2039.     /**
  2040.     * Creates a quickform error object, extending the PEAR_Error class
  2041.     *
  2042.     * @param int   $code the error code
  2043.     * @param int   $mode the reaction to the error, either return, die or trigger/callback
  2044.     * @param int   $level intensity of the error (PHP error code)
  2045.     * @param mixed $debuginfo any information that can inform user as to nature of the error
  2046.     */
  2047.     function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
  2048.                          $level = E_USER_NOTICE, $debuginfo = null)
  2049.     {
  2050.         if (is_int($code)) {
  2051.             $this->PEAR_Error(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
  2052.         } else {
  2053.             $this->PEAR_Error("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
  2054.         }
  2055.     }
  2056.  
  2057.     // }}}
  2058. } // end class HTML_QuickForm_Error
  2059. ?>