~ubuntu-branches/ubuntu/trusty/phpmyadmin/trusty

« back to all changes in this revision

Viewing changes to setup/lib/FormDisplay.class.php

  • Committer: Bazaar Package Importer
  • Author(s): Thijs Kinkhorst
  • Date: 2009-02-16 17:58:28 UTC
  • mfrom: (13.1.4 jaunty)
  • Revision ID: james.westby@ubuntu.com-20090216175828-d2dllrukk9kecv4k
Tags: 4:3.1.2-2
* Upload to unstable.
* [INTL:es] Spanish debconf template update (Closes: #513690).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Form management class, displays and processes forms
 
4
 *
 
5
 * Explanation of used terms:
 
6
 * o work_path - original field path, eg. Servers/4/verbose
 
7
 * o system_path - work_path modified so that it points to the first server, eg. Servers/1/verbose
 
8
 * o translated_path - work_path modified for HTML field name, a path with
 
9
 *                     slashes changed to hyphens, eg. Servers-4-verbose
 
10
 *
 
11
 * @package    phpMyAdmin-setup
 
12
 * @author     Piotr Przybylski <piotrprz@gmail.com>
 
13
 * @license    http://www.gnu.org/licenses/gpl.html GNU GPL 2.0
 
14
 * @version    $Id: FormDisplay.class.php 11673 2008-10-23 11:09:33Z crackpl $
 
15
 */
 
16
 
 
17
require_once './setup/lib/FormDisplay.tpl.php';
 
18
require_once './setup/lib/validate.lib.php';
 
19
require_once './libraries/js_escape.lib.php';
 
20
 
 
21
/**
 
22
 * Form management class, displays and processes forms
 
23
 */
 
24
class FormDisplay
 
25
{
 
26
    /**
 
27
     * Form list
 
28
     * @var array
 
29
     */
 
30
    private $forms = array();
 
31
 
 
32
    /**
 
33
     * Stores validation errors, indexed by paths
 
34
     * [ Form_name ] is an array of form errors
 
35
     * [path] is a string storing error associated with single field
 
36
     * @var array
 
37
     */
 
38
    private $errors = array();
 
39
 
 
40
    /**
 
41
     * Paths changed so that they can be used as HTML ids, indexed by paths
 
42
     * @var array
 
43
     */
 
44
    private $translated_paths = array();
 
45
 
 
46
    /**
 
47
     * Server paths change indexes so we define maps from current server
 
48
     * path to the first one, indexed by work path
 
49
     * @var array
 
50
     */
 
51
    private $system_paths = array();
 
52
 
 
53
    /**
 
54
     * Language strings which will be sent to PMA_messages JS variable
 
55
     * Will be looked up in $GLOBALS: str{value} or strSetup{value}
 
56
     * @var array
 
57
     */
 
58
    private $js_lang_strings = array('error_nan_p', 'error_nan_nneg',
 
59
        'error_incorrect_port');
 
60
 
 
61
    /**
 
62
     * Tells whether forms have been validated
 
63
     * @var bool
 
64
     */
 
65
    private $is_valdiated = true;
 
66
 
 
67
    /**
 
68
     * Registers form in form manager
 
69
     *
 
70
     * @param string $form_name
 
71
     * @param int    $server_id 0 if new server, validation; >= 1 if editing a server
 
72
     */
 
73
    public function registerForm($form_name, $server_id = null)
 
74
    {
 
75
        $this->forms[$form_name] = new Form($form_name, $server_id);
 
76
        $this->is_valdiated = false;
 
77
        foreach ($this->forms[$form_name]->fields as $path) {
 
78
            $work_path = $server_id === null
 
79
                ? $path
 
80
                : str_replace('Servers/1/', "Servers/$server_id/", $path);
 
81
            $this->system_paths[$work_path] = $path;
 
82
            $this->translated_paths[$work_path] = str_replace('/', '-', $work_path);
 
83
        }
 
84
    }
 
85
 
 
86
    /**
 
87
     * Processes forms, returns true on successful save
 
88
     *
 
89
     * @param  bool  $allow_partial_save  allows for partial form saving on failed validation
 
90
     * @return boolean
 
91
     */
 
92
    public function process($allow_partial_save = true)
 
93
    {
 
94
        // gather list of forms to save
 
95
        if (!isset($_POST['submit_save'])) {
 
96
            return false;
 
97
        }
 
98
 
 
99
        // save forms
 
100
        if (count($this->forms) > 0) {
 
101
            return $this->save(array_keys($this->forms), $allow_partial_save);
 
102
        }
 
103
        return false;
 
104
    }
 
105
 
 
106
    /**
 
107
     * Runs validation for all registered forms
 
108
     */
 
109
    private function _validate()
 
110
    {
 
111
        if ($this->is_valdiated) {
 
112
            return;
 
113
        }
 
114
 
 
115
        $cf = ConfigFile::getInstance();
 
116
        $paths = array();
 
117
        $values = array();
 
118
        foreach ($this->forms as $form) {
 
119
            /* @var $form Form */
 
120
            $paths[] = $form->name;
 
121
            // collect values and paths
 
122
            foreach ($form->fields as $path) {
 
123
                $work_path = array_search($path, $this->system_paths);
 
124
                $values[$path] = $cf->getValue($work_path);
 
125
                $paths[] = $path;
 
126
            }
 
127
        }
 
128
 
 
129
        // run validation
 
130
        $errors = validate($paths, $values, false);
 
131
 
 
132
        // change error keys from canonical paths to work paths
 
133
        if (is_array($errors) && count($errors) > 0) {
 
134
            $this->errors = array();
 
135
            foreach ($errors as $path => $error_list) {
 
136
                $work_path = array_search($path, $this->system_paths);
 
137
                // field error
 
138
                if (!$work_path) {
 
139
                    // form error, fix path
 
140
                    $work_path = $path;
 
141
                }
 
142
                $this->errors[$work_path] = $error_list;
 
143
            }
 
144
        }
 
145
        $this->is_valdiated = true;
 
146
    }
 
147
 
 
148
 
 
149
    /**
 
150
     * Outputs HTML for forms
 
151
     *
 
152
     * @param bool $tabbed_form
 
153
     * @param bool   $show_restore_default  whether show "restore default" button besides the input field
 
154
     */
 
155
    public function display($tabbed_form = false, $show_restore_default = false)
 
156
    {
 
157
        static $js_lang_sent = false;
 
158
 
 
159
        $js = array();
 
160
        $js_default = array();
 
161
        $tabbed_form = $tabbed_form && (count($this->forms) > 1);
 
162
        $validators = ConfigFile::getInstance()->getDbEntry('_validators');
 
163
 
 
164
        display_form_top();
 
165
 
 
166
        if ($tabbed_form) {
 
167
            $tabs = array();
 
168
            foreach ($this->forms as $form) {
 
169
                $tabs[$form->name] = PMA_lang("Form_$form->name");
 
170
            }
 
171
            display_tabs_top($tabs);
 
172
        }
 
173
 
 
174
        // valdiate only when we aren't displaying a "new server" form
 
175
        $is_new_server = false;
 
176
        foreach ($this->forms as $form) {
 
177
            /* @var $form Form */
 
178
            if ($form->index === 0) {
 
179
                $is_new_server = true;
 
180
                break;
 
181
            }
 
182
        }
 
183
        if (!$is_new_server) {
 
184
            $this->_validate();
 
185
        }
 
186
 
 
187
        // display forms
 
188
        foreach ($this->forms as $form) {
 
189
            /* @var $form Form */
 
190
            $form_desc = isset($GLOBALS["strSetupForm_{$form->name}_desc"])
 
191
                ? PMA_lang("Form_{$form->name}_desc")
 
192
                : '';
 
193
            $form_errors = isset($this->errors[$form->name])
 
194
                ? $this->errors[$form->name] : null;
 
195
            display_fieldset_top(PMA_lang("Form_$form->name"),
 
196
                $form_desc, $form_errors, array('id' => $form->name));
 
197
 
 
198
            foreach ($form->fields as $field => $path) {
 
199
                $work_path = array_search($path, $this->system_paths);
 
200
                $translated_path = $this->translated_paths[$work_path];
 
201
                // display input
 
202
                $this->_displayFieldInput($form, $field, $path, $work_path,
 
203
                    $translated_path, $show_restore_default, $js_default);
 
204
                // register JS validators for this field
 
205
                if (isset($validators[$path])) {
 
206
                    js_validate($translated_path, $validators[$path], $js);
 
207
                }
 
208
            }
 
209
            display_fieldset_bottom();
 
210
        }
 
211
 
 
212
        if ($tabbed_form) {
 
213
            display_tabs_bottom();
 
214
        }
 
215
        display_form_bottom();
 
216
 
 
217
        // if not already done, send strings used for valdiation to JavaScript
 
218
        if (!$js_lang_sent) {
 
219
            $js_lang_sent = true;
 
220
            $js_lang = array();
 
221
            foreach ($this->js_lang_strings as $str) {
 
222
                $lang = isset($GLOBALS["strSetup$str"])
 
223
                    ? $GLOBALS["strSetup$str"]
 
224
                    : filter_input($GLOBALS["str$str"]); // null if not set
 
225
                $js_lang[] = "'$str': '" . PMA_jsFormat($lang, false) . '\'';
 
226
            }
 
227
            $js[] = '$extend(PMA_messages, {' . implode(",\n\t", $js_lang) . '})';
 
228
        }
 
229
 
 
230
        $js[] = '$extend(defaultValues, {' . implode(",\n\t", $js_default) . '})';
 
231
        display_js($js);
 
232
    }
 
233
 
 
234
    /**
 
235
     * Prepares data for input field display and outputs HTML code
 
236
     *
 
237
     * @param Form   $form
 
238
     * @param string $field                 field name as it appears in $form
 
239
     * @param string $system_path           field path, eg. Servers/1/verbose
 
240
     * @param string $work_path             work path, eg. Servers/4/verbose
 
241
     * @param string $translated_path       work path changed so that it can be used as XHTML id
 
242
     * @param bool   $show_restore_default  whether show "restore default" button besides the input field
 
243
     * @param array  &$js_default           array which stores JavaScript code to be displayed
 
244
     */
 
245
    private function _displayFieldInput(Form $form, $field, $system_path, $work_path,
 
246
        $translated_path, $show_restore_default, array &$js_default)
 
247
    {
 
248
        $name = PMA_lang_name($system_path);
 
249
        $description = PMA_lang_desc($system_path);
 
250
 
 
251
        $cf = ConfigFile::getInstance();
 
252
        $value = $cf->get($work_path);
 
253
        $value_default = $cf->getDefault($system_path);
 
254
        $value_is_default = false;
 
255
        if ($value === null || $value === $value_default) {
 
256
            $value = $value_default;
 
257
            $value_is_default = true;
 
258
        }
 
259
 
 
260
        $opts = array(
 
261
            'doc' => $this->getDocLink($system_path),
 
262
            'wiki' =>  $this->getWikiLink($system_path),
 
263
            'show_restore_default' => $show_restore_default);
 
264
        if (isset($form->default[$system_path])) {
 
265
            $opts['setvalue'] = $form->default[$system_path];
 
266
        }
 
267
 
 
268
        if (isset($this->errors[$work_path])) {
 
269
            $opts['errors'] = $this->errors[$work_path];
 
270
        }
 
271
        switch ($form->getOptionType($field)) {
 
272
            case 'string':
 
273
                $type = 'text';
 
274
                break;
 
275
            case 'double':
 
276
                $type = 'text';
 
277
                break;
 
278
            case 'integer':
 
279
                $type = 'text';
 
280
                break;
 
281
            case 'boolean':
 
282
                $type = 'checkbox';
 
283
                break;
 
284
            case 'select':
 
285
                $type = 'select';
 
286
                $opts['values'] = array();
 
287
                $values = $form->getOptionValueList($form->fields[$field]);
 
288
                foreach ($values as $v) {
 
289
                    $opts['values'][$v] = $v;
 
290
                }
 
291
                break;
 
292
            case 'array':
 
293
                $type = 'list';
 
294
                $value = (array) $value;
 
295
                $value_default = (array) $value_default;
 
296
                break;
 
297
            case 'NULL':
 
298
                trigger_error("Field $system_path has no type", E_USER_WARNING);
 
299
                return;
 
300
        }
 
301
 
 
302
        // TrustedProxies requires changes before displaying
 
303
        if ($system_path == 'TrustedProxies') {
 
304
            foreach ($value as $ip => &$v) {
 
305
                if (!preg_match('/^-\d+$/', $ip)) {
 
306
                    $v = $ip . ': ' . $v;
 
307
                }
 
308
            }
 
309
        }
 
310
 
 
311
        // send default value to form's JS
 
312
        $js_line = '\'' . $translated_path . '\': ';
 
313
        switch ($type) {
 
314
            case 'text':
 
315
                $js_line .= '\'' . PMA_escapeJsString($value_default) . '\'';
 
316
                break;
 
317
            case 'checkbox':
 
318
                $js_line .= $value_default ? 'true' : 'false';
 
319
                break;
 
320
            case 'select':
 
321
                $value_default_js = is_bool($value_default)
 
322
                    ? (int) $value_default
 
323
                    : $value_default;
 
324
                $js_line .= '[\'' . PMA_escapeJsString($value_default_js) . '\']';
 
325
                break;
 
326
            case 'list':
 
327
                $js_line .= '\'' . PMA_escapeJsString(implode("\n", $value_default)) . '\'';
 
328
                break;
 
329
        }
 
330
        $js_default[] = $js_line;
 
331
 
 
332
        display_input($translated_path, $name, $description, $type,
 
333
            $value, $value_is_default, $opts);
 
334
    }
 
335
 
 
336
    /**
 
337
     * Displays errors
 
338
     */
 
339
    public function displayErrors()
 
340
    {
 
341
        $this->_validate();
 
342
        if (count($this->errors) == 0) {
 
343
            return;
 
344
        }
 
345
 
 
346
        foreach ($this->errors as $system_path => $error_list) {
 
347
            if (isset($this->system_paths[$system_path])) {
 
348
                $path = $this->system_paths[$system_path];
 
349
                $name = PMA_lang_name($path);
 
350
            } else {
 
351
                $name = $GLOBALS["strSetupForm_$system_path"];
 
352
            }
 
353
            display_errors($name, $error_list);
 
354
        }
 
355
    }
 
356
 
 
357
    /**
 
358
     * Reverts erroneous fields to their default values
 
359
     */
 
360
    public function fixErrors()
 
361
    {
 
362
        $this->_validate();
 
363
        if (count($this->errors) == 0) {
 
364
            return;
 
365
        }
 
366
 
 
367
        $cf = ConfigFile::getInstance();
 
368
        foreach (array_keys($this->errors) as $work_path) {
 
369
            if (!isset($this->system_paths[$work_path])) {
 
370
                continue;
 
371
            }
 
372
            $canonical_path = $this->system_paths[$work_path];
 
373
            $cf->set($work_path, $cf->getDefault($canonical_path));
 
374
        }
 
375
    }
 
376
 
 
377
    /**
 
378
     * Validates select field and casts $value to correct type
 
379
     *
 
380
     * @param  string  $value
 
381
     * @param  array   $allowed
 
382
     * @return bool
 
383
     */
 
384
    private function _validateSelect(&$value, array $allowed)
 
385
    {
 
386
        foreach ($allowed as $v) {
 
387
          if ($value == $v) {
 
388
              settype($value, gettype($v));
 
389
              return true;
 
390
          }
 
391
        }
 
392
        return false;
 
393
    }
 
394
 
 
395
    /**
 
396
     * Validates and saves form data to session
 
397
     *
 
398
     * @param  array|string  $forms               array of form names
 
399
     * @param  bool          $allow_partial_save  allows for partial form saving on failed validation
 
400
     * @return boolean  true on success (no errors and all saved)
 
401
     */
 
402
    public function save($forms, $allow_partial_save = true)
 
403
    {
 
404
        $result = true;
 
405
        $cf = ConfigFile::getInstance();
 
406
        $forms = (array) $forms;
 
407
 
 
408
        $values = array();
 
409
        $to_save = array();
 
410
        $this->errors = array();
 
411
        foreach ($forms as $form) {
 
412
            /* @var $form Form */
 
413
            if (isset($this->forms[$form])) {
 
414
                $form = $this->forms[$form];
 
415
            } else {
 
416
                continue;
 
417
            }
 
418
            // get current server id
 
419
            $change_index = $form->index === 0
 
420
                ? $cf->getServerCount() + 1
 
421
                : false;
 
422
            // grab POST values
 
423
            foreach ($form->fields as $field => $system_path) {
 
424
                $work_path = array_search($system_path, $this->system_paths);
 
425
                $key = $this->translated_paths[$work_path];
 
426
 
 
427
                // ensure the value is set
 
428
                if (!isset($_POST[$key])) {
 
429
                    // checkboxes aren't set by browsers if they're off
 
430
                    if ($form->getOptionType($field) == 'boolean') {
 
431
                        $_POST[$key] = false;
 
432
                    } else {
 
433
                        $this->errors[$form->name][] = PMA_lang(
 
434
                            'error_missing_field_data',
 
435
                            '<i>' . PMA_lang_name($system_path) . '</i>');
 
436
                        $result = false;
 
437
                        continue;
 
438
                    }
 
439
                }
 
440
 
 
441
                // cast variables to correct type
 
442
                $type = $form->getOptionType($field);
 
443
                switch ($type) {
 
444
                    case 'double':
 
445
                        settype($_POST[$key], 'float');
 
446
                        break;
 
447
                    case 'boolean':
 
448
                    case 'integer':
 
449
                        if ($_POST[$key] !== '') {
 
450
                            settype($_POST[$key], $type);
 
451
                        }
 
452
                        break;
 
453
                    case 'select':
 
454
                        if (!$this->_validateSelect($_POST[$key], $form->getOptionValueList($system_path))) {
 
455
                            $this->errors[$work_path][] = $GLOBALS["strstrSetuperror_incorrect_value"];
 
456
                            $result = false;
 
457
                            continue;
 
458
                        }
 
459
                        break;
 
460
                    case 'string':
 
461
                        $_POST[$key] = trim($_POST[$key]);
 
462
                        break;
 
463
                    case 'array':
 
464
                        // eliminate empty values and ensure we have an array
 
465
                        $post_values = explode("\n", $_POST[$key]);
 
466
                        $_POST[$key] = array();
 
467
                        foreach ($post_values as $v) {
 
468
                            $v = trim($v);
 
469
                            if ($v !== '') {
 
470
                                $_POST[$key][] = $v;
 
471
                            }
 
472
                        }
 
473
                        break;
 
474
                }
 
475
 
 
476
                // now we have value with proper type
 
477
                $values[$system_path] = $_POST[$key];
 
478
                if ($change_index !== false) {
 
479
                    $work_path = str_replace("Servers/$form->index/",
 
480
                      "Servers/$change_index/", $work_path);
 
481
                }
 
482
                $to_save[$work_path] = $system_path;
 
483
            }
 
484
        }
 
485
 
 
486
        // save forms
 
487
        if ($allow_partial_save || empty($this->errors)) {
 
488
            foreach ($to_save as $work_path => $path) {
 
489
                // TrustedProxies requires changes before saving
 
490
                if ($path == 'TrustedProxies') {
 
491
                    $proxies = array();
 
492
                    $i = 0;
 
493
                    foreach ($values[$path] as $value) {
 
494
                        $matches = array();
 
495
                        if (preg_match("/^(.+):(?:[ ]?)(\\w+)$/", $value, $matches)) {
 
496
                            // correct 'IP: HTTP header' pair
 
497
                            $ip = trim($matches[1]);
 
498
                            $proxies[$ip] = trim($matches[2]);
 
499
                        } else {
 
500
                            // save also incorrect values
 
501
                            $proxies["-$i"] = $value;
 
502
                            $i++;
 
503
                        }
 
504
                    }
 
505
                    $values[$path] = $proxies;
 
506
                }
 
507
                $cf->set($work_path, $values[$path], $path);
 
508
            }
 
509
        }
 
510
 
 
511
        // don't look for non-critical errors
 
512
        $this->_validate();
 
513
 
 
514
        return $result;
 
515
    }
 
516
 
 
517
    /**
 
518
     * Tells whether form validation failed
 
519
     *
 
520
     * @return boolean
 
521
     */
 
522
    public function hasErrors()
 
523
    {
 
524
        return count($this->errors) > 0;
 
525
    }
 
526
 
 
527
 
 
528
    /**
 
529
     * Returns link to documentation
 
530
     *
 
531
     * @param string $path
 
532
     * @return string
 
533
     */
 
534
    public function getDocLink($path)
 
535
    {
 
536
        $test = substr($path, 0, 6);
 
537
        if ($test == 'Import' || $test == 'Export') {
 
538
            return '';
 
539
        }
 
540
        return '../Documentation.html#cfg_' . self::_getOptName($path);
 
541
    }
 
542
 
 
543
    /**
 
544
     * Returns link to wiki
 
545
     *
 
546
     * @param string $path
 
547
     * @return string
 
548
     */
 
549
    public function getWikiLink($path)
 
550
    {
 
551
        $opt_name = self::_getOptName($path);
 
552
        if (substr($opt_name, 0, 7) == 'Servers') {
 
553
            $opt_name = substr($opt_name, 8);
 
554
            if (strpos($opt_name, 'AllowDeny') === 0) {
 
555
                $opt_name = str_replace('_', '_.28', $opt_name) . '.29';
 
556
            }
 
557
        }
 
558
        $test = substr($path, 0, 6);
 
559
        if ($test == 'Import') {
 
560
            $opt_name = substr($opt_name, 7);
 
561
            if ($opt_name == 'format') {
 
562
                $opt_name = 'format_2';
 
563
            }
 
564
        }
 
565
        if ($test == 'Export') {
 
566
            $opt_name = substr($opt_name, 7);
 
567
        }
 
568
        return 'http://wiki.cihar.com/pma/Config#' . $opt_name;
 
569
    }
 
570
 
 
571
    /**
 
572
     * Changes path so it can be used in URLs
 
573
     *
 
574
     * @param string $path
 
575
     * @return string
 
576
     */
 
577
    private static function _getOptName($path)
 
578
    {
 
579
      return str_replace(array('Servers/1/', '/'), array('Servers/', '_'), $path);
 
580
    }
 
581
}
 
582
?>
 
 
b'\\ No newline at end of file'