QuickForm.php 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143
  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. static function registerRule($ruleName, $type, $data1, $data2 = null)
  384. {
  385. $registry =& HTML_QuickForm_RuleRegistry::singleton();
  386. $registry->registerRule($ruleName, $type, $data1, $data2);
  387. } // end func registerRule
  388. // }}}
  389. // {{{ elementExists()
  390. /**
  391. * Returns true if element is in the form
  392. *
  393. * @param string $element form name of element to check
  394. * @since 1.0
  395. * @access public
  396. * @return boolean
  397. */
  398. function elementExists($element=null)
  399. {
  400. return isset($this->_elementIndex[$element]);
  401. } // end func elementExists
  402. // }}}
  403. // {{{ setDatasource()
  404. /**
  405. * Sets a datasource object for this form object
  406. *
  407. * Datasource default and constant values will feed the QuickForm object if
  408. * the datasource implements defaultValues() and constantValues() methods.
  409. *
  410. * @param object $datasource datasource object implementing the informal datasource protocol
  411. * @param mixed $defaultsFilter string or array of filter(s) to apply to default values
  412. * @param mixed $constantsFilter string or array of filter(s) to apply to constants values
  413. * @since 3.3
  414. * @access public
  415. * @return void
  416. * @throws HTML_QuickForm_Error
  417. */
  418. function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
  419. {
  420. if (is_object($datasource)) {
  421. $this->_datasource =& $datasource;
  422. if (is_callable(array($datasource, 'defaultValues'))) {
  423. $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
  424. }
  425. if (is_callable(array($datasource, 'constantValues'))) {
  426. $this->setConstants($datasource->constantValues($this), $constantsFilter);
  427. }
  428. } else {
  429. return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
  430. }
  431. } // end func setDatasource
  432. // }}}
  433. // {{{ setDefaults()
  434. /**
  435. * Initializes default form values
  436. *
  437. * @param array $defaultValues values used to fill the form
  438. * @param mixed $filter (optional) filter(s) to apply to all default values
  439. * @since 1.0
  440. * @access public
  441. * @return void
  442. * @throws HTML_QuickForm_Error
  443. */
  444. function setDefaults($defaultValues = null, $filter = null)
  445. {
  446. if (is_array($defaultValues)) {
  447. if (isset($filter)) {
  448. if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  449. foreach ($filter as $val) {
  450. if (!is_callable($val)) {
  451. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  452. } else {
  453. $defaultValues = $this->_recursiveFilter($val, $defaultValues);
  454. }
  455. }
  456. } elseif (!is_callable($filter)) {
  457. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  458. } else {
  459. $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
  460. }
  461. }
  462. $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
  463. foreach (array_keys($this->_elements) as $key) {
  464. $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  465. }
  466. }
  467. } // end func setDefaults
  468. // }}}
  469. // {{{ setConstants()
  470. /**
  471. * Initializes constant form values.
  472. * These values won't get overridden by POST or GET vars
  473. *
  474. * @param array $constantValues values used to fill the form
  475. * @param mixed $filter (optional) filter(s) to apply to all default values
  476. *
  477. * @since 2.0
  478. * @access public
  479. * @return void
  480. * @throws HTML_QuickForm_Error
  481. */
  482. function setConstants($constantValues = null, $filter = null)
  483. {
  484. if (is_array($constantValues)) {
  485. if (isset($filter)) {
  486. if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  487. foreach ($filter as $val) {
  488. if (!is_callable($val)) {
  489. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  490. } else {
  491. $constantValues = $this->_recursiveFilter($val, $constantValues);
  492. }
  493. }
  494. } elseif (!is_callable($filter)) {
  495. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  496. } else {
  497. $constantValues = $this->_recursiveFilter($filter, $constantValues);
  498. }
  499. }
  500. $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
  501. foreach (array_keys($this->_elements) as $key) {
  502. $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  503. }
  504. }
  505. } // end func setConstants
  506. // }}}
  507. // {{{ setMaxFileSize()
  508. /**
  509. * Sets the value of MAX_FILE_SIZE hidden element
  510. *
  511. * @param int $bytes Size in bytes
  512. * @since 3.0
  513. * @access public
  514. * @return void
  515. */
  516. function setMaxFileSize($bytes = 0)
  517. {
  518. if ($bytes > 0) {
  519. $this->_maxFileSize = $bytes;
  520. }
  521. if (!$this->elementExists('MAX_FILE_SIZE')) {
  522. $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
  523. } else {
  524. $el =& $this->getElement('MAX_FILE_SIZE');
  525. $el->updateAttributes(array('value' => $this->_maxFileSize));
  526. }
  527. } // end func setMaxFileSize
  528. // }}}
  529. // {{{ getMaxFileSize()
  530. /**
  531. * Returns the value of MAX_FILE_SIZE hidden element
  532. *
  533. * @since 3.0
  534. * @access public
  535. * @return int max file size in bytes
  536. */
  537. function getMaxFileSize()
  538. {
  539. return $this->_maxFileSize;
  540. } // end func getMaxFileSize
  541. // }}}
  542. // {{{ &createElement()
  543. /**
  544. * Creates a new form element of the given type.
  545. *
  546. * This method accepts variable number of parameters, their
  547. * meaning and count depending on $elementType
  548. *
  549. * @param string $elementType type of element to add (text, textarea, file...)
  550. * @since 1.0
  551. * @access public
  552. * @return HTML_QuickForm_Element
  553. * @throws HTML_QuickForm_Error
  554. */
  555. function &createElement($elementType) {
  556. $args = func_get_args();
  557. $element =& HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1));
  558. return $element;
  559. } // end func createElement
  560. // }}}
  561. // {{{ _loadElement()
  562. /**
  563. * Returns a form element of the given type
  564. *
  565. * @param string $event event to send to newly created element ('createElement' or 'addElement')
  566. * @param string $type element type
  567. * @param array $args arguments for event
  568. * @since 2.0
  569. * @access private
  570. * @return HTML_QuickForm_Element
  571. * @throws HTML_QuickForm_Error
  572. */
  573. function &_loadElement($event, $type, $args)
  574. {
  575. $type = strtolower($type);
  576. if (!HTML_QuickForm::isTypeRegistered($type)) {
  577. $error = PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
  578. return $error;
  579. }
  580. $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
  581. $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
  582. //include_once $includeFile;
  583. // Modified by Ivan Tcholakov, 16-MAR-2010. Suppressing a deprecation warning on PHP 5.3
  584. //$elementObject =& new $className();
  585. $elementObject = new $className();
  586. for ($i = 0; $i < 5; $i++) {
  587. if (!isset($args[$i])) {
  588. $args[$i] = null;
  589. }
  590. }
  591. $err = $elementObject->onQuickFormEvent($event, $args, $this);
  592. if ($err !== true) {
  593. return $err;
  594. }
  595. return $elementObject;
  596. } // end func _loadElement
  597. // }}}
  598. // {{{ addElement()
  599. /**
  600. * Adds an element into the form
  601. *
  602. * If $element is a string representing element type, then this
  603. * method accepts variable number of parameters, their meaning
  604. * and count depending on $element
  605. *
  606. * @param mixed $element element object or type of element to add (text, textarea, file...)
  607. * @since 1.0
  608. * @return HTML_QuickForm_Element a reference to newly added element
  609. * @access public
  610. * @throws HTML_QuickForm_Error
  611. */
  612. function &addElement($element)
  613. {
  614. if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
  615. $elementObject = &$element;
  616. $elementObject->onQuickFormEvent('updateValue', null, $this);
  617. } else {
  618. $args = func_get_args();
  619. $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1));
  620. if (PEAR::isError($elementObject)) {
  621. return $elementObject;
  622. }
  623. }
  624. $elementName = $elementObject->getName();
  625. // Add the element if it is not an incompatible duplicate
  626. if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  627. if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
  628. $elementObject->getType()) {
  629. $this->_elements[] =& $elementObject;
  630. $elKeys = array_keys($this->_elements);
  631. $this->_duplicateIndex[$elementName][] = end($elKeys);
  632. } else {
  633. $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
  634. return $error;
  635. }
  636. } else {
  637. $this->_elements[] =& $elementObject;
  638. $elKeys = array_keys($this->_elements);
  639. $this->_elementIndex[$elementName] = end($elKeys);
  640. }
  641. if ($this->_freezeAll) {
  642. $elementObject->freeze();
  643. }
  644. return $elementObject;
  645. } // end func addElement
  646. // }}}
  647. // {{{ insertElementBefore()
  648. /**
  649. * Inserts a new element right before the other element
  650. *
  651. * Warning: it is not possible to check whether the $element is already
  652. * added to the form, therefore if you want to move the existing form
  653. * element to a new position, you'll have to use removeElement():
  654. * $form->insertElementBefore($form->removeElement('foo', false), 'bar');
  655. *
  656. * @access public
  657. * @since 3.2.4
  658. * @param HTML_QuickForm_element Element to insert
  659. * @param string Name of the element before which the new
  660. * one is inserted
  661. * @return HTML_QuickForm_element reference to inserted element
  662. * @throws HTML_QuickForm_Error
  663. */
  664. function &insertElementBefore(&$element, $nameAfter)
  665. {
  666. if (!empty($this->_duplicateIndex[$nameAfter])) {
  667. $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);
  668. return $error;
  669. } elseif (!$this->elementExists($nameAfter)) {
  670. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  671. return $error;
  672. }
  673. $elementName = $element->getName();
  674. $targetIdx = $this->_elementIndex[$nameAfter];
  675. $duplicate = false;
  676. // Like in addElement(), check that it's not an incompatible duplicate
  677. if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  678. if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
  679. $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
  680. return $error;
  681. }
  682. $duplicate = true;
  683. }
  684. // Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
  685. $elKeys = array_keys($this->_elements);
  686. for ($i = end($elKeys); $i >= $targetIdx; $i--) {
  687. if (isset($this->_elements[$i])) {
  688. $currentName = $this->_elements[$i]->getName();
  689. $this->_elements[$i + 1] =& $this->_elements[$i];
  690. if ($this->_elementIndex[$currentName] == $i) {
  691. $this->_elementIndex[$currentName] = $i + 1;
  692. } else {
  693. $dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
  694. $this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
  695. }
  696. unset($this->_elements[$i]);
  697. }
  698. }
  699. // Put the element in place finally
  700. $this->_elements[$targetIdx] =& $element;
  701. if (!$duplicate) {
  702. $this->_elementIndex[$elementName] = $targetIdx;
  703. } else {
  704. $this->_duplicateIndex[$elementName][] = $targetIdx;
  705. }
  706. $element->onQuickFormEvent('updateValue', null, $this);
  707. if ($this->_freezeAll) {
  708. $element->freeze();
  709. }
  710. // If not done, the elements will appear in reverse order
  711. ksort($this->_elements);
  712. return $element;
  713. }
  714. // }}}
  715. // {{{ addGroup()
  716. /**
  717. * Adds an element group
  718. * @param array $elements array of elements composing the group
  719. * @param string $name (optional)group name
  720. * @param string $groupLabel (optional)group label
  721. * @param string $separator (optional)string to separate elements
  722. * @param string $appendName (optional)specify whether the group name should be
  723. * used in the form element name ex: group[element]
  724. * @return HTML_QuickForm_group reference to a newly added group
  725. * @since 2.8
  726. * @access public
  727. * @throws HTML_QuickForm_Error
  728. */
  729. function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
  730. {
  731. static $anonGroups = 1;
  732. if (0 == strlen($name)) {
  733. $name = 'qf_group_' . $anonGroups++;
  734. $appendName = false;
  735. }
  736. $group = & $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
  737. return $group;
  738. } // end func addGroup
  739. // }}}
  740. // {{{ &getElement()
  741. /**
  742. * Returns a reference to the element
  743. *
  744. * @param string $element Element name
  745. * @since 2.0
  746. * @access public
  747. * @return HTML_QuickForm_element reference to element
  748. * @throws HTML_QuickForm_Error
  749. */
  750. function &getElement($element)
  751. {
  752. if (isset($this->_elementIndex[$element])) {
  753. return $this->_elements[$this->_elementIndex[$element]];
  754. } else {
  755. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
  756. return $error;
  757. }
  758. } // end func getElement
  759. // }}}
  760. // {{{ &getElementValue()
  761. /**
  762. * Returns the element's raw value
  763. *
  764. * This returns the value as submitted by the form (not filtered)
  765. * or set via setDefaults() or setConstants()
  766. *
  767. * @param string $element Element name
  768. * @since 2.0
  769. * @access public
  770. * @return mixed element value
  771. * @throws HTML_QuickForm_Error
  772. */
  773. function &getElementValue($element)
  774. {
  775. if (!isset($this->_elementIndex[$element])) {
  776. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  777. return $error;
  778. }
  779. $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
  780. if (isset($this->_duplicateIndex[$element])) {
  781. foreach ($this->_duplicateIndex[$element] as $index) {
  782. if (null !== ($v = $this->_elements[$index]->getValue())) {
  783. if (is_array($value)) {
  784. $value[] = $v;
  785. } else {
  786. $value = (null === $value)? $v: array($value, $v);
  787. }
  788. }
  789. }
  790. }
  791. return $value;
  792. } // end func getElementValue
  793. // }}}
  794. // {{{ getSubmitValue()
  795. /**
  796. * Returns the elements value after submit and filter
  797. *
  798. * @param string Element name
  799. * @since 2.0
  800. * @access public
  801. * @return mixed submitted element value or null if not set
  802. */
  803. function getSubmitValue($elementName)
  804. {
  805. $value = null;
  806. if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
  807. $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
  808. if (is_array($value) && isset($this->_submitFiles[$elementName])) {
  809. foreach ($this->_submitFiles[$elementName] as $k => $v) {
  810. $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
  811. }
  812. }
  813. } elseif ('file' == $this->getElementType($elementName)) {
  814. return $this->getElementValue($elementName);
  815. } elseif (false !== ($pos = strpos($elementName, '['))) {
  816. $base = str_replace(
  817. array('\\', '\''), array('\\\\', '\\\''),
  818. substr($elementName, 0, $pos)
  819. );
  820. $idx = "['" . str_replace(
  821. array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
  822. substr($elementName, $pos + 1, -1)
  823. ) . "']";
  824. if (isset($this->_submitValues[$base])) {
  825. $value = eval("return (isset(\$this->_submitValues['{$base}']{$idx})) ? \$this->_submitValues['{$base}']{$idx} : null;");
  826. }
  827. if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
  828. $props = array('name', 'type', 'size', 'tmp_name', 'error');
  829. $code = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
  830. " return null;\n" .
  831. "} else {\n" .
  832. " \$v = array();\n";
  833. foreach ($props as $prop) {
  834. $code .= " \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
  835. }
  836. $fileValue = eval($code . " return \$v;\n}\n");
  837. if (null !== $fileValue) {
  838. $value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
  839. }
  840. }
  841. }
  842. // This is only supposed to work for groups with appendName = false
  843. if (null === $value && 'group' == $this->getElementType($elementName)) {
  844. $group =& $this->getElement($elementName);
  845. $elements =& $group->getElements();
  846. foreach (array_keys($elements) as $key) {
  847. $name = $group->getElementName($key);
  848. // prevent endless recursion in case of radios and such
  849. if ($name != $elementName) {
  850. if (null !== ($v = $this->getSubmitValue($name))) {
  851. $value[$name] = $v;
  852. }
  853. }
  854. }
  855. }
  856. return $value;
  857. } // end func getSubmitValue
  858. // }}}
  859. // {{{ _reindexFiles()
  860. /**
  861. * A helper function to change the indexes in $_FILES array
  862. *
  863. * @param mixed Some value from the $_FILES array
  864. * @param string The key from the $_FILES array that should be appended
  865. * @return array
  866. */
  867. function _reindexFiles($value, $key)
  868. {
  869. if (!is_array($value)) {
  870. return array($key => $value);
  871. } else {
  872. $ret = array();
  873. foreach ($value as $k => $v) {
  874. $ret[$k] = $this->_reindexFiles($v, $key);
  875. }
  876. return $ret;
  877. }
  878. }
  879. // }}}
  880. // {{{ getElementError()
  881. /**
  882. * Returns error corresponding to validated element
  883. *
  884. * @param string $element Name of form element to check
  885. * @since 1.0
  886. * @access public
  887. * @return string error message corresponding to checked element
  888. */
  889. function getElementError($element)
  890. {
  891. if (isset($this->_errors[$element])) {
  892. return $this->_errors[$element];
  893. }
  894. } // end func getElementError
  895. // }}}
  896. // {{{ setElementError()
  897. /**
  898. * Set error message for a form element
  899. *
  900. * @param string $element Name of form element to set error for
  901. * @param string $message Error message, if empty then removes the current error message
  902. * @since 1.0
  903. * @access public
  904. * @return void
  905. */
  906. function setElementError($element, $message = null)
  907. {
  908. if (!empty($message)) {
  909. $this->_errors[$element] = $message;
  910. } else {
  911. unset($this->_errors[$element]);
  912. }
  913. } // end func setElementError
  914. // }}}
  915. // {{{ getElementType()
  916. /**
  917. * Returns the type of the given element
  918. *
  919. * @param string $element Name of form element
  920. * @since 1.1
  921. * @access public
  922. * @return string Type of the element, false if the element is not found
  923. */
  924. function getElementType($element)
  925. {
  926. if (isset($this->_elementIndex[$element])) {
  927. return $this->_elements[$this->_elementIndex[$element]]->getType();
  928. }
  929. return false;
  930. } // end func getElementType
  931. // }}}
  932. // {{{ updateElementAttr()
  933. /**
  934. * Updates Attributes for one or more elements
  935. *
  936. * @param mixed $elements Array of element names/objects or string of elements to be updated
  937. * @param mixed $attrs Array or sting of html attributes
  938. * @since 2.10
  939. * @access public
  940. * @return void
  941. */
  942. function updateElementAttr($elements, $attrs)
  943. {
  944. if (is_string($elements)) {
  945. $elements = split('[ ]?,[ ]?', $elements);
  946. }
  947. foreach (array_keys($elements) as $key) {
  948. if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
  949. $elements[$key]->updateAttributes($attrs);
  950. } elseif (isset($this->_elementIndex[$elements[$key]])) {
  951. $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
  952. if (isset($this->_duplicateIndex[$elements[$key]])) {
  953. foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
  954. $this->_elements[$index]->updateAttributes($attrs);
  955. }
  956. }
  957. }
  958. }
  959. } // end func updateElementAttr
  960. // }}}
  961. // {{{ removeElement()
  962. /**
  963. * Removes an element
  964. *
  965. * The method "unlinks" an element from the form, returning the reference
  966. * to the element object. If several elements named $elementName exist,
  967. * it removes the first one, leaving the others intact.
  968. *
  969. * @param string $elementName The element name
  970. * @param boolean $removeRules True if rules for this element are to be removed too
  971. * @access public
  972. * @since 2.0
  973. * @return HTML_QuickForm_element a reference to the removed element
  974. * @throws HTML_QuickForm_Error
  975. */
  976. function &removeElement($elementName, $removeRules = true)
  977. {
  978. if (!isset($this->_elementIndex[$elementName])) {
  979. $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
  980. return $error;
  981. }
  982. $el =& $this->_elements[$this->_elementIndex[$elementName]];
  983. unset($this->_elements[$this->_elementIndex[$elementName]]);
  984. if (empty($this->_duplicateIndex[$elementName])) {
  985. unset($this->_elementIndex[$elementName]);
  986. } else {
  987. $this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
  988. }
  989. if ($removeRules) {
  990. $this->_required = array_diff($this->_required, array($elementName));
  991. unset($this->_rules[$elementName], $this->_errors[$elementName]);
  992. if ('group' == $el->getType()) {
  993. foreach (array_keys($el->getElements()) as $key) {
  994. unset($this->_rules[$el->getElementName($key)]);
  995. }
  996. }
  997. }
  998. return $el;
  999. } // end func removeElement
  1000. // }}}
  1001. // {{{ addRule()
  1002. /**
  1003. * Adds a validation rule for the given field
  1004. *
  1005. * If the element is in fact a group, it will be considered as a whole.
  1006. * To validate grouped elements as separated entities,
  1007. * use addGroupRule instead of addRule.
  1008. *
  1009. * @param string $element Form element name
  1010. * @param string $message Message to display for invalid data
  1011. * @param string $type Rule type, use getRegisteredRules() to get types
  1012. * @param string $format (optional)Required for extra rule data
  1013. * @param string $validation (optional)Where to perform validation: "server", "client"
  1014. * @param boolean $reset Client-side validation: reset the form element to its original value if there is an error?
  1015. * @param boolean $force Force the rule to be applied, even if the target form element does not exist
  1016. * @since 1.0
  1017. * @access public
  1018. * @throws HTML_QuickForm_Error
  1019. */
  1020. function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
  1021. {
  1022. if (!$force) {
  1023. if (!is_array($element) && !$this->elementExists($element)) {
  1024. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1025. } elseif (is_array($element)) {
  1026. foreach ($element as $el) {
  1027. if (!$this->elementExists($el)) {
  1028. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1029. }
  1030. }
  1031. }
  1032. }
  1033. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1034. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  1035. } elseif (is_string($newName)) {
  1036. $type = $newName;
  1037. }
  1038. if (is_array($element)) {
  1039. $dependent = $element;
  1040. $element = array_shift($dependent);
  1041. } else {
  1042. $dependent = null;
  1043. }
  1044. if ($type == 'required' || $type == 'uploadedfile') {
  1045. $this->_required[] = $element;
  1046. }
  1047. if (!isset($this->_rules[$element])) {
  1048. $this->_rules[$element] = array();
  1049. }
  1050. if ($validation == 'client') {
  1051. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1052. }
  1053. $this->_rules[$element][] = array(
  1054. 'type' => $type,
  1055. 'format' => $format,
  1056. 'message' => $message,
  1057. 'validation' => $validation,
  1058. 'reset' => $reset,
  1059. 'dependent' => $dependent
  1060. );
  1061. } // end func addRule
  1062. // }}}
  1063. // {{{ addGroupRule()
  1064. /**
  1065. * Adds a validation rule for the given group of elements
  1066. *
  1067. * Only groups with a name can be assigned a validation rule
  1068. * Use addGroupRule when you need to validate elements inside the group.
  1069. * Use addRule if you need to validate the group as a whole. In this case,
  1070. * the same rule will be applied to all elements in the group.
  1071. * Use addRule if you need to validate the group against a function.
  1072. *
  1073. * @param string $group Form group name
  1074. * @param mixed $arg1 Array for multiple elements or error message string for one element
  1075. * @param string $type (optional)Rule type use getRegisteredRules() to get types
  1076. * @param string $format (optional)Required for extra rule data
  1077. * @param int $howmany (optional)How many valid elements should be in the group
  1078. * @param string $validation (optional)Where to perform validation: "server", "client"
  1079. * @param bool $reset Client-side: whether to reset the element's value to its original state if validation failed.
  1080. * @since 2.5
  1081. * @access public
  1082. * @throws HTML_QuickForm_Error
  1083. */
  1084. function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
  1085. {
  1086. if (!$this->elementExists($group)) {
  1087. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1088. }
  1089. $groupObj =& $this->getElement($group);
  1090. if (is_array($arg1)) {
  1091. $required = 0;
  1092. foreach ($arg1 as $elementIndex => $rules) {
  1093. $elementName = $groupObj->getElementName($elementIndex);
  1094. foreach ($rules as $rule) {
  1095. $format = (isset($rule[2])) ? $rule[2] : null;
  1096. $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
  1097. $reset = isset($rule[4]) && $rule[4];
  1098. $type = $rule[1];
  1099. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1100. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1101. } elseif (is_string($newName)) {
  1102. $type = $newName;
  1103. }
  1104. $this->_rules[$elementName][] = array(
  1105. 'type' => $type,
  1106. 'format' => $format,
  1107. 'message' => $rule[0],
  1108. 'validation' => $validation,
  1109. 'reset' => $reset,
  1110. 'group' => $group);
  1111. if ('required' == $type || 'uploadedfile' == $type) {
  1112. $groupObj->_required[] = $elementName;
  1113. $this->_required[] = $elementName;
  1114. $required++;
  1115. }
  1116. if ('client' == $validation) {
  1117. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1118. }
  1119. }
  1120. }
  1121. if ($required > 0 && count($groupObj->getElements()) == $required) {
  1122. $this->_required[] = $group;
  1123. }
  1124. } elseif (is_string($arg1)) {
  1125. if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1126. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1127. } elseif (is_string($newName)) {
  1128. $type = $newName;
  1129. }
  1130. // addGroupRule() should also handle <select multiple>
  1131. if (is_a($groupObj, 'html_quickform_group')) {
  1132. // Radios need to be handled differently when required
  1133. if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
  1134. $howmany = ($howmany == 0) ? 1 : $howmany;
  1135. } else {
  1136. $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
  1137. }
  1138. }
  1139. $this->_rules[$group][] = array('type' => $type,
  1140. 'format' => $format,
  1141. 'message' => $arg1,
  1142. 'validation' => $validation,
  1143. 'howmany' => $howmany,
  1144. 'reset' => $reset);
  1145. if ($type == 'required') {
  1146. $this->_required[] = $group;
  1147. }
  1148. if ($validation == 'client') {
  1149. $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
  1150. }
  1151. }
  1152. } // end func addGroupRule
  1153. // }}}
  1154. // {{{ addFormRule()
  1155. /**
  1156. * Adds a global validation rule
  1157. *
  1158. * This should be used when for a rule involving several fields or if
  1159. * you want to use some completely custom validation for your form.
  1160. * The rule function/method should return true in case of successful
  1161. * validation and array('element name' => 'error') when there were errors.
  1162. *
  1163. * @access public
  1164. * @param mixed Callback, either function name or array(&$object, 'method')
  1165. * @throws HTML_QuickForm_Error
  1166. */
  1167. function addFormRule($rule)
  1168. {
  1169. if (!is_callable($rule)) {
  1170. return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
  1171. }
  1172. $this->_formRules[] = $rule;
  1173. }
  1174. // }}}
  1175. // {{{ applyFilter()
  1176. /**
  1177. * Applies a data filter for the given field(s)
  1178. *
  1179. * @param mixed $element Form element name or array of such names
  1180. * @param mixed $filter Callback, either function name or array(&$object, 'method')
  1181. * @since 2.0
  1182. * @access public
  1183. * @throws HTML_QuickForm_Error
  1184. */
  1185. function applyFilter($element, $filter)
  1186. {
  1187. if (!is_callable($filter)) {
  1188. return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
  1189. }
  1190. if ($element == '__ALL__') {
  1191. $this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
  1192. } else {
  1193. if (!is_array($element)) {
  1194. $element = array($element);
  1195. }
  1196. foreach ($element as $elName) {
  1197. $value = $this->getSubmitValue($elName);
  1198. if (null !== $value) {
  1199. if (false === strpos($elName, '[')) {
  1200. $this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
  1201. } else {
  1202. $idx = "['" . str_replace(
  1203. array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
  1204. $elName
  1205. ) . "']";
  1206. eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
  1207. }
  1208. }
  1209. }
  1210. }
  1211. } // end func applyFilter
  1212. // }}}
  1213. // {{{ _recursiveFilter()
  1214. /**
  1215. * Recursively apply a filter function
  1216. *
  1217. * @param string $filter filter to apply
  1218. * @param mixed $value submitted values
  1219. * @since 2.0
  1220. * @access private
  1221. * @return cleaned values
  1222. */
  1223. function _recursiveFilter($filter, $value)
  1224. {
  1225. if (is_array($value)) {
  1226. $cleanValues = array();
  1227. foreach ($value as $k => $v) {
  1228. $cleanValues[$k] = $this->_recursiveFilter($filter, $v);
  1229. }
  1230. return $cleanValues;
  1231. } else {
  1232. return call_user_func($filter, $value);
  1233. }
  1234. } // end func _recursiveFilter
  1235. // }}}
  1236. // {{{ arrayMerge()
  1237. /**
  1238. * Merges two arrays
  1239. *
  1240. * Merges two array like the PHP function array_merge but recursively.
  1241. * The main difference is that existing keys will not be renumbered
  1242. * if they are integers.
  1243. *
  1244. * @access public
  1245. * @param array $a original array
  1246. * @param array $b array which will be merged into first one
  1247. * @return array merged array
  1248. */
  1249. static function arrayMerge($a, $b)
  1250. {
  1251. foreach ($b as $k => $v) {
  1252. if (is_array($v)) {
  1253. if (isset($a[$k]) && !is_array($a[$k])) {
  1254. $a[$k] = $v;
  1255. } else {
  1256. if (!isset($a[$k])) {
  1257. $a[$k] = array();
  1258. }
  1259. $a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
  1260. }
  1261. } else {
  1262. $a[$k] = $v;
  1263. }
  1264. }
  1265. return $a;
  1266. } // end func arrayMerge
  1267. // }}}
  1268. // {{{ isTypeRegistered()
  1269. /**
  1270. * Returns whether or not the form element type is supported
  1271. *
  1272. * @param string $type Form element type
  1273. * @since 1.0
  1274. * @access public
  1275. * @return boolean
  1276. */
  1277. static function isTypeRegistered($type)
  1278. {
  1279. return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($type)]);
  1280. } // end func isTypeRegistered
  1281. // }}}
  1282. // {{{ getRegisteredTypes()
  1283. /**
  1284. * Returns an array of registered element types
  1285. *
  1286. * @since 1.0
  1287. * @access public
  1288. * @return array
  1289. */
  1290. function getRegisteredTypes()
  1291. {
  1292. return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
  1293. } // end func getRegisteredTypes
  1294. // }}}
  1295. // {{{ isRuleRegistered()
  1296. /**
  1297. * Returns whether or not the given rule is supported
  1298. *
  1299. * @param string $name Validation rule name
  1300. * @param bool Whether to automatically register subclasses of HTML_QuickForm_Rule
  1301. * @since 1.0
  1302. * @access public
  1303. * @return mixed true if previously registered, false if not, new rule name if auto-registering worked
  1304. */
  1305. function isRuleRegistered($name, $autoRegister = false)
  1306. {
  1307. if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
  1308. return true;
  1309. } elseif (!$autoRegister) {
  1310. return false;
  1311. }
  1312. $ruleName = false;
  1313. if (is_object($name) && is_a($name, 'html_quickform_rule')) {
  1314. $ruleName = !empty($name->name)? $name->name: get_class($name);
  1315. } elseif (is_string($name) && class_exists($name)) {
  1316. $parent = $name;
  1317. do {
  1318. if ('html_quickform_rule' == strtolower($parent)) {
  1319. $ruleName = $name;
  1320. break;
  1321. }
  1322. } while ($parent = get_parent_class($parent));
  1323. }
  1324. if ($ruleName) {
  1325. $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1326. $registry->registerRule($ruleName, null, $name);
  1327. }
  1328. return $ruleName;
  1329. } // end func isRuleRegistered
  1330. // }}}
  1331. // {{{ getRegisteredRules()
  1332. /**
  1333. * Returns an array of registered validation rules
  1334. *
  1335. * @since 1.0
  1336. * @access public
  1337. * @return array
  1338. */
  1339. function getRegisteredRules()
  1340. {
  1341. return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
  1342. } // end func getRegisteredRules
  1343. // }}}
  1344. // {{{ isElementRequired()
  1345. /**
  1346. * Returns whether or not the form element is required
  1347. *
  1348. * @param string $element Form element name
  1349. * @since 1.0
  1350. * @access public
  1351. * @return boolean
  1352. */
  1353. function isElementRequired($element)
  1354. {
  1355. return in_array($element, $this->_required, true);
  1356. } // end func isElementRequired
  1357. // }}}
  1358. // {{{ isElementFrozen()
  1359. /**
  1360. * Returns whether or not the form element is frozen
  1361. *
  1362. * @param string $element Form element name
  1363. * @since 1.0
  1364. * @access public
  1365. * @return boolean
  1366. */
  1367. function isElementFrozen($element)
  1368. {
  1369. if (isset($this->_elementIndex[$element])) {
  1370. return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
  1371. }
  1372. return false;
  1373. } // end func isElementFrozen
  1374. // }}}
  1375. // {{{ setJsWarnings()
  1376. /**
  1377. * Sets JavaScript warning messages
  1378. *
  1379. * @param string $pref Prefix warning
  1380. * @param string $post Postfix warning
  1381. * @since 1.1
  1382. * @access public
  1383. * @return void
  1384. */
  1385. function setJsWarnings($pref, $post)
  1386. {
  1387. $this->_jsPrefix = $pref;
  1388. $this->_jsPostfix = $post;
  1389. } // end func setJsWarnings
  1390. // }}}
  1391. // {{{ setRequiredNote()
  1392. /**
  1393. * Sets required-note
  1394. *
  1395. * @param string $note Message indicating some elements are required
  1396. * @since 1.1
  1397. * @access public
  1398. * @return void
  1399. */
  1400. function setRequiredNote($note)
  1401. {
  1402. $this->_requiredNote = $note;
  1403. } // end func setRequiredNote
  1404. // }}}
  1405. // {{{ getRequiredNote()
  1406. /**
  1407. * Returns the required note
  1408. *
  1409. * @since 2.0
  1410. * @access public
  1411. * @return string
  1412. */
  1413. function getRequiredNote()
  1414. {
  1415. return $this->_requiredNote;
  1416. } // end func getRequiredNote
  1417. // }}}
  1418. // {{{ validate()
  1419. /**
  1420. * Performs the server side validation
  1421. * @access public
  1422. * @since 1.0
  1423. * @return boolean true if no error found
  1424. * @throws HTML_QuickForm_Error
  1425. */
  1426. function validate()
  1427. {
  1428. if (count($this->_rules) == 0 && count($this->_formRules) == 0 &&
  1429. $this->isSubmitted()) {
  1430. return (0 == count($this->_errors));
  1431. } elseif (!$this->isSubmitted()) {
  1432. return false;
  1433. }
  1434. $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1435. foreach ($this->_rules as $target => $rules) {
  1436. $submitValue = $this->getSubmitValue($target);
  1437. foreach ($rules as $rule) {
  1438. if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
  1439. isset($this->_errors[$target])) {
  1440. continue 2;
  1441. }
  1442. // If element is not required and is empty, we shouldn't validate it
  1443. if (!$this->isElementRequired($target)) {
  1444. if (!isset($submitValue) || '' == $submitValue) {
  1445. continue 2;
  1446. // Fix for bug #3501: we shouldn't validate not uploaded files, either.
  1447. // Unfortunately, we can't just use $element->isUploadedFile() since
  1448. // the element in question can be buried in group. Thus this hack.
  1449. // See also bug #12014, we should only consider a file that has
  1450. // status UPLOAD_ERR_NO_FILE as not uploaded, in all other cases
  1451. // validation should be performed, so that e.g. 'maxfilesize' rule
  1452. // will display an error if status is UPLOAD_ERR_INI_SIZE
  1453. // or UPLOAD_ERR_FORM_SIZE
  1454. } elseif (is_array($submitValue)) {
  1455. if (false === ($pos = strpos($target, '['))) {
  1456. $isUpload = !empty($this->_submitFiles[$target]);
  1457. } else {
  1458. $base = str_replace(
  1459. array('\\', '\''), array('\\\\', '\\\''),
  1460. substr($target, 0, $pos)
  1461. );
  1462. $idx = "['" . str_replace(
  1463. array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
  1464. substr($target, $pos + 1, -1)
  1465. ) . "']";
  1466. eval("\$isUpload = isset(\$this->_submitFiles['{$base}']['name']{$idx});");
  1467. }
  1468. if ($isUpload && (!isset($submitValue['error']) || UPLOAD_ERR_NO_FILE == $submitValue['error'])) {
  1469. continue 2;
  1470. }
  1471. }
  1472. }
  1473. if (isset($rule['dependent']) && is_array($rule['dependent'])) {
  1474. $values = array($submitValue);
  1475. foreach ($rule['dependent'] as $elName) {
  1476. $values[] = $this->getSubmitValue($elName);
  1477. }
  1478. $result = $registry->validate($rule['type'], $values, $rule['format'], true);
  1479. } elseif (is_array($submitValue) && !isset($rule['howmany'])) {
  1480. $result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
  1481. } else {
  1482. $result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
  1483. }
  1484. if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
  1485. if (isset($rule['group'])) {
  1486. $this->_errors[$rule['group']] = $rule['message'];
  1487. } else {
  1488. $this->_errors[$target] = $rule['message'];
  1489. }
  1490. }
  1491. }
  1492. }
  1493. // process the global rules now
  1494. foreach ($this->_formRules as $rule) {
  1495. if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
  1496. if (is_array($res)) {
  1497. $this->_errors += $res;
  1498. } else {
  1499. return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
  1500. }
  1501. }
  1502. }
  1503. return (0 == count($this->_errors));
  1504. } // end func validate
  1505. // }}}
  1506. // {{{ freeze()
  1507. /**
  1508. * Displays elements without HTML input tags
  1509. *
  1510. * @param mixed $elementList array or string of element(s) to be frozen
  1511. * @since 1.0
  1512. * @access public
  1513. * @throws HTML_QuickForm_Error
  1514. */
  1515. function freeze($elementList=null)
  1516. {
  1517. if (!isset($elementList)) {
  1518. $this->_freezeAll = true;
  1519. $elementList = array();
  1520. } else {
  1521. if (!is_array($elementList)) {
  1522. $elementList = preg_split('/[ ]*,[ ]*/', $elementList);
  1523. }
  1524. $elementList = array_flip($elementList);
  1525. }
  1526. foreach (array_keys($this->_elements) as $key) {
  1527. $name = $this->_elements[$key]->getName();
  1528. if ($this->_freezeAll || isset($elementList[$name])) {
  1529. $this->_elements[$key]->freeze();
  1530. unset($elementList[$name]);
  1531. }
  1532. }
  1533. if (!empty($elementList)) {
  1534. 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);
  1535. }
  1536. return true;
  1537. } // end func freeze
  1538. // }}}
  1539. // {{{ isFrozen()
  1540. /**
  1541. * Returns whether or not the whole form is frozen
  1542. *
  1543. * @since 3.0
  1544. * @access public
  1545. * @return boolean
  1546. */
  1547. function isFrozen()
  1548. {
  1549. return $this->_freezeAll;
  1550. } // end func isFrozen
  1551. // }}}
  1552. // {{{ process()
  1553. /**
  1554. * Performs the form data processing
  1555. *
  1556. * @param mixed $callback Callback, either function name or array(&$object, 'method')
  1557. * @param bool $mergeFiles Whether uploaded files should be processed too
  1558. * @since 1.0
  1559. * @access public
  1560. * @throws HTML_QuickForm_Error
  1561. * @return mixed Whatever value the $callback function returns
  1562. */
  1563. function process($callback, $mergeFiles = true)
  1564. {
  1565. if (!is_callable($callback)) {
  1566. return PEAR::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
  1567. }
  1568. $values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
  1569. return call_user_func($callback, $values);
  1570. } // end func process
  1571. // }}}
  1572. // {{{ accept()
  1573. /**
  1574. * Accepts a renderer
  1575. *
  1576. * @param object An HTML_QuickForm_Renderer object
  1577. * @since 3.0
  1578. * @access public
  1579. * @return void
  1580. */
  1581. function accept(&$renderer) {
  1582. $renderer->startForm($this);
  1583. foreach (array_keys($this->_elements) as $key) {
  1584. $element = &$this->_elements[$key];
  1585. $elementName = $element->getName();
  1586. if ($this->getAllowRichEditorInForm() == false) {
  1587. if ($element->getType() == 'html_editor') {
  1588. if (!in_array($elementName, $this->getAllowedRichEditorList())) {
  1589. $element->setRichEditorStatus(false);
  1590. }
  1591. }
  1592. }
  1593. $required = $this->isElementRequired($elementName) && !$element->isFrozen();
  1594. $error = $this->getElementError($elementName);
  1595. $element->accept($renderer, $required, $error);
  1596. }
  1597. $renderer->finishForm($this);
  1598. } // end func accept
  1599. // }}}
  1600. // {{{ defaultRenderer()
  1601. /**
  1602. * Returns a reference to default renderer object
  1603. *
  1604. * @access public
  1605. * @since 3.0
  1606. * @return object a default renderer object
  1607. */
  1608. function &defaultRenderer() {
  1609. if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
  1610. //include_once 'HTML/QuickForm/Renderer/Default.php';
  1611. // Modified by Ivan Tcholakov, 16-MAR-2010. Suppressing a deprecation warning on PHP 5.3
  1612. //$GLOBALS['_HTML_QuickForm_default_renderer'] =& new HTML_QuickForm_Renderer_Default();
  1613. $GLOBALS['_HTML_QuickForm_default_renderer'] = new HTML_QuickForm_Renderer_Default();
  1614. }
  1615. return $GLOBALS['_HTML_QuickForm_default_renderer'];
  1616. } // end func defaultRenderer
  1617. // }}}
  1618. // {{{ toHtml ()
  1619. /**
  1620. * Returns an HTML version of the form
  1621. *
  1622. * @param string $in_data (optional) Any extra data to insert right
  1623. * before form is rendered. Useful when using templates.
  1624. *
  1625. * @return string Html version of the form
  1626. * @since 1.0
  1627. * @access public
  1628. */
  1629. function toHtml ($in_data = null) {
  1630. if (!is_null($in_data)) {
  1631. $this->addElement('html', $in_data);
  1632. }
  1633. $renderer =& $this->defaultRenderer();
  1634. $this->accept($renderer);
  1635. return $renderer->toHtml();
  1636. } // end func toHtml
  1637. // }}}
  1638. // {{{ getValidationScript()
  1639. /**
  1640. * Returns the client side validation script
  1641. *
  1642. * @since 2.0
  1643. * @access public
  1644. * @return string Javascript to perform validation, empty string if no 'client' rules were added
  1645. */
  1646. function getValidationScript()
  1647. {
  1648. if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
  1649. return '';
  1650. }
  1651. $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1652. $test = array();
  1653. $js_escape = array(
  1654. "\r" => '\r',
  1655. "\n" => '\n',
  1656. "\t" => '\t',
  1657. "'" => "\\'",
  1658. '"' => '\"',
  1659. '\\' => '\\\\'
  1660. );
  1661. foreach ($this->_rules as $elementName => $rules) {
  1662. foreach ($rules as $rule) {
  1663. if ('client' == $rule['validation']) {
  1664. unset($element);
  1665. $dependent = isset($rule['dependent']) && is_array($rule['dependent']);
  1666. $rule['message'] = strtr($rule['message'], $js_escape);
  1667. if (isset($rule['group'])) {
  1668. $group =& $this->getElement($rule['group']);
  1669. // No JavaScript validation for frozen elements
  1670. if ($group->isFrozen()) {
  1671. continue 2;
  1672. }
  1673. $elements =& $group->getElements();
  1674. foreach (array_keys($elements) as $key) {
  1675. if ($elementName == $group->getElementName($key)) {
  1676. $element =& $elements[$key];
  1677. break;
  1678. }
  1679. }
  1680. } elseif ($dependent) {
  1681. $element = array();
  1682. $element[] =& $this->getElement($elementName);
  1683. foreach ($rule['dependent'] as $elName) {
  1684. $element[] =& $this->getElement($elName);
  1685. }
  1686. } else {
  1687. $element =& $this->getElement($elementName);
  1688. }
  1689. // No JavaScript validation for frozen elements
  1690. if (is_object($element) && $element->isFrozen()) {
  1691. continue 2;
  1692. } elseif (is_array($element)) {
  1693. foreach (array_keys($element) as $key) {
  1694. if ($element[$key]->isFrozen()) {
  1695. continue 3;
  1696. }
  1697. }
  1698. }
  1699. $test[] = $registry->getValidationScript($element, $elementName, $rule);
  1700. }
  1701. }
  1702. }
  1703. if (count($test) > 0) {
  1704. return
  1705. "\n<script type=\"text/javascript\">\n" .
  1706. "//<![CDATA[\n" .
  1707. "function validate_" . $this->_attributes['id'] . "(frm) {\n" .
  1708. " var value = '';\n" .
  1709. " var errFlag = new Array();\n" .
  1710. " var _qfGroups = {};\n" .
  1711. " _qfMsg = '';\n\n" .
  1712. join("\n", $test) .
  1713. "\n if (_qfMsg != '') {\n" .
  1714. " _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
  1715. " _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
  1716. " alert(_qfMsg);\n" .
  1717. " return false;\n" .
  1718. " }\n" .
  1719. " return true;\n" .
  1720. "}\n" .
  1721. "//]]>\n" .
  1722. "</script>";
  1723. }
  1724. return '';
  1725. } // end func getValidationScript
  1726. // }}}
  1727. // {{{ getSubmitValues()
  1728. /**
  1729. * Returns the values submitted by the form
  1730. *
  1731. * @since 2.0
  1732. * @access public
  1733. * @param bool Whether uploaded files should be returned too
  1734. * @return array
  1735. */
  1736. function getSubmitValues($mergeFiles = false)
  1737. {
  1738. return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
  1739. } // end func getSubmitValues
  1740. // }}}
  1741. // {{{ toArray()
  1742. /**
  1743. * Returns the form's contents in an array.
  1744. *
  1745. * The description of the array structure is in HTML_QuickForm_Renderer_Array docs
  1746. *
  1747. * @since 2.0
  1748. * @access public
  1749. * @param bool Whether to collect hidden elements (passed to the Renderer's constructor)
  1750. * @return array of form contents
  1751. */
  1752. function toArray($collectHidden = false)
  1753. {
  1754. // Modified by Ivan Tcholakov, 16-MAR-2010. Suppressing a deprecation warning on PHP 5.3
  1755. //$renderer =& new HTML_QuickForm_Renderer_Array($collectHidden);
  1756. $renderer = new HTML_QuickForm_Renderer_Array($collectHidden);
  1757. //
  1758. $this->accept($renderer);
  1759. return $renderer->toArray();
  1760. } // end func toArray
  1761. // }}}
  1762. // {{{ exportValue()
  1763. /**
  1764. * Returns a 'safe' element's value
  1765. *
  1766. * This method first tries to find a cleaned-up submitted value,
  1767. * it will return a value set by setValue()/setDefaults()/setConstants()
  1768. * if submitted value does not exist for the given element.
  1769. *
  1770. * @param string Name of an element
  1771. * @access public
  1772. * @return mixed
  1773. * @throws HTML_QuickForm_Error
  1774. */
  1775. function exportValue($element)
  1776. {
  1777. if (!isset($this->_elementIndex[$element])) {
  1778. return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  1779. }
  1780. $value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
  1781. if (isset($this->_duplicateIndex[$element])) {
  1782. foreach ($this->_duplicateIndex[$element] as $index) {
  1783. if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
  1784. if (is_array($value)) {
  1785. $value[] = $v;
  1786. } else {
  1787. $value = (null === $value)? $v: array($value, $v);
  1788. }
  1789. }
  1790. }
  1791. }
  1792. return $value;
  1793. }
  1794. // }}}
  1795. // {{{ exportValues()
  1796. /**
  1797. * Returns 'safe' elements' values
  1798. *
  1799. * Unlike getSubmitValues(), this will return only the values
  1800. * corresponding to the elements present in the form.
  1801. *
  1802. * @param mixed Array/string of element names, whose values we want. If not set then return all elements.
  1803. * @access public
  1804. * @return array An assoc array of elements' values
  1805. * @throws HTML_QuickForm_Error
  1806. */
  1807. function exportValues($elementList = null)
  1808. {
  1809. $values = array();
  1810. if (null === $elementList) {
  1811. // iterate over all elements, calling their exportValue() methods
  1812. foreach (array_keys($this->_elements) as $key) {
  1813. $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
  1814. if (is_array($value)) {
  1815. // This shit throws a bogus warning in PHP 4.3.x
  1816. $values = HTML_QuickForm::arrayMerge($values, $value);
  1817. }
  1818. }
  1819. } else {
  1820. if (!is_array($elementList)) {
  1821. $elementList = array_map('trim', explode(',', $elementList));
  1822. }
  1823. foreach ($elementList as $elementName) {
  1824. $value = $this->exportValue($elementName);
  1825. if (PEAR::isError($value)) {
  1826. return $value;
  1827. }
  1828. $values[$elementName] = $value;
  1829. }
  1830. }
  1831. return $values;
  1832. }
  1833. // }}}
  1834. // {{{ isSubmitted()
  1835. /**
  1836. * Tells whether the form was already submitted
  1837. *
  1838. * This is useful since the _submitFiles and _submitValues arrays
  1839. * may be completely empty after the trackSubmit value is removed.
  1840. *
  1841. * @access public
  1842. * @return bool
  1843. */
  1844. function isSubmitted()
  1845. {
  1846. return $this->_flagSubmitted;
  1847. }
  1848. // }}}
  1849. // {{{ isError()
  1850. /**
  1851. * Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
  1852. *
  1853. * @access public
  1854. * @param mixed result code
  1855. * @return bool whether $value is an error
  1856. * @static
  1857. */
  1858. function isError($value)
  1859. {
  1860. return (is_object($value) && is_a($value, 'html_quickform_error'));
  1861. } // end func isError
  1862. // }}}
  1863. // {{{ errorMessage()
  1864. /**
  1865. * Return a textual error message for an QuickForm error code
  1866. *
  1867. * @access public
  1868. * @param int error code
  1869. * @return string error message
  1870. * @static
  1871. */
  1872. function errorMessage($value)
  1873. {
  1874. // make the variable static so that it only has to do the defining on the first call
  1875. static $errorMessages;
  1876. // define the varies error messages
  1877. if (!isset($errorMessages)) {
  1878. $errorMessages = array(
  1879. QUICKFORM_OK => 'no error',
  1880. QUICKFORM_ERROR => 'unknown error',
  1881. QUICKFORM_INVALID_RULE => 'the rule does not exist as a registered rule',
  1882. QUICKFORM_NONEXIST_ELEMENT => 'nonexistent html element',
  1883. QUICKFORM_INVALID_FILTER => 'invalid filter',
  1884. QUICKFORM_UNREGISTERED_ELEMENT => 'unregistered element',
  1885. QUICKFORM_INVALID_ELEMENT_NAME => 'element already exists',
  1886. QUICKFORM_INVALID_PROCESS => 'process callback does not exist',
  1887. QUICKFORM_DEPRECATED => 'method is deprecated',
  1888. QUICKFORM_INVALID_DATASOURCE => 'datasource is not an object'
  1889. );
  1890. }
  1891. // If this is an error object, then grab the corresponding error code
  1892. if (HTML_QuickForm::isError($value)) {
  1893. $value = $value->getCode();
  1894. }
  1895. // return the textual error message corresponding to the code
  1896. return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
  1897. } // end func errorMessage
  1898. /**
  1899. *
  1900. * @param bool $status
  1901. */
  1902. public function setAllowRichEditorInForm($status) {
  1903. $this->allowRichEditorInForm = (bool)$status;
  1904. }
  1905. /**
  1906. * Returns the rich editor status
  1907. * @return bool status
  1908. */
  1909. public function getAllowRichEditorInForm()
  1910. {
  1911. return $this->allowRichEditorInForm;
  1912. }
  1913. public function setAllowedRichEditorList($array)
  1914. {
  1915. $this->allowedRichEditorList = $array;
  1916. }
  1917. public function getAllowedRichEditorList()
  1918. {
  1919. return $this->allowedRichEditorList;
  1920. }
  1921. // }}}
  1922. } // end class HTML_QuickForm
  1923. /**
  1924. * Class for errors thrown by HTML_QuickForm package
  1925. *
  1926. * @category HTML
  1927. * @package HTML_QuickForm
  1928. * @author Adam Daniel <adaniel1@eesus.jnj.com>
  1929. * @author Bertrand Mansion <bmansion@mamasam.com>
  1930. * @version Release: 3.2.11
  1931. */
  1932. class HTML_QuickForm_Error extends PEAR_Error {
  1933. // {{{ properties
  1934. /**
  1935. * Prefix for all error messages
  1936. * @var string
  1937. */
  1938. var $error_message_prefix = 'QuickForm Error: ';
  1939. // }}}
  1940. // {{{ constructor
  1941. /**
  1942. * Creates a quickform error object, extending the PEAR_Error class
  1943. *
  1944. * @param int $code the error code
  1945. * @param int $mode the reaction to the error, either return, die or trigger/callback
  1946. * @param int $level intensity of the error (PHP error code)
  1947. * @param mixed $debuginfo any information that can inform user as to nature of the error
  1948. */
  1949. function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
  1950. $level = E_USER_NOTICE, $debuginfo = null)
  1951. {
  1952. if (is_int($code)) {
  1953. $this->PEAR_Error(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
  1954. } else {
  1955. $this->PEAR_Error("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
  1956. }
  1957. }
  1958. // }}}
  1959. } // end class HTML_QuickForm_Error