QuickForm.php 80 KB

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