MDL-62947 core_form: fix remote code execution exploit in QuickForms
[moodle.git] / lib / pear / HTML / QuickForm / element.php
CommitLineData
da6f8763 1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3// +----------------------------------------------------------------------+
4// | PHP version 4.0 |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
7// +----------------------------------------------------------------------+
8// | This source file is subject to version 2.0 of the PHP license, |
9// | that is bundled with this package in the file LICENSE, and is |
10// | available at through the world-wide-web at |
11// | http://www.php.net/license/2_02.txt. |
12// | If you did not receive a copy of the PHP license and are unable to |
13// | obtain it through the world-wide-web, please send a note to |
14// | license@php.net so we can mail you a copy immediately. |
15// +----------------------------------------------------------------------+
16// | Authors: Adam Daniel <adaniel1@eesus.jnj.com> |
17// | Bertrand Mansion <bmansion@mamasam.com> |
18// +----------------------------------------------------------------------+
19//
20// $Id$
21
22require_once('HTML/Common.php');
c87010ba
JD
23/**
24 * Static utility methods.
25 */
26require_once('HTML/QuickForm/utils.php');
da6f8763 27
28/**
29 * Base class for form elements
30 *
31 * @author Adam Daniel <adaniel1@eesus.jnj.com>
32 * @author Bertrand Mansion <bmansion@mamasam.com>
33 * @version 1.3
34 * @since PHP4.04pl1
35 * @access public
36 * @abstract
37 */
38class HTML_QuickForm_element extends HTML_Common
39{
40 // {{{ properties
41
42 /**
43 * Label of the field
44 * @var string
45 * @since 1.3
46 * @access private
47 */
48 var $_label = '';
49
50 /**
51 * Form element type
52 * @var string
53 * @since 1.0
54 * @access private
55 */
56 var $_type = '';
57
58 /**
59 * Flag to tell if element is frozen
60 * @var boolean
61 * @since 1.0
62 * @access private
63 */
64 var $_flagFrozen = false;
65
66 /**
67 * Does the element support persistant data when frozen
68 * @var boolean
69 * @since 1.3
70 * @access private
71 */
72 var $_persistantFreeze = false;
73
74 // }}}
75 // {{{ constructor
76
77 /**
78 * Class constructor
79 *
80 * @param string Name of the element
81 * @param mixed Label(s) for the element
82 * @param mixed Associative array of tag attributes or HTML attributes name="value" pairs
83 * @since 1.0
84 * @access public
85 * @return void
86 */
1a0df553
MG
87 public function __construct($elementName=null, $elementLabel=null, $attributes=null) {
88 parent::__construct($attributes);
da6f8763 89 if (isset($elementName)) {
90 $this->setName($elementName);
91 }
92 if (isset($elementLabel)) {
93 $this->setLabel($elementLabel);
94 }
95 } //end constructor
1a0df553
MG
96
97 /**
98 * Old syntax of class constructor. Deprecated in PHP7.
99 *
100 * @deprecated since Moodle 3.1
101 */
102 public function HTML_QuickForm_element($elementName=null, $elementLabel=null, $attributes=null) {
103 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
104 self::__construct($elementName, $elementLabel, $attributes);
105 }
da6f8763 106
107 // }}}
108 // {{{ apiVersion()
109
110 /**
111 * Returns the current API version
112 *
113 * @since 1.0
114 * @access public
115 * @return float
116 */
117 function apiVersion()
118 {
119 return 2.0;
120 } // end func apiVersion
121
122 // }}}
123 // {{{ getType()
124
125 /**
126 * Returns element type
127 *
128 * @since 1.0
129 * @access public
130 * @return string
131 */
132 function getType()
133 {
134 return $this->_type;
135 } // end func getType
136
137 // }}}
138 // {{{ setName()
139
140 /**
141 * Sets the input field name
142 *
143 * @param string $name Input field name attribute
144 * @since 1.0
145 * @access public
146 * @return void
147 */
148 function setName($name)
149 {
150 // interface method
151 } //end func setName
152
153 // }}}
154 // {{{ getName()
155
156 /**
157 * Returns the element name
158 *
159 * @since 1.0
160 * @access public
161 * @return string
162 */
163 function getName()
164 {
165 // interface method
166 } //end func getName
167
168 // }}}
169 // {{{ setValue()
170
171 /**
172 * Sets the value of the form element
173 *
174 * @param string $value Default value of the form element
175 * @since 1.0
176 * @access public
177 * @return void
178 */
179 function setValue($value)
180 {
181 // interface
182 } // end func setValue
183
184 // }}}
185 // {{{ getValue()
186
187 /**
188 * Returns the value of the form element
189 *
190 * @since 1.0
191 * @access public
192 * @return mixed
193 */
194 function getValue()
195 {
196 // interface
197 return null;
198 } // end func getValue
199
200 // }}}
201 // {{{ freeze()
202
203 /**
204 * Freeze the element so that only its value is returned
205 *
206 * @access public
207 * @return void
208 */
209 function freeze()
210 {
211 $this->_flagFrozen = true;
212 } //end func freeze
213
214 // }}}
215 // {{{ unfreeze()
216
217 /**
218 * Unfreezes the element so that it becomes editable
219 *
220 * @access public
221 * @return void
222 * @since 3.2.4
223 */
224 function unfreeze()
225 {
226 $this->_flagFrozen = false;
227 }
228
229 // }}}
230 // {{{ getFrozenHtml()
231
232 /**
233 * Returns the value of field without HTML tags
234 *
235 * @since 1.0
236 * @access public
237 * @return string
238 */
239 function getFrozenHtml()
240 {
241 $value = $this->getValue();
242 return ('' != $value? htmlspecialchars($value): '&nbsp;') .
243 $this->_getPersistantData();
244 } //end func getFrozenHtml
245
246 // }}}
247 // {{{ _getPersistantData()
248
249 /**
250 * Used by getFrozenHtml() to pass the element's value if _persistantFreeze is on
251 *
252 * @access private
253 * @return string
254 */
255 function _getPersistantData()
256 {
257 if (!$this->_persistantFreeze) {
258 return '';
259 } else {
260 $id = $this->getAttribute('id');
1ebda3eb
RT
261 if (isset($id)) {
262 // Id of persistant input is different then the actual input.
263 $id = array('id' => $id . '_persistant');
264 } else {
265 $id = array();
266 }
267
da6f8763 268 return '<input' . $this->_getAttrString(array(
269 'type' => 'hidden',
270 'name' => $this->getName(),
271 'value' => $this->getValue()
1ebda3eb 272 ) + $id) . ' />';
da6f8763 273 }
274 }
275
276 // }}}
277 // {{{ isFrozen()
278
279 /**
280 * Returns whether or not the element is frozen
281 *
282 * @since 1.3
283 * @access public
284 * @return bool
285 */
286 function isFrozen()
287 {
288 return $this->_flagFrozen;
289 } // end func isFrozen
290
291 // }}}
292 // {{{ setPersistantFreeze()
293
294 /**
295 * Sets wether an element value should be kept in an hidden field
296 * when the element is frozen or not
297 *
298 * @param bool $persistant True if persistant value
299 * @since 2.0
300 * @access public
301 * @return void
302 */
303 function setPersistantFreeze($persistant=false)
304 {
305 $this->_persistantFreeze = $persistant;
306 } //end func setPersistantFreeze
307
308 // }}}
309 // {{{ setLabel()
310
311 /**
312 * Sets display text for the element
313 *
314 * @param string $label Display text for the element
315 * @since 1.3
316 * @access public
317 * @return void
318 */
319 function setLabel($label)
320 {
321 $this->_label = $label;
322 } //end func setLabel
323
324 // }}}
325 // {{{ getLabel()
326
327 /**
328 * Returns display text for the element
329 *
330 * @since 1.3
331 * @access public
332 * @return string
333 */
334 function getLabel()
335 {
336 return $this->_label;
337 } //end func getLabel
338
339 // }}}
340 // {{{ _findValue()
341
342 /**
343 * Tries to find the element value from the values array
344 *
345 * @since 2.7
346 * @access private
347 * @return mixed
348 */
349 function _findValue(&$values)
350 {
351 if (empty($values)) {
352 return null;
353 }
354 $elementName = $this->getName();
355 if (isset($values[$elementName])) {
356 return $values[$elementName];
357 } elseif (strpos($elementName, '[')) {
c87010ba
JD
358 $keys = str_replace(
359 array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
360 $elementName
361 );
362 $arrayKeys = explode("']['", $keys);
363 return HTML_QuickForm_utils::recursiveValue($values, $arrayKeys);
da6f8763 364 } else {
365 return null;
366 }
367 } //end func _findValue
368
369 // }}}
370 // {{{ onQuickFormEvent()
371
372 /**
373 * Called by HTML_QuickForm whenever form event is made on this element
374 *
375 * @param string $event Name of event
376 * @param mixed $arg event arguments
377 * @param object $caller calling object
378 * @since 1.0
379 * @access public
380 * @return void
381 */
382 function onQuickFormEvent($event, $arg, &$caller)
383 {
384 switch ($event) {
385 case 'createElement':
1a0df553 386 static::__construct($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]);
da6f8763 387 break;
388 case 'addElement':
389 $this->onQuickFormEvent('createElement', $arg, $caller);
390 $this->onQuickFormEvent('updateValue', null, $caller);
391 break;
392 case 'updateValue':
393 // constant values override both default and submitted ones
394 // default values are overriden by submitted
395 $value = $this->_findValue($caller->_constantValues);
396 if (null === $value) {
397 $value = $this->_findValue($caller->_submitValues);
398 if (null === $value) {
399 $value = $this->_findValue($caller->_defaultValues);
400 }
401 }
402 if (null !== $value) {
403 $this->setValue($value);
404 }
405 break;
406 case 'setGroupValue':
407 $this->setValue($arg);
408 }
409 return true;
410 } // end func onQuickFormEvent
411
412 // }}}
413 // {{{ accept()
414
415 /**
416 * Accepts a renderer
417 *
418 * @param object An HTML_QuickForm_Renderer object
419 * @param bool Whether an element is required
420 * @param string An error message associated with an element
421 * @access public
422 * @return void
423 */
424 function accept(&$renderer, $required=false, $error=null)
425 {
426 $renderer->renderElement($this, $required, $error);
427 } // end func accept
428
429 // }}}
430 // {{{ _generateId()
431
432 /**
433 * Automatically generates and assigns an 'id' attribute for the element.
434 *
435 * Currently used to ensure that labels work on radio buttons and
436 * checkboxes. Per idea of Alexander Radivanovich.
437 *
438 * @access private
439 * @return void
440 */
820b41e3
TH
441 function _generateId() {
442 if ($this->getAttribute('id')) {
443 return;
da6f8763 444 }
820b41e3
TH
445
446 $id = $this->getName();
447 $id = 'id_' . str_replace(array('qf_', '[', ']'), array('', '_', ''), $id);
448 $id = clean_param($id, PARAM_ALPHANUMEXT);
449 $this->updateAttributes(array('id' => $id));
450 }
da6f8763 451
452 // }}}
453 // {{{ exportValue()
454
455 /**
456 * Returns a 'safe' element's value
457 *
458 * @param array array of submitted values to search
459 * @param bool whether to return the value as associative array
460 * @access public
461 * @return mixed
462 */
463 function exportValue(&$submitValues, $assoc = false)
464 {
465 $value = $this->_findValue($submitValues);
466 if (null === $value) {
467 $value = $this->getValue();
468 }
469 return $this->_prepareValue($value, $assoc);
470 }
471
472 // }}}
473 // {{{ _prepareValue()
474
475 /**
476 * Used by exportValue() to prepare the value for returning
477 *
478 * @param mixed the value found in exportValue()
479 * @param bool whether to return the value as associative array
480 * @access private
481 * @return mixed
482 */
483 function _prepareValue($value, $assoc)
484 {
485 if (null === $value) {
486 return null;
487 } elseif (!$assoc) {
488 return $value;
489 } else {
490 $name = $this->getName();
491 if (!strpos($name, '[')) {
492 return array($name => $value);
493 } else {
c87010ba
JD
494 $keys = str_replace(
495 array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
496 $name
497 );
498 $keysArray = explode("']['", $keys);
499 return HTML_QuickForm_utils::recursiveBuild($keysArray, $value);
da6f8763 500 }
501 }
502 }
503
504 // }}}
505} // end class HTML_QuickForm_element
1ebda3eb 506?>