493b168d |
1 | <?php |
4b4abf93 |
2 | |
493b168d |
3 | /** |
ed6d3334 |
4 | * forms.php - html form functions |
493b168d |
5 | * |
ba556ce5 |
6 | * Functions to build forms in a safe and consistent manner. |
15623730 |
7 | * All attribute values are sanitized with htmlspecialchars(). |
ba556ce5 |
8 | //FIXME: I think the Template class might be better place to sanitize inside assign() method |
493b168d |
9 | * |
ed6d3334 |
10 | * Currently functions don't provide simple wrappers for file and |
11 | * image input fields, support only submit and reset buttons and use |
15623730 |
12 | * html input tags for buttons. |
ed6d3334 |
13 | * |
574240f5 |
14 | * Since 1.5.1: |
15 | * |
16 | * * all form functions should support id tags. Original |
17 | * idea by dugan <at> passwall.com. Tags can be used for Section 508 |
18 | * or WAI compliance. |
19 | * |
20 | * * input tag functions accept extra html attributes that can be submitted |
21 | * in $aAttribs array. |
22 | * |
23 | * * default css class attributes are added. |
ed6d3334 |
24 | * |
25 | * @link http://www.section508.gov/ Section 508 |
26 | * @link http://www.w3.org/WAI/ Web Accessibility Initiative (WAI) |
27 | * @link http://www.w3.org/TR/html4/ W3.org HTML 4.01 form specs |
4b5049de |
28 | * @copyright © 2004-2007 The SquirrelMail Project Team |
4b4abf93 |
29 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
74f5d33f |
30 | * @version $Id$ |
493b168d |
31 | * @package squirrelmail |
74f5d33f |
32 | * @subpackage forms |
ed6d3334 |
33 | * @since 1.4.3 and 1.5.1 |
493b168d |
34 | */ |
35 | |
36 | /** |
37 | * Helper function to create form fields, not to be called directly, |
38 | * only by other functions below. |
574240f5 |
39 | * |
40 | * Function used different syntax before 1.5.1 |
41 | * @param string $sType type of input field. Possible values (html 4.01 |
ed6d3334 |
42 | * specs.): text, password, checkbox, radio, submit, reset, file, |
43 | * hidden, image, button. |
574240f5 |
44 | * @param array $aAttribs (since 1.5.1) extra attributes. Array key is |
45 | * attribute name, array value is attribute value. Array keys must use |
46 | * lowercase. |
ed6d3334 |
47 | * @return string html formated input field |
48 | * @deprecated use other functions that provide simple wrappers to this function |
493b168d |
49 | */ |
574240f5 |
50 | function addInputField($sType, $aAttribs=array()) { |
51 | $sAttribs = ''; |
52 | // define unique identifier |
53 | if (! isset($aAttribs['id']) && isset($aAttribs['name']) && ! is_null($aAttribs['name'])) { |
5f817a0b |
54 | /** |
55 | * if 'id' is not set, set it to 'name' and replace brackets |
56 | * with underscores. 'name' might contain field name with squire |
57 | * brackets (array). Brackets are not allowed in id (validator.w3.org |
58 | * fails to validate document). According to html 4.01 manual cdata |
59 | * type description, 'name' attribute uses same type, but validator.w3.org |
60 | * does not barf on brackets in 'name' attributes. |
61 | */ |
62 | $aAttribs['id'] = strtr($aAttribs['name'],'[]','__'); |
574240f5 |
63 | } |
ba556ce5 |
64 | |
65 | global $oTemplate; |
66 | |
67 | $oTemplate->assign('type', $sType); |
68 | //FIXME: all the values in the $aAttribs list used to go thru htmlspecialchars()... I would propose that most everything that is assigned to the template should go thru that *in the template class* on its way between here and the actual template file. Otherwise we have to do something like: foreach ($aAttribs as $key => $value) $aAttribs[$key] = htmlspecialchars($value); |
69 | $oTemplate->assign('aAttribs', $aAttribs); |
70 | |
71 | return $oTemplate->fetch('input.tpl'); |
72 | |
493b168d |
73 | } |
74 | |
10ff256e |
75 | /** |
76 | * Password input field |
574240f5 |
77 | * @param string $sName field name |
78 | * @param string $sValue initial password value |
3fa09710 |
79 | * @param integer $iSize field size (number of characters) |
80 | * @param integer $iMaxlength maximum number of characters the user may enter |
81 | * @param array $aAttribs (since 1.5.1) extra attributes - should be given |
82 | * in the form array('attribute_name' => 'attribute_value', ...) |
83 | * @return string html formated password field |
10ff256e |
84 | */ |
3fa09710 |
85 | function addPwField($sName, $sValue = '', $iSize = 0, $iMaxlength = 0, $aAttribs=array()) { |
574240f5 |
86 | $aAttribs['name'] = $sName; |
3fa09710 |
87 | $aAttribs['value'] = $sValue; |
88 | if ($iSize) $aAttribs['size'] = (int)$iSize; |
89 | if ($iMaxlength) $aAttribs['maxlength'] = (int)$iMaxlength; |
574240f5 |
90 | // add default css |
91 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmpwfield'; |
92 | return addInputField('password',$aAttribs); |
10ff256e |
93 | } |
94 | |
493b168d |
95 | /** |
96 | * Form checkbox |
574240f5 |
97 | * @param string $sName field name |
98 | * @param boolean $bChecked controls if field is checked |
99 | * @param string $sValue |
100 | * @param array $aAttribs (since 1.5.1) extra attributes |
ed6d3334 |
101 | * @return string html formated checkbox field |
493b168d |
102 | */ |
574240f5 |
103 | function addCheckBox($sName, $bChecked = false, $sValue = null, $aAttribs=array()) { |
104 | $aAttribs['name'] = $sName; |
105 | if ($bChecked) $aAttribs['checked'] = 'checked'; |
106 | if (! is_null($sValue)) $aAttribs['value'] = $sValue; |
107 | // add default css |
108 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmcheckbox'; |
109 | return addInputField('checkbox',$aAttribs); |
493b168d |
110 | } |
111 | |
112 | /** |
113 | * Form radio box |
574240f5 |
114 | * @param string $sName field name |
115 | * @param boolean $bChecked controls if field is selected |
116 | * @param string $sValue |
117 | * @param array $aAttribs (since 1.5.1) extra attributes. |
ed6d3334 |
118 | * @return string html formated radio box |
493b168d |
119 | */ |
574240f5 |
120 | function addRadioBox($sName, $bChecked = false, $sValue = null, $aAttribs=array()) { |
121 | $aAttribs['name'] = $sName; |
122 | if ($bChecked) $aAttribs['checked'] = 'checked'; |
123 | if (! is_null($sValue)) $aAttribs['value'] = $sValue; |
124 | if (! isset($aAttribs['id'])) $aAttribs['id'] = $sName . $sValue; |
125 | // add default css |
126 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmradiobox'; |
127 | return addInputField('radio', $aAttribs); |
493b168d |
128 | } |
129 | |
130 | /** |
131 | * A hidden form field. |
574240f5 |
132 | * @param string $sName field name |
133 | * @param string $sValue field value |
134 | * @param array $aAttribs (since 1.5.1) extra attributes |
ed6d3334 |
135 | * @return html formated hidden form field |
493b168d |
136 | */ |
574240f5 |
137 | function addHidden($sName, $sValue, $aAttribs=array()) { |
138 | $aAttribs['name'] = $sName; |
139 | $aAttribs['value'] = $sValue; |
140 | // add default css |
141 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmhiddenfield'; |
142 | return addInputField('hidden', $aAttribs); |
493b168d |
143 | } |
144 | |
145 | /** |
146 | * An input textbox. |
574240f5 |
147 | * @param string $sName field name |
148 | * @param string $sValue initial field value |
149 | * @param integer $iSize field size (number of characters) |
150 | * @param integer $iMaxlength maximum number of characters the user may enter |
87745b9c |
151 | * @param array $aAttribs (since 1.5.1) extra attributes - should be given |
152 | * in the form array('attribute_name' => 'attribute_value', ...) |
ed6d3334 |
153 | * @return string html formated text input field |
493b168d |
154 | */ |
574240f5 |
155 | function addInput($sName, $sValue = '', $iSize = 0, $iMaxlength = 0, $aAttribs=array()) { |
156 | $aAttribs['name'] = $sName; |
157 | $aAttribs['value'] = $sValue; |
158 | if ($iSize) $aAttribs['size'] = (int)$iSize; |
159 | if ($iMaxlength) $aAttribs['maxlength'] = (int)$iMaxlength; |
160 | // add default css |
161 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmtextfield'; |
162 | return addInputField('text', $aAttribs); |
493b168d |
163 | } |
164 | |
493b168d |
165 | /** |
166 | * Function to create a selectlist from an array. |
42b7c9d4 |
167 | * @param string $sName Field name |
168 | * @param array $aValues Field values array(key => value) results in: |
169 | * <option value="key">value</option>, |
170 | * although if $bUsekeys is FALSE, then it changes to: |
171 | * <option value="value">value</option> |
172 | * @param mixed $default The key(s) that will be selected (it is OK to pass |
173 | * in an array here in the case of multiple select lists) |
174 | * @param boolean $bUsekeys Use the keys of the array as option value or not |
175 | * @param array $aAttribs (since 1.5.1) Extra attributes |
176 | * @param boolean $bMultiple When TRUE, a multiple select list will be shown |
177 | * (OPTIONAL; default is FALSE (single select list)) |
38d93650 |
178 | * @param int $iSize Desired height of multiple select boxes |
179 | * (OPTIONAL; default is SMOPT_SIZE_NORMAL) |
180 | * (only applicable when $bMultiple is TRUE) |
02ded2ae |
181 | * |
ed6d3334 |
182 | * @return string html formated selection box |
574240f5 |
183 | * @todo add attributes argument for option tags and default css |
493b168d |
184 | */ |
38d93650 |
185 | function addSelect($sName, $aValues, $default = null, $bUsekeys = false, $aAttribs = array(), $bMultiple = FALSE, $iSize = SMOPT_SIZE_NORMAL) { |
493b168d |
186 | // only one element |
38d93650 |
187 | if (!$bMultiple && count($aValues) == 1) { |
574240f5 |
188 | $k = key($aValues); $v = array_pop($aValues); |
38d93650 |
189 | return addHidden($sName, ($bUsekeys ? $k : $v), $aAttribs) |
190 | . htmlspecialchars($v); |
493b168d |
191 | } |
192 | |
42b7c9d4 |
193 | |
194 | // make sure $default is an array, since multiple select lists |
195 | // need the chance to have more than one default... |
196 | // |
197 | if (!is_array($default)) |
198 | $default = array($default); |
199 | |
200 | |
ba556ce5 |
201 | global $oTemplate; |
ed6d3334 |
202 | |
42b7c9d4 |
203 | //FIXME: all the values in the $aAttribs list and $sName and both the keys and values in $aValues used to go thru htmlspecialchars()... I would propose that most everything that is assigned to the template should go thru that *in the template class* on its way between here and the actual template file. Otherwise we have to do something like: foreach ($aAttribs as $key => $value) $aAttribs[$key] = htmlspecialchars($value); $sName = htmlspecialchars($sName); $aNewValues = array(); foreach ($aValues as $key => $value) $aNewValues[htmlspecialchars($key)] = htmlspecialchars($value); $aValues = $aNewValues; And probably this too because it has to be matched to a value that has already been sanitized: $default = htmlspecialchars($default); (oops, watch out for when $default is an array! (multiple select lists)) |
ba556ce5 |
204 | $oTemplate->assign('aAttribs', $aAttribs); |
205 | $oTemplate->assign('aValues', $aValues); |
206 | $oTemplate->assign('bUsekeys', $bUsekeys); |
207 | $oTemplate->assign('default', $default); |
208 | $oTemplate->assign('name', $sName); |
42b7c9d4 |
209 | $oTemplate->assign('multiple', $bMultiple); |
38d93650 |
210 | $oTemplate->assign('size', $iSize); |
574240f5 |
211 | |
ba556ce5 |
212 | return $oTemplate->fetch('select.tpl'); |
493b168d |
213 | } |
214 | |
02ded2ae |
215 | /** |
216 | * Normal button |
217 | * |
218 | * Note the switched value/name parameters! |
219 | * Note also that regular buttons are not very useful unless |
220 | * used with onclick handlers, thus are only really appropriate |
221 | * if you use them after having checked if JavaScript is turned |
222 | * on by doing this: if (checkForJavascript()) ... |
223 | * |
224 | * @param string $sValue button name |
225 | * @param string $sName key name |
226 | * @param array $aAttribs extra attributes |
227 | * |
228 | * @return string html formated submit input field |
229 | * |
230 | * @since 1.5.2 |
231 | */ |
232 | function addButton($sValue, $sName = null, $aAttribs=array()) { |
233 | $aAttribs['value'] = $sValue; |
234 | if (! is_null($sName)) $aAttribs['name'] = $sName; |
235 | // add default css |
236 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmsubmitfield'; |
237 | return addInputField('button', $aAttribs); |
238 | } |
239 | |
10ff256e |
240 | /** |
241 | * Form submission button |
242 | * Note the switched value/name parameters! |
574240f5 |
243 | * @param string $sValue button name |
244 | * @param string $sName submitted key name |
245 | * @param array $aAttribs (since 1.5.1) extra attributes |
ed6d3334 |
246 | * @return string html formated submit input field |
10ff256e |
247 | */ |
574240f5 |
248 | function addSubmit($sValue, $sName = null, $aAttribs=array()) { |
249 | $aAttribs['value'] = $sValue; |
250 | if (! is_null($sName)) $aAttribs['name'] = $sName; |
251 | // add default css |
252 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmsubmitfield'; |
253 | return addInputField('submit', $aAttribs); |
10ff256e |
254 | } |
02ded2ae |
255 | |
10ff256e |
256 | /** |
ed6d3334 |
257 | * Form reset button |
574240f5 |
258 | * @param string $sValue button name |
259 | * @param array $aAttribs (since 1.5.1) extra attributes |
ed6d3334 |
260 | * @return string html formated reset input field |
10ff256e |
261 | */ |
574240f5 |
262 | function addReset($sValue, $aAttribs=array()) { |
263 | $aAttribs['value'] = $sValue; |
264 | // add default css |
265 | if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmresetfield'; |
266 | return addInputField('reset', $aAttribs); |
10ff256e |
267 | } |
268 | |
493b168d |
269 | /** |
270 | * Textarea form element. |
ba556ce5 |
271 | * |
272 | * @param string $sName field name |
273 | * @param string $sText initial field value (OPTIONAL; default empty) |
274 | * @param integer $iCols field width (number of chars) (OPTIONAL; default 40) |
275 | * @param integer $iRows field height (number of character rows) (OPTIONAL; default 10) |
276 | * @param array $aAttribs (since 1.5.1) extra attributes (OPTIONAL; default empty) |
277 | * |
ed6d3334 |
278 | * @return string html formated text area field |
ba556ce5 |
279 | * |
493b168d |
280 | */ |
574240f5 |
281 | function addTextArea($sName, $sText = '', $iCols = 40, $iRows = 10, $aAttribs = array()) { |
ba556ce5 |
282 | |
283 | // no longer accept string arguments for attribs; print |
284 | // backtrace to help people fix their code |
02ded2ae |
285 | //FIXME: throw error instead? |
ba556ce5 |
286 | if (!is_array($aAttribs)) { |
287 | echo '$aAttribs argument to addTextArea() must be an array<br /><pre>'; |
288 | debug_print_backtrace(); |
289 | echo '</pre><br />'; |
290 | exit; |
ed6d3334 |
291 | } |
ba556ce5 |
292 | |
02ded2ae |
293 | // add default css |
ba556ce5 |
294 | else if (!isset($aAttribs['class'])) $aAttribs['class'] = 'sqmtextarea'; |
295 | |
296 | global $oTemplate; |
297 | |
298 | //FIXME: all the values in the $aAttribs list as well as $sName and $sText used to go thru htmlspecialchars()... I would propose that most everything that is assigned to the template should go thru that *in the template class* on its way between here and the actual template file. Otherwise we have to do something like: foreach ($aAttribs as $key => $value) $aAttribs[$key] = htmlspecialchars($value); $sName = htmlspecialchars($sName); $sText = htmlspecialchars($sText); |
299 | $oTemplate->assign('aAttribs', $aAttribs); |
300 | $oTemplate->assign('name', $sName); |
301 | $oTemplate->assign('text', $sText); |
302 | $oTemplate->assign('cols', (int)$iCols); |
303 | $oTemplate->assign('rows', (int)$iRows); |
304 | |
305 | return $oTemplate->fetch('textarea.tpl'); |
493b168d |
306 | } |
307 | |
308 | /** |
309 | * Make a <form> start-tag. |
ba556ce5 |
310 | * |
311 | * @param string $sAction form handler URL |
312 | * @param string $sMethod http method used to submit form data. 'get' or 'post' |
313 | * @param string $sName form name used for identification (used for backward |
314 | * compatibility). Use of id is recommended instead. |
574240f5 |
315 | * @param string $sEnctype content type that is used to submit data. html 4.01 |
ba556ce5 |
316 | * defaults to 'application/x-www-form-urlencoded'. Form |
317 | * with file field needs 'multipart/form-data' encoding type. |
574240f5 |
318 | * @param string $sCharset charset that is used for submitted data |
ba556ce5 |
319 | * @param array $aAttribs (since 1.5.1) extra attributes |
320 | * |
ed6d3334 |
321 | * @return string html formated form start string |
ba556ce5 |
322 | * |
493b168d |
323 | */ |
574240f5 |
324 | function addForm($sAction, $sMethod = 'post', $sName = '', $sEnctype = '', $sCharset = '', $aAttribs = array()) { |
574240f5 |
325 | |
ba556ce5 |
326 | global $oTemplate; |
574240f5 |
327 | |
ba556ce5 |
328 | //FIXME: all the values in the $aAttribs list as well as $charset used to go thru htmlspecialchars()... I would propose that most everything that is assigned to the template should go thru that *in the template class* on its way between here and the actual template file. Otherwise we have to do something like: foreach ($aAttribs as $key => $value) $aAttribs[$key] = htmlspecialchars($value); $sCharset = htmlspecialchars($sCharset); |
329 | $oTemplate->assign('aAttribs', $aAttribs); |
330 | $oTemplate->assign('name', $sName); |
331 | $oTemplate->assign('method', $sMethod); |
332 | $oTemplate->assign('action', $sAction); |
333 | $oTemplate->assign('enctype', $sEnctype); |
334 | $oTemplate->assign('charset', $sCharset); |
493b168d |
335 | |
ba556ce5 |
336 | return $oTemplate->fetch('form.tpl'); |
493b168d |
337 | } |
ba556ce5 |
338 | |
61bd57f5 |
339 | /** |
340 | * Creates unique widget names |
341 | * |
342 | * Names are formatted as such: "send1", "send2", "send3", etc., |
343 | * where "send" in this example is what was given for $base_name |
344 | * |
345 | * @param string $base_name The name upon which to base the |
346 | * returned widget name. |
347 | * @param boolean $return_count When TRUE, this function will |
348 | * return the last number used to |
349 | * create a widget name for $base_name |
350 | * (OPTIONAL; default = FALSE). |
351 | * |
352 | * @return mixed When $return_output is FALSE, a string containing |
353 | * the unique widget name; otherwise an integer with |
354 | * the last number used to create the last widget |
355 | * name for the given $base_name (where 0 (zero) means |
356 | * that no such widgets have been created yet). |
357 | * |
4709e2f7 |
358 | * @since 1.5.2 |
61bd57f5 |
359 | * |
360 | */ |
361 | function unique_widget_name($base_name, $return_count=FALSE) |
362 | { |
363 | static $counts = array(); |
364 | |
365 | if (!isset($counts[$base_name])) |
366 | $counts[$base_name] = 0; |
367 | |
368 | if ($return_count) |
369 | return $counts[$base_name]; |
370 | |
371 | ++$counts[$base_name]; |
372 | return $base_name . $counts[$base_name]; |
373 | } |
374 | |