Commit 1bf803c8447e413c4e1ac11055cbe7dea627107e

Authored by Conrad Vermeulen
1 parent 7b9dd3ef

KTS-2178

"cross site scripting"
Updated.

Reviewed By: Kevin Fourie

git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@6919 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing 1 changed file with 122 additions and 122 deletions
lib/widgets/forms.inc.php
1 1 <?php
2 2 /**
3 3 * $Id$
4   - *
  4 + *
5 5 * The contents of this file are subject to the KnowledgeTree Public
6 6 * License Version 1.1.2 ("License"); You may not use this file except in
7 7 * compliance with the License. You may obtain a copy of the License at
8 8 * http://www.knowledgetree.com/KPL
9   - *
  9 + *
10 10 * Software distributed under the License is distributed on an "AS IS"
11 11 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
12 12 * See the License for the specific language governing rights and
... ... @@ -17,9 +17,9 @@
17 17 * (ii) the KnowledgeTree copyright notice
18 18 * in the same form as they appear in the distribution. See the License for
19 19 * requirements.
20   - *
  20 + *
21 21 * The Original Code is: KnowledgeTree Open Source
22   - *
  22 + *
23 23 * The Initial Developer of the Original Code is The Jam Warehouse Software
24 24 * (Pty) Ltd, trading as KnowledgeTree.
25 25 * Portions created by The Jam Warehouse Software (Pty) Ltd are Copyright
... ... @@ -31,7 +31,7 @@
31 31 /* handle basic machinery for form handling, including working with
32 32 * widgets, sessions and validation
33 33 */
34   -
  34 +
35 35 require_once(KT_LIB_DIR . "/widgets/widgetfactory.inc.php");
36 36 require_once(KT_LIB_DIR . "/validation/validatorfactory.inc.php");
37 37  
... ... @@ -39,11 +39,11 @@ class KTForm {
39 39 // serialisation info
40 40 var $_kt_form_name;
41 41 var $sIdentifier; // a simple identifier.
42   -
  42 +
43 43 // visual options
44 44 var $sLabel;
45 45 var $sDescription;
46   -
  46 +
47 47 // core storage options
48 48 var $_widgets; // what widgets get stored
49 49 var $_validators; // validators
... ... @@ -59,12 +59,12 @@ class KTForm {
59 59 var $_errors;
60 60 var $_method;
61 61 var $_noframe;
62   -
  62 +
63 63 var $_oVF;
64 64 var $_oWF;
65 65  
66   -
67   -
  66 +
  67 +
68 68 // we don't use a constructor here, rather use aOptions
69 69 function setOptions($aOptions) {
70 70 // we grab the "context" dispatcher(ish) object here
... ... @@ -72,16 +72,16 @@ class KTForm {
72 72 $this->_context =& $context;
73 73  
74 74 // form identifier (namespace)
75   - $this->sIdentifier = KTUtil::arrayGet($aOptions, 'identifier','kt.default');
  75 + $this->sIdentifier = KTUtil::arrayGet($aOptions, 'identifier','kt.default');
76 76 // form name
77   - $this->_kt_form_name = KTUtil::arrayGet($aOptions, '_kt_form_name',
  77 + $this->_kt_form_name = KTUtil::arrayGet($aOptions, '_kt_form_name',
78 78 $this->generateFormName($this->sIdentifier), false);
79 79  
80   -
  80 +
81 81 // form labelling
82 82 $this->sLabel = KTUtil::arrayGet($aOptions, 'label');
83 83 $this->sDescription = KTUtil::arrayGet($aOptions, 'description');
84   -
  84 +
85 85 // actions
86 86 $this->_action = KTUtil::arrayGet($aOptions, 'action');
87 87 $qs = KTUtil::arrayGet($aOptions, 'actionparams','');
... ... @@ -91,7 +91,7 @@ class KTForm {
91 91 $this->_enctype="multipart/form-data";
92 92 }
93 93 }
94   -
  94 +
95 95 $targeturl = KTUtil::arrayGet($aOptions, 'targeturl', false);
96 96 if($targeturl === false) {
97 97 $this->_actionurl = KTUtil::addQueryStringSelf($qs);
... ... @@ -114,43 +114,43 @@ class KTForm {
114 114 }
115 115  
116 116 $this->_noframe = KTUtil::arrayGet($aOptions, 'noframe', false);
117   -
  117 +
118 118 // cancel
119 119 // there are a few options here:
120 120 // 1. cancel_action
121 121 // 2. cancel_url
122 122 $cancel_action = KTUtil::arrayGet($aOptions, 'cancel_action');
123 123 $cancel_url = KTUtil::arrayGet($aOptions, 'cancel_url');
124   -
  124 +
125 125 if (!empty($cancel_action)) {
126   - $this->bCancel = true;
  126 + $this->bCancel = true;
127 127 // there are two cases here - if we have a context, we can
128 128 // use the meldPersistQuery to create the url.
129 129 if (!is_null($context)) {
130   - $sQuery = $context->meldPersistQuery("",
  130 + $sQuery = $context->meldPersistQuery("",
131 131 $cancel_action);
132   - $this->_cancelurl =
  132 + $this->_cancelurl =
133 133 KTUtil::addQueryString($_SERVER['PHP_SELF'], $sQuery);
134 134 } else {
135 135 // give it a try using addQSSelf
136 136 $this->_cancelurl = KTUtil::addQueryStringSelf(
137   - sprintf('%s=%s', $this->_event, $cancel_action));
  137 + sprintf('%s=%s', $this->_event, $cancel_action));
138 138 }
139   -
140   -
  139 +
  140 +
141 141 } else if (!empty($cancel_url)) {
142   - $this->bCancel = true;
  142 + $this->bCancel = true;
143 143 $this->_cancelurl = $cancel_url;
144 144 } else {
145 145 $this->bCancel = false;
146 146 }
147   -
  147 +
148 148 // FIXME process extra arguments more intelligently
149 149 $default_args = array();
150 150 if (!is_null($this->_context)) {
151 151 $default_args = $this->_context->meldPersistQuery("","",true);
152 152 }
153   - $this->_extraargs = KTUtil::arrayGet($aOptions,
  153 + $this->_extraargs = KTUtil::arrayGet($aOptions,
154 154 'extraargs', $default_args);
155 155  
156 156 // method
... ... @@ -158,7 +158,7 @@ class KTForm {
158 158  
159 159 $this->_extraargs['postReceived'] = 1;
160 160 }
161   -
  161 +
162 162 function getWidget(&$aInfo) {
163 163 if (is_null($this->_oWF)) {
164 164 $this->_oWF =& KTWidgetFactory::getSingleton();
... ... @@ -167,13 +167,13 @@ class KTForm {
167 167 if (is_null($aInfo)) {
168 168 $widget = null;
169 169 } else if (is_object($aInfo)) {
170   -
  170 +
171 171 // assume this is a fully configured object
172 172 $widget =& $aInfo;
173 173 } else {
174 174 $namespaceOrObject = $aInfo[0];
175 175 $config = (array) $aInfo[1];
176   -
  176 +
177 177 $widget =& $this->_oWF->get($namespaceOrObject, $config);
178 178 }
179 179  
... ... @@ -183,10 +183,10 @@ class KTForm {
183 183 function getValidator($aInfo) {
184 184 if (is_null($this->_oVF)) {
185 185 $this->_oVF =& KTValidatorFactory::getSingleton();
186   - }
187   -
  186 + }
  187 +
188 188 $validator = null;
189   -
  189 +
190 190 // we don't want to expose the factory stuff to the user - its an
191 191 // arbitrary distinction to the user. Good point from NBM ;)
192 192 if (is_null($aInfo)) {
... ... @@ -197,29 +197,29 @@ class KTForm {
197 197 } else {
198 198 $namespaceOrObject = $aInfo[0];
199 199 $config = (array) $aInfo[1];
200   -
  200 +
201 201 $validator =& $this->_oVF->get($namespaceOrObject, $config);
202 202 }
203   -
  203 +
204 204 return $validator;
205 205 }
206   -
  206 +
207 207 // set the "form widgets" that will be used.
208 208 // these are pushed into the "data" component
209 209 function setWidgets($aWidgets) {
210 210 $this->_widgets = array();
211   -
  211 +
212 212 if (is_null($this->_oWF)) {
213 213 $this->_oWF =& KTWidgetFactory::getSingleton();
214 214 }
215   -
  215 +
216 216 $this->addWidgets($aWidgets);
217 217 }
218   -
  218 +
219 219 function addWidgets($aWidgets) {
220   - foreach ($aWidgets as $aInfo) {
  220 + foreach ($aWidgets as $aInfo) {
221 221 $widget = $this->getWidget($aInfo);
222   -
  222 +
223 223 if (is_null($widget)) {
224 224 continue;
225 225 } else {
... ... @@ -227,51 +227,51 @@ class KTForm {
227 227 }
228 228 }
229 229 }
230   -
  230 +
231 231 function setValidators($aValidators) {
232 232 $this->_validators = array();
233   -
  233 +
234 234 if (is_null($this->_oVF)) {
235 235 $this->_oVF =& KTValidatorFactory::getSingleton();
236   - }
237   -
  236 + }
  237 +
238 238 $this->addValidators($aValidators);
239 239 }
240   -
  240 +
241 241 function addValidators($aValidators) {
242 242 // we don't want to expose the factory stuff to the user - its an
243 243 // arbitrary distinction to the user. Good point from NBM ;)
244 244 foreach ($aValidators as $aInfo) {
245 245 $validator = $this->getValidator($aInfo);
246   -
  246 +
247 247 if (is_null($validator)) {
248 248 continue;
249 249 } else {
250 250 $this->_validators[] = $validator;
251 251 }
252   - }
  252 + }
253 253 }
254   -
  254 +
255 255 function addValidator($aInfo) {
256 256 $validator = $this->getValidator($aInfo);
257   -
  257 +
258 258 if (is_null($validator)) {
259 259 return false;
260 260 } else {
261 261 $this->_validators[] =& $validator;
262   - }
  262 + }
263 263 }
264   -
  264 +
265 265 function addWidget($aInfo) {
266 266 $widget = $this->getWidget($aInfo);
267   -
  267 +
268 268 if (is_null($widget)) {
269 269 return false;
270 270 } else {
271 271 $this->_widgets[] =& $widget;
272   - }
273   - }
274   -
  272 + }
  273 + }
  274 +
275 275 function addInitializedWidget($oWidget) {
276 276 $this->_widgets[] = $oWidget;
277 277 }
... ... @@ -279,10 +279,10 @@ class KTForm {
279 279 function render() {
280 280 $sWidgets = $this->renderWidgets();
281 281 $sButtons = $this->renderButtons();
282   -
  282 +
283 283 return $this->renderContaining($sWidgets . ' ' . $sButtons);
284 284 }
285   -
  285 +
286 286 function renderPage($sTitle = null, $sDescription = null) {
287 287 if ($sTitle == null) {
288 288 $sTitle = $this->sLabel;
... ... @@ -292,35 +292,35 @@ class KTForm {
292 292 if (!is_null($sDescription)) {
293 293 $sHelpText = sprintf('<p class="descriptiveText">%s</p>', $sDescription);
294 294 }
295   - return sprintf('<h2>%s</h2> %s %s', $sTitle, $sHelpText, $pageval);
296   - }
297   -
  295 + return sprintf('<h2>%s</h2> %s %s', sanitizeForHTML($sTitle), $sHelpText, $pageval);
  296 + }
  297 +
298 298 function getErrors() {
299 299 $aErrors = array();
300   - $old_data = KTUtil::arrayGet((array) $_SESSION['_kt_old_data'],
  300 + $old_data = KTUtil::arrayGet((array) $_SESSION['_kt_old_data'],
301 301 $this->_kt_form_name, array());
302 302 if (KTUtil::arrayGet($old_data, 'identifier') == $this->sIdentifier) {
303 303 $aErrors = (array) unserialize(KTUtil::arrayGet($old_data, 'errors'));
304   - }
  304 + }
305 305 return $aErrors;
306 306 }
307   -
  307 +
308 308 function renderWidgets() {
309 309 if (empty($this->_widgets)) {
310 310 return '&nbsp;';
311 311 }
312   -
  312 +
313 313 // do this all at the *last* possible moment
314 314 // now we need to do two things:
315 315 //
316   - // 1. inform each "widget" that it needs to wrap itself inside
  316 + // 1. inform each "widget" that it needs to wrap itself inside
317 317 // the "data" var
318   - // 2. replace the widget's default values with the ones from the
  318 + // 2. replace the widget's default values with the ones from the
319 319 // failed request, as appropriate.
320 320 $bUseOld = false;
321 321 $aOldData = array();
322 322 $aErrors = array();
323   - $old_data = KTUtil::arrayGet((array) $_SESSION['_kt_old_data'],
  323 + $old_data = KTUtil::arrayGet((array) $_SESSION['_kt_old_data'],
324 324 $this->_kt_form_name, array());
325 325 if (KTUtil::arrayGet($old_data, 'identifier') == $this->sIdentifier) {
326 326 $bUseOld = true;
... ... @@ -331,7 +331,7 @@ class KTForm {
331 331 }
332 332 $aErrors = (array) unserialize(KTUtil::arrayGet($old_data, 'errors'));
333 333 }
334   -
  334 +
335 335 foreach ($this->_widgets as $k => $v) {
336 336 if (PEAR::isError($v)) {
337 337 continue; // error, handle it in render.
... ... @@ -339,16 +339,16 @@ class KTForm {
339 339 $widget =& $this->_widgets[$k]; // reference needed since we're changing them
340 340 $widget->wrapName('data');
341 341 if ($bUseOld) {
342   - $widget->setDefault(KTUtil::arrayGet($aOldData, $widget->getBasename(),
  342 + $widget->setDefault(KTUtil::arrayGet($aOldData, $widget->getBasename(),
343 343 $widget->getDefault(), false));
344 344 $widget->setErrors(KTUtil::arrayGet($aErrors, $widget->getBasename()));
345 345 }
346 346 }
347   -
  347 +
348 348 // too much overhead by half to use a template here
349 349 // so we do it the "old fashioned" way.
350 350 $rendered = array();
351   -
  351 +
352 352 foreach ($this->_widgets as $v) {
353 353 if (PEAR::isError($v)) {
354 354 $rendered[] = sprintf(_kt('<div class="ktError"><p>Unable to show widget &mdash; %s</p></div>'), $v->getMessage());
... ... @@ -356,45 +356,45 @@ class KTForm {
356 356 $rendered[] = $v->render();
357 357 }
358 358 }
359   -
  359 +
360 360 return implode(' ', $rendered);
361 361 }
362   -
  362 +
363 363 function renderButtons() {
364 364 $oKTTemplating =& KTTemplating::getSingleton();
365 365 $oTemplate = $oKTTemplating->loadTemplate('ktcore/forms/buttons');
366   -
  366 +
367 367 // now do the render.
368 368 $oTemplate->setData(array(
369   - 'context' => &$this,
  369 + 'context' => &$this,
370 370 ));
371   -
  371 +
372 372 return $oTemplate->render();
373 373 }
374   -
  374 +
375 375 function renderContaining() {
376   -
  376 +
377 377 $args = func_get_args();
378 378 $sInner = implode(' ', $args);
379   -
  379 +
380 380 $oKTTemplating =& KTTemplating::getSingleton();
381 381 $oTemplate = $oKTTemplating->loadTemplate('ktcore/forms/outerform');
382   -
  382 +
383 383 // remove inner "action" var from extraargs
384 384 // if its there at all.
385 385 unset($this->_extraargs[$this->_event]);
386 386 $this->_extraargs['_kt_form_name'] = $this->_kt_form_name;
387   -
  387 +
388 388 // now do the render.
389 389 $oTemplate->setData(array(
390   - 'context' => &$this,
  390 + 'context' => &$this,
391 391 'inner' => $sInner,
392 392 ));
393   -
  393 +
394 394 return $oTemplate->render();
395 395 }
396   -
397   - function generateFormName($sIdentifier = null) {
  396 +
  397 + function generateFormName($sIdentifier = null) {
398 398 if (!is_null($sIdentifier)) {
399 399 // try use the existing one from the request.
400 400 $existing = KTUtil::arrayGet($_REQUEST, '_kt_form_name');
... ... @@ -409,62 +409,62 @@ class KTForm {
409 409 }
410 410 return KTUtil::randomString(32); // unique 32 char string
411 411 }
412   -
  412 +
413 413 function validate() {
414 414 // we first ask each widget to pull its data out.
415 415 // while we do that, we create the storage set for the session
416 416 // that widgets can call on later.
417   -
  417 +
418 418 $raw_data = KTUtil::arrayGet($_REQUEST, 'data');
419 419 $processed_data = array();
420 420 foreach ($this->_widgets as $oWidget) {
421 421 if (PEAR::isError($oWidget)) {
422 422 continue;
423 423 }
424   -
425   - // widgets are expected to place their data in the "basename"
  424 +
  425 + // widgets are expected to place their data in the "basename"
426 426 // entry in the processed data area
427 427 //
428 428 // they should also be able to reconstruct their inputs from this
429 429 // since its what they get later.
430   -
  430 +
431 431 $res = $oWidget->process($raw_data);
432 432 $processed_data = kt_array_merge($processed_data, $res);
433 433 }
434   -
  434 +
435 435 // before we validate ANYTHING we store data into the session
436 436  
437 437 $store_data = array(); // we only want to store serialized values here
438 438 foreach ($processed_data as $k => $v) {
439 439 $store_data[$k] = serialize($v);
440 440 }
441   -
  441 +
442 442 $_SESSION['_kt_old_data'][$this->_kt_form_name]['data'] = serialize($store_data);
443   - $_SESSION['_kt_old_data'][$this->_kt_form_name]['identifier'] =
444   - $this->sIdentifier;
445   - $_SESSION['_kt_old_data'][$this->_kt_form_name]['created'] =
  443 + $_SESSION['_kt_old_data'][$this->_kt_form_name]['identifier'] =
  444 + $this->sIdentifier;
  445 + $_SESSION['_kt_old_data'][$this->_kt_form_name]['created'] =
446 446 getCurrentDateTime();
447   -
  447 +
448 448 $results = array();
449 449 $errors = array();
450   -
  450 +
451 451 // some things can be checked by the actual widgets involved. These
452 452 // are obvious (e.g. required) and shouldn't require the developer to
453 453 // think about them.
454 454 //
455 455 // to accomplish this, we call each widget's "getValidators" method.
456   - //
  456 + //
457 457 // note that autovalidation can be turned off for a widget by passing
458 458 // "autovalidate" => "false" in the widget's config.
459   -
  459 +
460 460 $extra_validators = array();
461 461 foreach ($this->_widgets as $oWidget) {
462   - if (PEAR::isError($oWidget)) {
  462 + if (PEAR::isError($oWidget)) {
463 463 continue;
464 464 }
465   -
  465 +
466 466 $res = $oWidget->getValidators();
467   -
  467 +
468 468 if (!is_null($res)) {
469 469 if (is_array($res)) {
470 470 $extra_validators = kt_array_merge($extra_validators, $res);
... ... @@ -473,23 +473,23 @@ class KTForm {
473 473 }
474 474 }
475 475 }
476   -
  476 +
477 477 $validators = kt_array_merge($extra_validators, $this->_validators);
478   -
  478 +
479 479 foreach ($validators as $oValidator) {
480 480 if (PEAR::isError($oValidator)) {
481 481 // don't bother with broken validators, but warn the user/dev
482 482 $errors['_kt_global'][] = $oValidator->getMessage();
483   - continue;
  483 + continue;
484 484 }
485   -
  485 +
486 486 $res = $oValidator->validate($processed_data);
487   -
  487 +
488 488 // results comes out with a set of names and values.
489 489 // these *shouldn't* overlap, so just merge them
490 490 $extra_results = KTUtil::arrayGet($res, 'results', array());
491 491 $results = kt_array_merge($results, $extra_results);
492   -
  492 +
493 493 // errors *can* overlap
494 494 // the format is:
495 495 // basename => array(errors)
... ... @@ -501,27 +501,27 @@ class KTForm {
501 501 $extra_errors = KTUtil::arrayGet($res, 'errors', array());
502 502 foreach ($extra_errors as $varname => $aErrors) {
503 503 if (is_string($aErrors)) {
504   - $errors[$varname][] = $aErrors;
  504 + $errors[$varname][] = $aErrors;
505 505 } else {
506 506 $errors[$varname] = kt_array_merge($errors[$varname], $aErrors);
507 507 }
508 508 }
509 509 }
510   -
  510 +
511 511 $this->_errors = $errors; // store for later use without unserialising
512 512 if (!empty($errors)) {
513   - $_SESSION['_kt_old_data'][$this->_kt_form_name]['errors'] =
  513 + $_SESSION['_kt_old_data'][$this->_kt_form_name]['errors'] =
514 514 serialize($errors);
515   - }
516   -
  515 + }
  516 +
517 517 //var_dump($errors); exit(0);
518   -
  518 +
519 519 return array(
520 520 'errors' => $errors,
521 521 'results' => $results,
522 522 );
523 523 }
524   -
  524 +
525 525 function handleError($sGlobalError = null, $aSimplerErrors = null) {
526 526 if (!is_null($sGlobalError)) {
527 527 $this->_errors['_kt_global'][] = $sGlobalError;
... ... @@ -531,23 +531,23 @@ class KTForm {
531 531 $this->_errors[$k] = kt_array_merge($this->_errors[$k], $v);
532 532 }
533 533 // since we've changed them, update the stored version
534   - $_SESSION['_kt_old_data'][$this->_kt_form_name]['errors'] =
535   - serialize($this->_errors);
  534 + $_SESSION['_kt_old_data'][$this->_kt_form_name]['errors'] =
  535 + serialize($this->_errors);
536 536 }
537 537 if (is_array($this->_errors)) {
538 538 $global_errors = KTUtil::arrayGet($this->_errors, '_kt_global', array());
539 539 $_SESSION['KTErrorMessage'] = kt_array_merge($_SESSION['KTErrorMessage'], $global_errors);
540 540 }
541   -
  541 +
542 542 if (!empty($this->_failaction) && !is_null($this->_context)) {
543   - $this->_context->errorRedirectTo($this->_failaction,
544   - _kt("Please correct the errors indicated."),
  543 + $this->_context->errorRedirectTo($this->_failaction,
  544 + _kt("Please correct the errors indicated."),
545 545 sprintf("_kt_form_name=%s",$this->_kt_form_name));
546 546 exit(0);
547 547 } else if ($this->_failurl){
548 548 redirect(KTUtil::addQueryString($this->_failurl,
549   - sprintf("_kt_form_name=%s",$this->_kt_form_name)));
550   - exit(0);
  549 + sprintf("_kt_form_name=%s",$this->_kt_form_name)));
  550 + exit(0);
551 551 } else {
552 552 return '<div class="ktError"><p>' . _kt("An error occured, and no error handlers were configured.") . '</p></div>';
553 553 exit(0);
... ...