PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/pear/HTML/QuickForm.php

https://bitbucket.org/ceu/moodle_demo
PHP | 1992 lines | 1145 code | 141 blank | 706 comment | 220 complexity | d3d6bcae53163d135f52471aac8bf518 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Adam Daniel <adaniel1@eesus.jnj.com> |
  17. // | Bertrand Mansion <bmansion@mamasam.com> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: QuickForm.php,v 1.1 2006/09/24 17:04:53 jamiesensei Exp $
  21. require_once('PEAR.php');
  22. require_once('HTML/Common.php');
  23. $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] =
  24. array(
  25. 'group' =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
  26. 'hidden' =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
  27. 'reset' =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
  28. 'checkbox' =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
  29. 'file' =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
  30. 'image' =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
  31. 'password' =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
  32. 'radio' =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
  33. 'button' =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
  34. 'submit' =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
  35. 'select' =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
  36. 'hiddenselect' =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
  37. 'text' =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
  38. 'textarea' =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
  39. 'link' =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
  40. 'advcheckbox' =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
  41. 'date' =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
  42. 'static' =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
  43. 'header' =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
  44. 'html' =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
  45. 'hierselect' =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
  46. 'autocomplete' =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
  47. 'xbutton' =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
  48. );
  49. $GLOBALS['_HTML_QuickForm_registered_rules'] = array(
  50. 'required' => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
  51. 'maxlength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
  52. 'minlength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
  53. 'rangelength' => array('html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'),
  54. 'email' => array('html_quickform_rule_email', 'HTML/QuickForm/Rule/Email.php'),
  55. 'regex' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  56. 'lettersonly' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  57. 'alphanumeric' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  58. 'numeric' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  59. 'nopunctuation' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  60. 'nonzero' => array('html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'),
  61. 'callback' => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
  62. 'compare' => array('html_quickform_rule_compare', 'HTML/QuickForm/Rule/Compare.php')
  63. );
  64. // {{{ error codes
  65. /*
  66. * Error codes for the QuickForm interface, which will be mapped to textual messages
  67. * in the QuickForm::errorMessage() function. If you are to add a new error code, be
  68. * sure to add the textual messages to the QuickForm::errorMessage() function as well
  69. */
  70. define('QUICKFORM_OK', 1);
  71. define('QUICKFORM_ERROR', -1);
  72. define('QUICKFORM_INVALID_RULE', -2);
  73. define('QUICKFORM_NONEXIST_ELEMENT', -3);
  74. define('QUICKFORM_INVALID_FILTER', -4);
  75. define('QUICKFORM_UNREGISTERED_ELEMENT', -5);
  76. define('QUICKFORM_INVALID_ELEMENT_NAME', -6);
  77. define('QUICKFORM_INVALID_PROCESS', -7);
  78. define('QUICKFORM_DEPRECATED', -8);
  79. define('QUICKFORM_INVALID_DATASOURCE', -9);
  80. // }}}
  81. /**
  82. * Create, validate and process HTML forms
  83. *
  84. * @author Adam Daniel <adaniel1@eesus.jnj.com>
  85. * @author Bertrand Mansion <bmansion@mamasam.com>
  86. * @version 2.0
  87. * @since PHP 4.0.3pl1
  88. */
  89. class HTML_QuickForm extends HTML_Common {
  90. // {{{ properties
  91. /**
  92. * Array containing the form fields
  93. * @since 1.0
  94. * @var array
  95. * @access private
  96. */
  97. var $_elements = array();
  98. /**
  99. * Array containing element name to index map
  100. * @since 1.1
  101. * @var array
  102. * @access private
  103. */
  104. var $_elementIndex = array();
  105. /**
  106. * Array containing indexes of duplicate elements
  107. * @since 2.10
  108. * @var array
  109. * @access private
  110. */
  111. var $_duplicateIndex = array();
  112. /**
  113. * Array containing required field IDs
  114. * @since 1.0
  115. * @var array
  116. * @access private
  117. */
  118. var $_required = array();
  119. /**
  120. * Prefix message in javascript alert if error
  121. * @since 1.0
  122. * @var string
  123. * @access public
  124. */
  125. var $_jsPrefix = 'Invalid information entered.';
  126. /**
  127. * Postfix message in javascript alert if error
  128. * @since 1.0
  129. * @var string
  130. * @access public
  131. */
  132. var $_jsPostfix = 'Please correct these fields.';
  133. /**
  134. * Datasource object implementing the informal
  135. * datasource protocol
  136. * @since 3.3
  137. * @var object
  138. * @access private
  139. */
  140. var $_datasource;
  141. /**
  142. * Array of default form values
  143. * @since 2.0
  144. * @var array
  145. * @access private
  146. */
  147. var $_defaultValues = array();
  148. /**
  149. * Array of constant form values
  150. * @since 2.0
  151. * @var array
  152. * @access private
  153. */
  154. var $_constantValues = array();
  155. /**
  156. * Array of submitted form values
  157. * @since 1.0
  158. * @var array
  159. * @access private
  160. */
  161. var $_submitValues = array();
  162. /**
  163. * Array of submitted form files
  164. * @since 1.0
  165. * @var integer
  166. * @access public
  167. */
  168. var $_submitFiles = array();
  169. /**
  170. * Value for maxfilesize hidden element if form contains file input
  171. * @since 1.0
  172. * @var integer
  173. * @access public
  174. */
  175. var $_maxFileSize = 1048576; // 1 Mb = 1048576
  176. /**
  177. * Flag to know if all fields are frozen
  178. * @since 1.0
  179. * @var boolean
  180. * @access private
  181. */
  182. var $_freezeAll = false;
  183. /**
  184. * Array containing the form rules
  185. * @since 1.0
  186. * @var array
  187. * @access private
  188. */
  189. var $_rules = array();
  190. /**
  191. * Form rules, global variety
  192. * @var array
  193. * @access private
  194. */
  195. var $_formRules = array();
  196. /**
  197. * Array containing the validation errors
  198. * @since 1.0
  199. * @var array
  200. * @access private
  201. */
  202. var $_errors = array();
  203. /**
  204. * Note for required fields in the form
  205. * @var string
  206. * @since 1.0
  207. * @access private
  208. */
  209. var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
  210. /**
  211. * Whether the form was submitted
  212. * @var boolean
  213. * @access private
  214. */
  215. var $_flagSubmitted = false;
  216. // }}}
  217. // {{{ constructor
  218. /**
  219. * Class constructor
  220. * @param string $formName Form's name.
  221. * @param string $method (optional)Form's method defaults to 'POST'
  222. * @param string $action (optional)Form's action
  223. * @param string $target (optional)Form's target defaults to '_self'
  224. * @param mixed $attributes (optional)Extra attributes for <form> tag
  225. * @param bool $trackSubmit (optional)Whether to track if the form was submitted by adding a special hidden field
  226. * @access public
  227. */
  228. function HTML_QuickForm($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false)
  229. {
  230. HTML_Common::HTML_Common($attributes);
  231. $method = (strtoupper($method) == 'GET') ? 'get' : 'post';
  232. $action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
  233. $target = empty($target) ? array() : array('target' => $target);
  234. $attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
  235. $this->updateAttributes($attributes);
  236. if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
  237. if (1 == get_magic_quotes_gpc()) {
  238. $this->_submitValues = $this->_recursiveFilter('stripslashes', 'get' == $method? $_GET: $_POST);
  239. foreach ($_FILES as $keyFirst => $valFirst) {
  240. foreach ($valFirst as $keySecond => $valSecond) {
  241. if ('name' == $keySecond) {
  242. $this->_submitFiles[$keyFirst][$keySecond] = $this->_recursiveFilter('stripslashes', $valSecond);
  243. } else {
  244. $this->_submitFiles[$keyFirst][$keySecond] = $valSecond;
  245. }
  246. }
  247. }
  248. } else {
  249. $this->_submitValues = 'get' == $method? $_GET: $_POST;
  250. $this->_submitFiles = $_FILES;
  251. }
  252. $this->_flagSubmitted = count($this->_submitValues) > 0 || count($this->_submitFiles) > 0;
  253. }
  254. if ($trackSubmit) {
  255. unset($this->_submitValues['_qf__' . $formName]);
  256. $this->addElement('hidden', '_qf__' . $formName, null);
  257. }
  258. if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', ini_get('upload_max_filesize'), $matches)) {
  259. // see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
  260. switch (strtoupper($matches['2'])) {
  261. case 'G':
  262. $this->_maxFileSize = $matches['1'] * 1073741824;
  263. break;
  264. case 'M':
  265. $this->_maxFileSize = $matches['1'] * 1048576;
  266. break;
  267. case 'K':
  268. $this->_maxFileSize = $matches['1'] * 1024;
  269. break;
  270. default:
  271. $this->_maxFileSize = $matches['1'];
  272. }
  273. }
  274. } // end constructor
  275. // }}}
  276. // {{{ apiVersion()
  277. /**
  278. * Returns the current API version
  279. *
  280. * @since 1.0
  281. * @access public
  282. * @return float
  283. */
  284. function apiVersion()
  285. {
  286. return 3.2;
  287. } // end func apiVersion
  288. // }}}
  289. // {{{ registerElementType()
  290. /**
  291. * Registers a new element type
  292. *
  293. * @param string $typeName Name of element type
  294. * @param string $include Include path for element type
  295. * @param string $className Element class name
  296. * @since 1.0
  297. * @access public
  298. * @return void
  299. */
  300. function registerElementType($typeName, $include, $className)
  301. {
  302. $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
  303. } // end func registerElementType
  304. // }}}
  305. // {{{ registerRule()
  306. /**
  307. * Registers a new validation rule
  308. *
  309. * @param string $ruleName Name of validation rule
  310. * @param string $type Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
  311. * @param string $data1 Name of function, regular expression or HTML_QuickForm_Rule classname
  312. * @param string $data2 Object parent of above function or HTML_QuickForm_Rule file path
  313. * @since 1.0
  314. * @access public
  315. * @return void
  316. */
  317. function registerRule($ruleName, $type, $data1, $data2 = null)
  318. {
  319. include_once('HTML/QuickForm/RuleRegistry.php');
  320. $registry =& HTML_QuickForm_RuleRegistry::singleton();
  321. $registry->registerRule($ruleName, $type, $data1, $data2);
  322. } // end func registerRule
  323. // }}}
  324. // {{{ elementExists()
  325. /**
  326. * Returns true if element is in the form
  327. *
  328. * @param string $element form name of element to check
  329. * @since 1.0
  330. * @access public
  331. * @return boolean
  332. */
  333. function elementExists($element=null)
  334. {
  335. return isset($this->_elementIndex[$element]);
  336. } // end func elementExists
  337. // }}}
  338. // {{{ setDatasource()
  339. /**
  340. * Sets a datasource object for this form object
  341. *
  342. * Datasource default and constant values will feed the QuickForm object if
  343. * the datasource implements defaultValues() and constantValues() methods.
  344. *
  345. * @param object $datasource datasource object implementing the informal datasource protocol
  346. * @param mixed $defaultsFilter string or array of filter(s) to apply to default values
  347. * @param mixed $constantsFilter string or array of filter(s) to apply to constants values
  348. * @since 3.3
  349. * @access public
  350. * @return void
  351. */
  352. function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
  353. {
  354. if (is_object($datasource)) {
  355. $this->_datasource =& $datasource;
  356. if (is_callable(array($datasource, 'defaultValues'))) {
  357. $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
  358. }
  359. if (is_callable(array($datasource, 'constantValues'))) {
  360. $this->setConstants($datasource->constantValues($this), $constantsFilter);
  361. }
  362. } else {
  363. return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
  364. }
  365. } // end func setDatasource
  366. // }}}
  367. // {{{ setDefaults()
  368. /**
  369. * Initializes default form values
  370. *
  371. * @param array $defaultValues values used to fill the form
  372. * @param mixed $filter (optional) filter(s) to apply to all default values
  373. * @since 1.0
  374. * @access public
  375. * @return void
  376. */
  377. function setDefaults($defaultValues = null, $filter = null)
  378. {
  379. if (is_array($defaultValues)) {
  380. if (isset($filter)) {
  381. if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  382. foreach ($filter as $val) {
  383. if (!is_callable($val)) {
  384. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  385. } else {
  386. $defaultValues = $this->_recursiveFilter($val, $defaultValues);
  387. }
  388. }
  389. } elseif (!is_callable($filter)) {
  390. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  391. } else {
  392. $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
  393. }
  394. }
  395. $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
  396. foreach (array_keys($this->_elements) as $key) {
  397. $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  398. }
  399. }
  400. } // end func setDefaults
  401. // }}}
  402. // {{{ setConstants()
  403. /**
  404. * Initializes constant form values.
  405. * These values won't get overridden by POST or GET vars
  406. *
  407. * @param array $constantValues values used to fill the form
  408. * @param mixed $filter (optional) filter(s) to apply to all default values
  409. *
  410. * @since 2.0
  411. * @access public
  412. * @return void
  413. */
  414. function setConstants($constantValues = null, $filter = null)
  415. {
  416. if (is_array($constantValues)) {
  417. if (isset($filter)) {
  418. if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  419. foreach ($filter as $val) {
  420. if (!is_callable($val)) {
  421. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  422. } else {
  423. $constantValues = $this->_recursiveFilter($val, $constantValues);
  424. }
  425. }
  426. } elseif (!is_callable($filter)) {
  427. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  428. } else {
  429. $constantValues = $this->_recursiveFilter($filter, $constantValues);
  430. }
  431. }
  432. $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
  433. foreach (array_keys($this->_elements) as $key) {
  434. $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  435. }
  436. }
  437. } // end func setConstants
  438. // }}}
  439. // {{{ setMaxFileSize()
  440. /**
  441. * Sets the value of MAX_FILE_SIZE hidden element
  442. *
  443. * @param int $bytes Size in bytes
  444. * @since 3.0
  445. * @access public
  446. * @return void
  447. */
  448. function setMaxFileSize($bytes = 0)
  449. {
  450. if ($bytes > 0) {
  451. $this->_maxFileSize = $bytes;
  452. }
  453. if (!$this->elementExists('MAX_FILE_SIZE')) {
  454. $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
  455. } else {
  456. $el =& $this->getElement('MAX_FILE_SIZE');
  457. $el->updateAttributes(array('value' => $this->_maxFileSize));
  458. }
  459. } // end func setMaxFileSize
  460. // }}}
  461. // {{{ getMaxFileSize()
  462. /**
  463. * Returns the value of MAX_FILE_SIZE hidden element
  464. *
  465. * @since 3.0
  466. * @access public
  467. * @return int max file size in bytes
  468. */
  469. function getMaxFileSize()
  470. {
  471. return $this->_maxFileSize;
  472. } // end func getMaxFileSize
  473. // }}}
  474. // {{{ &createElement()
  475. /**
  476. * Creates a new form element of the given type.
  477. *
  478. * This method accepts variable number of parameters, their
  479. * meaning and count depending on $elementType
  480. *
  481. * @param string $elementType type of element to add (text, textarea, file...)
  482. * @since 1.0
  483. * @access public
  484. * @return object extended class of HTML_element
  485. * @throws HTML_QuickForm_Error
  486. */
  487. function &createElement($elementType)
  488. {
  489. $args = func_get_args();
  490. $element =& HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1));
  491. return $element;
  492. } // end func createElement
  493. // }}}
  494. // {{{ _loadElement()
  495. /**
  496. * Returns a form element of the given type
  497. *
  498. * @param string $event event to send to newly created element ('createElement' or 'addElement')
  499. * @param string $type element type
  500. * @param array $args arguments for event
  501. * @since 2.0
  502. * @access private
  503. * @return object a new element
  504. * @throws HTML_QuickForm_Error
  505. */
  506. function &_loadElement($event, $type, $args)
  507. {
  508. $type = strtolower($type);
  509. if (!HTML_QuickForm::isTypeRegistered($type)) {
  510. $error = PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
  511. return $error;
  512. }
  513. $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
  514. $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
  515. include_once($includeFile);
  516. $elementObject =& new $className();
  517. for ($i = 0; $i < 5; $i++) {
  518. if (!isset($args[$i])) {
  519. $args[$i] = null;
  520. }
  521. }
  522. $err = $elementObject->onQuickFormEvent($event, $args, $this);
  523. if ($err !== true) {
  524. return $err;
  525. }
  526. return $elementObject;
  527. } // end func _loadElement
  528. // }}}
  529. // {{{ addElement()
  530. /**
  531. * Adds an element into the form
  532. *
  533. * If $element is a string representing element type, then this
  534. * method accepts variable number of parameters, their meaning
  535. * and count depending on $element
  536. *
  537. * @param mixed $element element object or type of element to add (text, textarea, file...)
  538. * @since 1.0
  539. * @return object reference to element
  540. * @access public
  541. * @throws HTML_QuickForm_Error
  542. */
  543. function &addElement($element)
  544. {
  545. if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
  546. $elementObject = &$element;
  547. $elementObject->onQuickFormEvent('updateValue', null, $this);
  548. } else {
  549. $args = func_get_args();
  550. $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1));
  551. if (PEAR::isError($elementObject)) {
  552. return $elementObject;
  553. }
  554. }
  555. $elementName = $elementObject->getName();
  556. // Add the element if it is not an incompatible duplicate
  557. if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  558. if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
  559. $elementObject->getType()) {
  560. $this->_elements[] =& $elementObject;
  561. $elKeys = array_keys($this->_elements);
  562. $this->_duplicateIndex[$elementName][] = end($elKeys);
  563. } else {
  564. $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
  565. return $error;
  566. }
  567. } else {
  568. $this->_elements[] =& $elementObject;
  569. $elKeys = array_keys($this->_elements);
  570. $this->_elementIndex[$elementName] = end($elKeys);
  571. }
  572. if ($this->_freezeAll) {
  573. $elementObject->freeze();
  574. }
  575. return $elementObject;
  576. } // end func addElement
  577. // }}}
  578. // {{{ insertElementBefore()
  579. /**
  580. * Inserts a new element right before the other element
  581. *
  582. * Warning: it is not possible to check whether the $element is already
  583. * added to the form, therefore if you want to move the existing form
  584. * element to a new position, you'll have to use removeElement():
  585. * $form->insertElementBefore($form->removeElement('foo', false), 'bar');
  586. *
  587. * @access public
  588. * @since 3.2.4
  589. * @param object HTML_QuickForm_element Element to insert
  590. * @param string Name of the element before which the new one is inserted
  591. * @return object HTML_QuickForm_element reference to inserted element
  592. * @throws HTML_QuickForm_Error
  593. */
  594. function &insertElementBefore(&$element, $nameAfter)
  595. {
  596. if (!empty($this->_duplicateIndex[$nameAfter])) {
  597. $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);
  598. return $error;
  599. } elseif (!$this->elementExists($nameAfter)) {
  600. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  601. return $error;
  602. }
  603. $elementName = $element->getName();
  604. $targetIdx = $this->_elementIndex[$nameAfter];
  605. $duplicate = false;
  606. // Like in addElement(), check that it's not an incompatible duplicate
  607. if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  608. if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
  609. $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  610. return $error;
  611. }
  612. $duplicate = true;
  613. }
  614. // Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
  615. $elKeys = array_keys($this->_elements);
  616. for ($i = end($elKeys); $i >= $targetIdx; $i--) {
  617. if (isset($this->_elements[$i])) {
  618. $currentName = $this->_elements[$i]->getName();
  619. $this->_elements[$i + 1] =& $this->_elements[$i];
  620. if ($this->_elementIndex[$currentName] == $i) {
  621. $this->_elementIndex[$currentName] = $i + 1;
  622. } else {
  623. $dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
  624. $this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
  625. }
  626. unset($this->_elements[$i]);
  627. }
  628. }
  629. // Put the element in place finally
  630. $this->_elements[$targetIdx] =& $element;
  631. if (!$duplicate) {
  632. $this->_elementIndex[$elementName] = $targetIdx;
  633. } else {
  634. $this->_duplicateIndex[$elementName][] = $targetIdx;
  635. }
  636. $element->onQuickFormEvent('updateValue', null, $this);
  637. if ($this->_freezeAll) {
  638. $element->freeze();
  639. }
  640. // If not done, the elements will appear in reverse order
  641. ksort($this->_elements);
  642. return $element;
  643. }
  644. // }}}
  645. // {{{ addGroup()
  646. /**
  647. * Adds an element group
  648. * @param array $elements array of elements composing the group
  649. * @param string $name (optional)group name
  650. * @param string $groupLabel (optional)group label
  651. * @param string $separator (optional)string to separate elements
  652. * @param string $appendName (optional)specify whether the group name should be
  653. * used in the form element name ex: group[element]
  654. * @return object reference to added group of elements
  655. * @since 2.8
  656. * @access public
  657. * @throws PEAR_Error
  658. */
  659. function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
  660. {
  661. static $anonGroups = 1;
  662. if (0 == strlen($name)) {
  663. $name = 'qf_group_' . $anonGroups++;
  664. $appendName = false;
  665. }
  666. $group =& $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
  667. return $group;
  668. } // end func addGroup
  669. // }}}
  670. // {{{ &getElement()
  671. /**
  672. * Returns a reference to the element
  673. *
  674. * @param string $element Element name
  675. * @since 2.0
  676. * @access public
  677. * @return object reference to element
  678. * @throws HTML_QuickForm_Error
  679. */
  680. function &getElement($element)
  681. {
  682. if (isset($this->_elementIndex[$element])) {
  683. return $this->_elements[$this->_elementIndex[$element]];
  684. } else {
  685. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
  686. return $error;
  687. }
  688. } // end func getElement
  689. // }}}
  690. // {{{ &getElementValue()
  691. /**
  692. * Returns the element's raw value
  693. *
  694. * This returns the value as submitted by the form (not filtered)
  695. * or set via setDefaults() or setConstants()
  696. *
  697. * @param string $element Element name
  698. * @since 2.0
  699. * @access public
  700. * @return mixed element value
  701. * @throws HTML_QuickForm_Error
  702. */
  703. function &getElementValue($element)
  704. {
  705. if (!isset($this->_elementIndex[$element])) {
  706. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  707. return $error;
  708. }
  709. $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
  710. if (isset($this->_duplicateIndex[$element])) {
  711. foreach ($this->_duplicateIndex[$element] as $index) {
  712. if (null !== ($v = $this->_elements[$index]->getValue())) {
  713. if (is_array($value)) {
  714. $value[] = $v;
  715. } else {
  716. $value = (null === $value)? $v: array($value, $v);
  717. }
  718. }
  719. }
  720. }
  721. return $value;
  722. } // end func getElementValue
  723. // }}}
  724. // {{{ getSubmitValue()
  725. /**
  726. * Returns the elements value after submit and filter
  727. *
  728. * @param string Element name
  729. * @since 2.0
  730. * @access public
  731. * @return mixed submitted element value or null if not set
  732. */
  733. function getSubmitValue($elementName)
  734. {
  735. $value = null;
  736. if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
  737. $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
  738. if (is_array($value) && isset($this->_submitFiles[$elementName])) {
  739. foreach ($this->_submitFiles[$elementName] as $k => $v) {
  740. $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
  741. }
  742. }
  743. } elseif ('file' == $this->getElementType($elementName)) {
  744. return $this->getElementValue($elementName);
  745. } elseif (false !== ($pos = strpos($elementName, '['))) {
  746. $base = substr($elementName, 0, $pos);
  747. $idx = "['" . str_replace(array(']', '['), array('', "']['"), substr($elementName, $pos + 1, -1)) . "']";
  748. if (isset($this->_submitValues[$base])) {
  749. $value = eval("return (isset(\$this->_submitValues['{$base}']{$idx})) ? \$this->_submitValues['{$base}']{$idx} : null;");
  750. }
  751. if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
  752. $props = array('name', 'type', 'size', 'tmp_name', 'error');
  753. $code = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
  754. " return null;\n" .
  755. "} else {\n" .
  756. " \$v = array();\n";
  757. foreach ($props as $prop) {
  758. $code .= " \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
  759. }
  760. $fileValue = eval($code . " return \$v;\n}\n");
  761. if (null !== $fileValue) {
  762. $value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
  763. }
  764. }
  765. }
  766. // This is only supposed to work for groups with appendName = false
  767. if (null === $value && 'group' == $this->getElementType($elementName)) {
  768. $group =& $this->getElement($elementName);
  769. $elements =& $group->getElements();
  770. foreach (array_keys($elements) as $key) {
  771. $name = $group->getElementName($key);
  772. // prevent endless recursion in case of radios and such
  773. if ($name != $elementName) {
  774. if (null !== ($v = $this->getSubmitValue($name))) {
  775. $value[$name] = $v;
  776. }
  777. }
  778. }
  779. }
  780. return $value;
  781. } // end func getSubmitValue
  782. // }}}
  783. // {{{ _reindexFiles()
  784. /**
  785. * A helper function to change the indexes in $_FILES array
  786. *
  787. * @param mixed Some value from the $_FILES array
  788. * @param string The key from the $_FILES array that should be appended
  789. * @return array
  790. */
  791. function _reindexFiles($value, $key)
  792. {
  793. if (!is_array($value)) {
  794. return array($key => $value);
  795. } else {
  796. $ret = array();
  797. foreach ($value as $k => $v) {
  798. $ret[$k] = $this->_reindexFiles($v, $key);
  799. }
  800. return $ret;
  801. }
  802. }
  803. // }}}
  804. // {{{ getElementError()
  805. /**
  806. * Returns error corresponding to validated element
  807. *
  808. * @param string $element Name of form element to check
  809. * @since 1.0
  810. * @access public
  811. * @return string error message corresponding to checked element
  812. */
  813. function getElementError($element)
  814. {
  815. if (isset($this->_errors[$element])) {
  816. return $this->_errors[$element];
  817. }
  818. } // end func getElementError
  819. // }}}
  820. // {{{ setElementError()
  821. /**
  822. * Set error message for a form element
  823. *
  824. * @param string $element Name of form element to set error for
  825. * @param string $message Error message, if empty then removes the current error message
  826. * @since 1.0
  827. * @access public
  828. * @return void
  829. */
  830. function setElementError($element, $message = null)
  831. {
  832. if (!empty($message)) {
  833. $this->_errors[$element] = $message;
  834. } else {
  835. unset($this->_errors[$element]);
  836. }
  837. } // end func setElementError
  838. // }}}
  839. // {{{ getElementType()
  840. /**
  841. * Returns the type of the given element
  842. *
  843. * @param string $element Name of form element
  844. * @since 1.1
  845. * @access public
  846. * @return string Type of the element, false if the element is not found
  847. */
  848. function getElementType($element)
  849. {
  850. if (isset($this->_elementIndex[$element])) {
  851. return $this->_elements[$this->_elementIndex[$element]]->getType();
  852. }
  853. return false;
  854. } // end func getElementType
  855. // }}}
  856. // {{{ updateElementAttr()
  857. /**
  858. * Updates Attributes for one or more elements
  859. *
  860. * @param mixed $elements Array of element names/objects or string of elements to be updated
  861. * @param mixed $attrs Array or sting of html attributes
  862. * @since 2.10
  863. * @access public
  864. * @return void
  865. */
  866. function updateElementAttr($elements, $attrs)
  867. {
  868. if (is_string($elements)) {
  869. $elements = split('[ ]?,[ ]?', $elements);
  870. }
  871. foreach (array_keys($elements) as $key) {
  872. if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
  873. $elements[$key]->updateAttributes($attrs);
  874. } elseif (isset($this->_elementIndex[$elements[$key]])) {
  875. $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
  876. if (isset($this->_duplicateIndex[$elements[$key]])) {
  877. foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
  878. $this->_elements[$index]->updateAttributes($attrs);
  879. }
  880. }
  881. }
  882. }
  883. } // end func updateElementAttr
  884. // }}}
  885. // {{{ removeElement()
  886. /**
  887. * Removes an element
  888. *
  889. * The method "unlinks" an element from the form, returning the reference
  890. * to the element object. If several elements named $elementName exist,
  891. * it removes the first one, leaving the others intact.
  892. *
  893. * @param string $elementName The element name
  894. * @param boolean $removeRules True if rules for this element are to be removed too
  895. * @access public
  896. * @since 2.0
  897. * @return object HTML_QuickForm_element a reference to the removed element
  898. * @throws HTML_QuickForm_Error
  899. */
  900. function &removeElement($elementName, $removeRules = true)
  901. {
  902. if (!isset($this->_elementIndex[$elementName])) {
  903. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
  904. return $error;
  905. }
  906. $el =& $this->_elements[$this->_elementIndex[$elementName]];
  907. unset($this->_elements[$this->_elementIndex[$elementName]]);
  908. if (empty($this->_duplicateIndex[$elementName])) {
  909. unset($this->_elementIndex[$elementName]);
  910. } else {
  911. $this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
  912. }
  913. if ($removeRules) {
  914. unset($this->_rules[$elementName], $this->_errors[$elementName]);
  915. }
  916. return $el;
  917. } // end func removeElement
  918. // }}}
  919. // {{{ addRule()
  920. /**
  921. * Adds a validation rule for the given field
  922. *
  923. * If the element is in fact a group, it will be considered as a whole.
  924. * To validate grouped elements as separated entities,
  925. * use addGroupRule instead of addRule.
  926. *
  927. * @param string $element Form element name
  928. * @param string $message Message to display for invalid data
  929. * @param string $type Rule type, use getRegisteredRules() to get types
  930. * @param string $format (optional)Required for extra rule data
  931. * @param string $validation (optional)Where to perform validation: "server", "client"
  932. * @param boolean $reset Client-side validation: reset the form element to its original value if there is an error?
  933. * @param boolean $force Force the rule to be applied, even if the target form element does not exist
  934. * @since 1.0
  935. * @access public
  936. * @throws HTML_QuickForm_Error
  937. */
  938. function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
  939. {
  940. if (!$force) {
  941. if (!is_array($element) && !$this->elementExists($element)) {
  942. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  943. } elseif (is_array($element)) {
  944. foreach ($element as $el) {
  945. if (!$this->elementExists($el)) {
  946. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  947. }
  948. }
  949. }
  950. }
  951. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  952. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  953. } elseif (is_string($newName)) {
  954. $type = $newName;
  955. }
  956. if (is_array($element)) {
  957. $dependent = $element;
  958. $element = array_shift($dependent);
  959. } else {
  960. $dependent = null;
  961. }
  962. if ($type == 'required' || $type == 'uploadedfile') {
  963. $this->_required[] = $element;
  964. }
  965. if (!isset($this->_rules[$element])) {
  966. $this->_rules[$element] = array();
  967. }
  968. if ($validation == 'client') {
  969. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  970. }
  971. $this->_rules[$element][] = array(
  972. 'type' => $type,
  973. 'format' => $format,
  974. 'message' => $message,
  975. 'validation' => $validation,
  976. 'reset' => $reset,
  977. 'dependent' => $dependent
  978. );
  979. } // end func addRule
  980. // }}}
  981. // {{{ addGroupRule()
  982. /**
  983. * Adds a validation rule for the given group of elements
  984. *
  985. * Only groups with a name can be assigned a validation rule
  986. * Use addGroupRule when you need to validate elements inside the group.
  987. * Use addRule if you need to validate the group as a whole. In this case,
  988. * the same rule will be applied to all elements in the group.
  989. * Use addRule if you need to validate the group against a function.
  990. *
  991. * @param string $group Form group name
  992. * @param mixed $arg1 Array for multiple elements or error message string for one element
  993. * @param string $type (optional)Rule type use getRegisteredRules() to get types
  994. * @param string $format (optional)Required for extra rule data
  995. * @param int $howmany (optional)How many valid elements should be in the group
  996. * @param string $validation (optional)Where to perform validation: "server", "client"
  997. * @param bool $reset Client-side: whether to reset the element's value to its original state if validation failed.
  998. * @since 2.5
  999. * @access public
  1000. * @throws HTML_QuickForm_Error
  1001. */
  1002. function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
  1003. {
  1004. if (!$this->elementExists($group)) {
  1005. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1006. }
  1007. $groupObj =& $this->getElement($group);
  1008. if (is_array($arg1)) {
  1009. $required = 0;
  1010. foreach ($arg1 as $elementIndex => $rules) {
  1011. $elementName = $groupObj->getElementName($elementIndex);
  1012. foreach ($rules as $rule) {
  1013. $format = (isset($rule[2])) ? $rule[2] : null;
  1014. $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
  1015. $reset = isset($rule[4]) && $rule[4];
  1016. $type = $rule[1];
  1017. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1018. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1019. } elseif (is_string($newName)) {
  1020. $type = $newName;
  1021. }
  1022. $this->_rules[$elementName][] = array(
  1023. 'type' => $type,
  1024. 'format' => $format,
  1025. 'message' => $rule[0],
  1026. 'validation' => $validation,
  1027. 'reset' => $reset,
  1028. 'group' => $group);
  1029. if ('required' == $type || 'uploadedfile' == $type) {
  1030. $groupObj->_required[] = $elementName;
  1031. $this->_required[] = $elementName;
  1032. $required++;
  1033. }
  1034. if ('client' == $validation) {
  1035. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1036. }
  1037. }
  1038. }
  1039. if ($required > 0 && count($groupObj->getElements()) == $required) {
  1040. $this->_required[] = $group;
  1041. }
  1042. } elseif (is_string($arg1)) {
  1043. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1044. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1045. } elseif (is_string($newName)) {
  1046. $type = $newName;
  1047. }
  1048. // addGroupRule() should also handle <select multiple>
  1049. if (is_a($groupObj, 'html_quickform_group')) {
  1050. // Radios need to be handled differently when required
  1051. if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
  1052. $howmany = ($howmany == 0) ? 1 : $howmany;
  1053. } else {
  1054. $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
  1055. }
  1056. }
  1057. $this->_rules[$group][] = array('type' => $type,
  1058. 'format' => $format,
  1059. 'message' => $arg1,
  1060. 'validation' => $validation,
  1061. 'howmany' => $howmany,
  1062. 'reset' => $reset);
  1063. if ($type == 'required') {
  1064. $this->_required[] = $group;
  1065. }
  1066. if ($validation == 'client') {
  1067. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1068. }
  1069. }
  1070. } // end func addGroupRule
  1071. // }}}
  1072. // {{{ addFormRule()
  1073. /**
  1074. * Adds a global validation rule
  1075. *
  1076. * This should be used when for a rule involving several fields or if
  1077. * you want to use some completely custom validation for your form.
  1078. * The rule function/method should return true in case of successful
  1079. * validation and array('element name' => 'error') when there were errors.
  1080. *
  1081. * @access public
  1082. * @param mixed Callback, either function name or array(&$object, 'method')
  1083. * @throws HTML_QuickForm_Error
  1084. */
  1085. function addFormRule($rule)
  1086. {
  1087. if (!is_callable($rule)) {
  1088. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
  1089. }
  1090. $this->_formRules[] = $rule;
  1091. }
  1092. // }}}
  1093. // {{{ applyFilter()
  1094. /**
  1095. * Applies a data filter for the given field(s)
  1096. *
  1097. * @param mix…

Large files files are truncated, but you can click here to view the full file