source: documentation/trunk/packages/dokuwiki-2011-05-25a/lib/plugins/config/settings/config.class.php@ 25027

Last change on this file since 25027 was 25027, checked in by jmt12, 12 years ago

Adding the packages directory, and within it a configured version of dokuwiki all ready to run

File size: 33.2 KB
Line 
1<?php
2/**
3 * Configuration Class and generic setting classes
4 *
5 * @author Chris Smith <[email protected]>
6 * @author Ben Coburn <[email protected]>
7 */
8
9if (!class_exists('configuration')) {
10
11 class configuration {
12
13 var $_name = 'conf'; // name of the config variable found in the files (overridden by $config['varname'])
14 var $_format = 'php'; // format of the config file, supported formats - php (overridden by $config['format'])
15 var $_heading = ''; // heading string written at top of config file - don't include comment indicators
16 var $_loaded = false; // set to true after configuration files are loaded
17 var $_metadata = array(); // holds metadata describing the settings
18 var $setting = array(); // array of setting objects
19 var $locked = false; // configuration is considered locked if it can't be updated
20
21 // configuration filenames
22 var $_default_files = array();
23 var $_local_files = array(); // updated configuration is written to the first file
24 var $_protected_files = array();
25
26 var $_plugin_list = null;
27
28 /**
29 * constructor
30 */
31 function configuration($datafile) {
32 global $conf, $config_cascade;
33
34 if (!@file_exists($datafile)) {
35 msg('No configuration metadata found at - '.htmlspecialchars($datafile),-1);
36 return;
37 }
38 include($datafile);
39
40 if (isset($config['varname'])) $this->_name = $config['varname'];
41 if (isset($config['format'])) $this->_format = $config['format'];
42 if (isset($config['heading'])) $this->_heading = $config['heading'];
43
44 $this->_default_files = $config_cascade['main']['default'];
45 $this->_local_files = $config_cascade['main']['local'];
46 $this->_protected_files = $config_cascade['main']['protected'];
47
48# if (isset($file['default'])) $this->_default_file = $file['default'];
49# if (isset($file['local'])) $this->_local_file = $file['local'];
50# if (isset($file['protected'])) $this->_protected_file = $file['protected'];
51
52 $this->locked = $this->_is_locked();
53
54 $this->_metadata = array_merge($meta, $this->get_plugintpl_metadata($conf['template']));
55
56 $this->retrieve_settings();
57 }
58
59 function retrieve_settings() {
60 global $conf;
61 $no_default_check = array('setting_fieldset', 'setting_undefined', 'setting_no_class');
62
63 if (!$this->_loaded) {
64 $default = array_merge($this->get_plugintpl_default($conf['template']), $this->_read_config_group($this->_default_files));
65 $local = $this->_read_config_group($this->_local_files);
66 $protected = $this->_read_config_group($this->_protected_files);
67
68 $keys = array_merge(array_keys($this->_metadata),array_keys($default), array_keys($local), array_keys($protected));
69 $keys = array_unique($keys);
70
71 foreach ($keys as $key) {
72 if (isset($this->_metadata[$key])) {
73 $class = $this->_metadata[$key][0];
74 $class = ($class && class_exists('setting_'.$class)) ? 'setting_'.$class : 'setting';
75 if ($class=='setting') {
76 $this->setting[] = new setting_no_class($key,$param);
77 }
78
79 $param = $this->_metadata[$key];
80 array_shift($param);
81 } else {
82 $class = 'setting_undefined';
83 $param = NULL;
84 }
85
86 if (!in_array($class, $no_default_check) && !isset($default[$key])) {
87 $this->setting[] = new setting_no_default($key,$param);
88 }
89
90 $this->setting[$key] = new $class($key,$param);
91 $this->setting[$key]->initialize($default[$key],$local[$key],$protected[$key]);
92 }
93
94 $this->_loaded = true;
95 }
96 }
97
98 function save_settings($id, $header='', $backup=true) {
99 global $conf;
100
101 if ($this->locked) return false;
102
103# $file = eval('return '.$this->_local_file.';');
104 $file = $this->_local_files[0];
105
106 // backup current file (remove any existing backup)
107 if (@file_exists($file) && $backup) {
108 if (@file_exists($file.'.bak')) @unlink($file.'.bak');
109 if (!io_rename($file, $file.'.bak')) return false;
110 }
111
112 if (!$fh = @fopen($file, 'wb')) {
113 io_rename($file.'.bak', $file); // problem opening, restore the backup
114 return false;
115 }
116
117 if (empty($header)) $header = $this->_heading;
118
119 $out = $this->_out_header($id,$header);
120
121 foreach ($this->setting as $setting) {
122 $out .= $setting->out($this->_name, $this->_format);
123 }
124
125 $out .= $this->_out_footer();
126
127 @fwrite($fh, $out);
128 fclose($fh);
129 if($conf['fperm']) chmod($file, $conf['fperm']);
130 return true;
131 }
132
133 function _read_config_group($files) {
134 $config = array();
135 foreach ($files as $file) {
136 $config = array_merge($config, $this->_read_config($file));
137 }
138
139 return $config;
140 }
141
142 /**
143 * return an array of config settings
144 */
145 function _read_config($file) {
146
147 if (!$file) return array();
148
149 $config = array();
150# $file = eval('return '.$file.';');
151
152 if ($this->_format == 'php') {
153
154 if(@file_exists($file)){
155 $contents = @php_strip_whitespace($file);
156 }else{
157 $contents = '';
158 }
159 $pattern = '/\$'.$this->_name.'\[[\'"]([^=]+)[\'"]\] ?= ?(.*?);(?=[^;]*(?:\$'.$this->_name.'|@include|$))/s';
160 $matches=array();
161 preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
162
163 for ($i=0; $i<count($matches); $i++) {
164
165 // correct issues with the incoming data
166 // FIXME ... for now merge multi-dimensional array indices using ____
167 $key = preg_replace('/.\]\[./',CM_KEYMARKER,$matches[$i][1]);
168
169 // remove quotes from quoted strings & unescape escaped data
170 $value = preg_replace('/^(\'|")(.*)(?<!\\\\)\1$/s','$2',$matches[$i][2]);
171 $value = strtr($value, array('\\\\'=>'\\','\\\''=>'\'','\\"'=>'"'));
172
173 $config[$key] = $value;
174 }
175 }
176
177 return $config;
178 }
179
180 function _out_header($id, $header) {
181 $out = '';
182 if ($this->_format == 'php') {
183 $out .= '<'.'?php'."\n".
184 "/*\n".
185 " * ".$header."\n".
186 " * Auto-generated by ".$id." plugin\n".
187 " * Run for user: ".$_SERVER['REMOTE_USER']."\n".
188 " * Date: ".date('r')."\n".
189 " */\n\n";
190 }
191
192 return $out;
193 }
194
195 function _out_footer() {
196 $out = '';
197 if ($this->_format == 'php') {
198 # if ($this->_protected_file) {
199 # $out .= "\n@include(".$this->_protected_file.");\n";
200 # }
201 $out .= "\n// end auto-generated content\n";
202 }
203
204 return $out;
205 }
206
207 // configuration is considered locked if there is no local settings filename
208 // or the directory its in is not writable or the file exists and is not writable
209 function _is_locked() {
210 if (!$this->_local_files) return true;
211
212# $local = eval('return '.$this->_local_file.';');
213 $local = $this->_local_files[0];
214
215 if (!is_writable(dirname($local))) return true;
216 if (@file_exists($local) && !is_writable($local)) return true;
217
218 return false;
219 }
220
221 /**
222 * not used ... conf's contents are an array!
223 * reduce any multidimensional settings to one dimension using CM_KEYMARKER
224 */
225 function _flatten($conf,$prefix='') {
226
227 $out = array();
228
229 foreach($conf as $key => $value) {
230 if (!is_array($value)) {
231 $out[$prefix.$key] = $value;
232 continue;
233 }
234
235 $tmp = $this->_flatten($value,$prefix.$key.CM_KEYMARKER);
236 $out = array_merge($out,$tmp);
237 }
238
239 return $out;
240 }
241
242 function get_plugin_list() {
243 if (is_null($this->_plugin_list)) {
244 $list = plugin_list('',true); // all plugins, including disabled ones
245
246 // remove this plugin from the list
247 $idx = array_search('config',$list);
248 unset($list[$idx]);
249
250 trigger_event('PLUGIN_CONFIG_PLUGINLIST',$list);
251 $this->_plugin_list = $list;
252 }
253
254 return $this->_plugin_list;
255 }
256
257 /**
258 * load metadata for plugin and template settings
259 */
260 function get_plugintpl_metadata($tpl){
261 $file = '/conf/metadata.php';
262 $class = '/conf/settings.class.php';
263 $metadata = array();
264
265 foreach ($this->get_plugin_list() as $plugin) {
266 $plugin_dir = plugin_directory($plugin);
267 if (@file_exists(DOKU_PLUGIN.$plugin_dir.$file)){
268 $meta = array();
269 @include(DOKU_PLUGIN.$plugin_dir.$file);
270 @include(DOKU_PLUGIN.$plugin_dir.$class);
271 if (!empty($meta)) {
272 $metadata['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.'plugin_settings_name'] = array('fieldset');
273 }
274 foreach ($meta as $key => $value){
275 if ($value[0]=='fieldset') { continue; } //plugins only get one fieldset
276 $metadata['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.$key] = $value;
277 }
278 }
279 }
280
281 // the same for the active template
282 if (@file_exists(DOKU_TPLINC.$file)){
283 $meta = array();
284 @include(DOKU_TPLINC.$file);
285 @include(DOKU_TPLINC.$class);
286 if (!empty($meta)) {
287 $metadata['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.'template_settings_name'] = array('fieldset');
288 }
289 foreach ($meta as $key => $value){
290 if ($value[0]=='fieldset') { continue; } //template only gets one fieldset
291 $metadata['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.$key] = $value;
292 }
293 }
294
295 return $metadata;
296 }
297
298 /**
299 * load default settings for plugins and templates
300 */
301 function get_plugintpl_default($tpl){
302 $file = '/conf/default.php';
303 $default = array();
304
305 foreach ($this->get_plugin_list() as $plugin) {
306 $plugin_dir = plugin_directory($plugin);
307 if (@file_exists(DOKU_PLUGIN.$plugin_dir.$file)){
308 $conf = array();
309 @include(DOKU_PLUGIN.$plugin_dir.$file);
310 foreach ($conf as $key => $value){
311 $default['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.$key] = $value;
312 }
313 }
314 }
315
316 // the same for the active template
317 if (@file_exists(DOKU_TPLINC.$file)){
318 $conf = array();
319 @include(DOKU_TPLINC.$file);
320 foreach ($conf as $key => $value){
321 $default['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.$key] = $value;
322 }
323 }
324
325 return $default;
326 }
327
328 }
329}
330
331if (!class_exists('setting')) {
332 class setting {
333
334 var $_key = '';
335 var $_default = NULL;
336 var $_local = NULL;
337 var $_protected = NULL;
338
339 var $_pattern = '';
340 var $_error = false; // only used by those classes which error check
341 var $_input = NULL; // only used by those classes which error check
342
343 var $_cautionList = array(
344 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger',
345 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning',
346 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security'
347 );
348
349 function setting($key, $params=NULL) {
350 $this->_key = $key;
351
352 if (is_array($params)) {
353 foreach($params as $property => $value) {
354 $this->$property = $value;
355 }
356 }
357 }
358
359 /**
360 * receives current values for the setting $key
361 */
362 function initialize($default, $local, $protected) {
363 if (isset($default)) $this->_default = $default;
364 if (isset($local)) $this->_local = $local;
365 if (isset($protected)) $this->_protected = $protected;
366 }
367
368 /**
369 * update setting with user provided value $input
370 * if value fails error check, save it
371 *
372 * @return true if changed, false otherwise (incl. on error)
373 */
374 function update($input) {
375 if (is_null($input)) return false;
376 if ($this->is_protected()) return false;
377
378 $value = is_null($this->_local) ? $this->_default : $this->_local;
379 if ($value == $input) return false;
380
381 if ($this->_pattern && !preg_match($this->_pattern,$input)) {
382 $this->_error = true;
383 $this->_input = $input;
384 return false;
385 }
386
387 $this->_local = $input;
388 return true;
389 }
390
391 /**
392 * @return array(string $label_html, string $input_html)
393 */
394 function html(&$plugin, $echo=false) {
395 $value = '';
396 $disable = '';
397
398 if ($this->is_protected()) {
399 $value = $this->_protected;
400 $disable = 'disabled="disabled"';
401 } else {
402 if ($echo && $this->_error) {
403 $value = $this->_input;
404 } else {
405 $value = is_null($this->_local) ? $this->_default : $this->_local;
406 }
407 }
408
409 $key = htmlspecialchars($this->_key);
410 $value = htmlspecialchars($value);
411
412 $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
413 $input = '<textarea rows="3" cols="40" id="config___'.$key.'" name="config['.$key.']" class="edit" '.$disable.'>'.$value.'</textarea>';
414 return array($label,$input);
415 }
416
417 /**
418 * generate string to save setting value to file according to $fmt
419 */
420 function out($var, $fmt='php') {
421
422 if ($this->is_protected()) return '';
423 if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
424
425 $out = '';
426
427 if ($fmt=='php') {
428 // translation string needs to be improved FIXME
429 $tr = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t', "\\" => '\\\\', "'" => '\\\'');
430 $tr = array("\\" => '\\\\', "'" => '\\\'');
431
432 $out = '$'.$var."['".$this->_out_key()."'] = '".strtr($this->_local, $tr)."';\n";
433 }
434
435 return $out;
436 }
437
438 function prompt(&$plugin) {
439 $prompt = $plugin->getLang($this->_key);
440 if (!$prompt) $prompt = htmlspecialchars(str_replace(array('____','_'),' ',$this->_key));
441 return $prompt;
442 }
443
444 function is_protected() { return !is_null($this->_protected); }
445 function is_default() { return !$this->is_protected() && is_null($this->_local); }
446 function error() { return $this->_error; }
447
448 function caution() {
449 if (!array_key_exists($this->_key, $this->_cautionList)) return false;
450 return $this->_cautionList[$this->_key];
451 }
452
453 function _out_key($pretty=false,$url=false) {
454 if($pretty){
455 $out = str_replace(CM_KEYMARKER,"&raquo;",$this->_key);
456 if ($url && !strstr($out,'&raquo;')) {//provide no urls for plugins, etc.
457 if ($out == 'start') //one exception
458 return '<a href="http://www.dokuwiki.org/config:startpage">'.$out.'</a>';
459 else
460 return '<a href="http://www.dokuwiki.org/config:'.$out.'">'.$out.'</a>';
461 }
462 return $out;
463 }else{
464 return str_replace(CM_KEYMARKER,"']['",$this->_key);
465 }
466 }
467 }
468}
469
470if (!class_exists('setting_string')) {
471 class setting_string extends setting {
472 function html(&$plugin, $echo=false) {
473 $value = '';
474 $disable = '';
475
476 if ($this->is_protected()) {
477 $value = $this->_protected;
478 $disable = 'disabled="disabled"';
479 } else {
480 if ($echo && $this->_error) {
481 $value = $this->_input;
482 } else {
483 $value = is_null($this->_local) ? $this->_default : $this->_local;
484 }
485 }
486
487 $key = htmlspecialchars($this->_key);
488 $value = htmlspecialchars($value);
489
490 $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
491 $input = '<input id="config___'.$key.'" name="config['.$key.']" type="text" class="edit" value="'.$value.'" '.$disable.'/>';
492 return array($label,$input);
493 }
494 }
495}
496
497if (!class_exists('setting_password')) {
498 class setting_password extends setting_string {
499
500 var $_code = 'plain'; // mechanism to be used to obscure passwords
501
502 function update($input) {
503 if ($this->is_protected()) return false;
504 if (!$input) return false;
505
506 if ($this->_pattern && !preg_match($this->_pattern,$input)) {
507 $this->_error = true;
508 $this->_input = $input;
509 return false;
510 }
511
512 $this->_local = conf_encodeString($input,$this->_code);
513 return true;
514 }
515
516 function html(&$plugin, $echo=false) {
517
518 $value = '';
519 $disable = $this->is_protected() ? 'disabled="disabled"' : '';
520
521 $key = htmlspecialchars($this->_key);
522
523 $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
524 $input = '<input id="config___'.$key.'" name="config['.$key.']" autocomplete="off" type="password" class="edit" value="" '.$disable.' />';
525 return array($label,$input);
526 }
527 }
528}
529
530if (!class_exists('setting_email')) {
531 if (!defined('SETTING_EMAIL_PATTERN')) define('SETTING_EMAIL_PATTERN','<^'.PREG_PATTERN_VALID_EMAIL.'$>');
532
533 class setting_email extends setting_string {
534 var $_pattern = SETTING_EMAIL_PATTERN; // no longer required, retained for backward compatibility - FIXME, may not be necessary
535 var $_multiple = false;
536
537 /**
538 * update setting with user provided value $input
539 * if value fails error check, save it
540 *
541 * @return true if changed, false otherwise (incl. on error)
542 */
543 function update($input) {
544 if (is_null($input)) return false;
545 if ($this->is_protected()) return false;
546
547 $value = is_null($this->_local) ? $this->_default : $this->_local;
548 if ($value == $input) return false;
549
550 if ($this->_multiple) {
551 $mails = array_filter(array_map('trim', split(',', $input)));
552 } else {
553 $mails = array($input);
554 }
555
556 foreach ($mails as $mail) {
557 if (!mail_isvalid($mail)) {
558 $this->_error = true;
559 $this->_input = $input;
560 return false;
561 }
562 }
563
564 $this->_local = $input;
565 return true;
566 }
567 }
568}
569
570if (!class_exists('setting_richemail')) {
571 class setting_richemail extends setting_email {
572
573 /**
574 * update setting with user provided value $input
575 * if value fails error check, save it
576 *
577 * @return true if changed, false otherwise (incl. on error)
578 */
579 function update($input) {
580 if (is_null($input)) return false;
581 if ($this->is_protected()) return false;
582
583 $value = is_null($this->_local) ? $this->_default : $this->_local;
584 if ($value == $input) return false;
585
586 // replace variables with pseudo values
587 $test = $input;
588 $test = str_replace('@USER@','joe',$test);
589 $test = str_replace('@NAME@','Joe Schmoe',$test);
590 $test = str_replace('@MAIL@','[email protected]',$test);
591
592 // now only check the address part
593 if(preg_match('#(.*?)<(.*?)>#',$test,$matches)){
594 $text = trim($matches[1]);
595 $addr = $matches[2];
596 }else{
597 $addr = $test;
598 }
599
600 if ($test !== '' && !mail_isvalid($addr)) {
601 $this->_error = true;
602 $this->_input = $input;
603 return false;
604 }
605
606 $this->_local = $input;
607 return true;
608 }
609
610 }
611}
612
613
614if (!class_exists('setting_numeric')) {
615 class setting_numeric extends setting_string {
616 // This allows for many PHP syntax errors...
617 // var $_pattern = '/^[-+\/*0-9 ]*$/';
618 // much more restrictive, but should eliminate syntax errors.
619 var $_pattern = '/^[-+]? *[0-9]+ *(?:[-+*] *[0-9]+ *)*$/';
620 var $_min = null;
621 var $_max = null;
622
623 function update($input) {
624 $local = $this->_local;
625 $valid = parent::update($input);
626 if ($valid && !(is_null($this->_min) && is_null($this->_max))) {
627 $numeric_local = (int) eval('return '.$this->_local.';');
628 if ((!is_null($this->_min) && $numeric_local < $this->_min) ||
629 (!is_null($this->_max) && $numeric_local > $this->_max)) {
630 $this->_error = true;
631 $this->_input = $input;
632 $this->_local = $local;
633 $valid = false;
634 }
635 }
636 return $valid;
637 }
638
639 function out($var, $fmt='php') {
640
641 if ($this->is_protected()) return '';
642 if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
643
644 $out = '';
645
646 if ($fmt=='php') {
647 $local = $this->_local === '' ? "''" : $this->_local;
648 $out .= '$'.$var."['".$this->_out_key()."'] = ".$local.";\n";
649 }
650
651 return $out;
652 }
653 }
654}
655
656if (!class_exists('setting_numericopt')) {
657 class setting_numericopt extends setting_numeric {
658 // just allow an empty config
659 var $_pattern = '/^(|[-]?[0-9]+(?:[-+*][0-9]+)*)$/';
660 }
661}
662
663if (!class_exists('setting_onoff')) {
664 class setting_onoff extends setting_numeric {
665
666 function html(&$plugin) {
667 $value = '';
668 $disable = '';
669
670 if ($this->is_protected()) {
671 $value = $this->_protected;
672 $disable = ' disabled="disabled"';
673 } else {
674 $value = is_null($this->_local) ? $this->_default : $this->_local;
675 }
676
677 $key = htmlspecialchars($this->_key);
678 $checked = ($value) ? ' checked="checked"' : '';
679
680 $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
681 $input = '<div class="input"><input id="config___'.$key.'" name="config['.$key.']" type="checkbox" class="checkbox" value="1"'.$checked.$disable.'/></div>';
682 return array($label,$input);
683 }
684
685 function update($input) {
686 if ($this->is_protected()) return false;
687
688 $input = ($input) ? 1 : 0;
689 $value = is_null($this->_local) ? $this->_default : $this->_local;
690 if ($value == $input) return false;
691
692 $this->_local = $input;
693 return true;
694 }
695 }
696}
697
698if (!class_exists('setting_multichoice')) {
699 class setting_multichoice extends setting_string {
700 var $_choices = array();
701
702 function html(&$plugin) {
703 $value = '';
704 $disable = '';
705 $nochoice = '';
706
707 if ($this->is_protected()) {
708 $value = $this->_protected;
709 $disable = ' disabled="disabled"';
710 } else {
711 $value = is_null($this->_local) ? $this->_default : $this->_local;
712 }
713
714 // ensure current value is included
715 if (!in_array($value, $this->_choices)) {
716 $this->_choices[] = $value;
717 }
718 // disable if no other choices
719 if (!$this->is_protected() && count($this->_choices) <= 1) {
720 $disable = ' disabled="disabled"';
721 $nochoice = $plugin->getLang('nochoice');
722 }
723
724 $key = htmlspecialchars($this->_key);
725
726 $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
727
728 $input = "<div class=\"input\">\n";
729 $input .= '<select class="edit" id="config___'.$key.'" name="config['.$key.']"'.$disable.'>'."\n";
730 foreach ($this->_choices as $choice) {
731 $selected = ($value == $choice) ? ' selected="selected"' : '';
732 $option = $plugin->getLang($this->_key.'_o_'.$choice);
733 if (!$option && isset($this->lang[$this->_key.'_o_'.$choice])) $option = $this->lang[$this->_key.'_o_'.$choice];
734 if (!$option) $option = $choice;
735
736 $choice = htmlspecialchars($choice);
737 $option = htmlspecialchars($option);
738 $input .= ' <option value="'.$choice.'"'.$selected.' >'.$option.'</option>'."\n";
739 }
740 $input .= "</select> $nochoice \n";
741 $input .= "</div>\n";
742
743 return array($label,$input);
744 }
745
746 function update($input) {
747 if (is_null($input)) return false;
748 if ($this->is_protected()) return false;
749
750 $value = is_null($this->_local) ? $this->_default : $this->_local;
751 if ($value == $input) return false;
752
753 if (!in_array($input, $this->_choices)) return false;
754
755 $this->_local = $input;
756 return true;
757 }
758 }
759}
760
761
762if (!class_exists('setting_dirchoice')) {
763 class setting_dirchoice extends setting_multichoice {
764
765 var $_dir = '';
766
767 function initialize($default,$local,$protected) {
768
769 // populate $this->_choices with a list of directories
770 $list = array();
771
772 if ($dh = @opendir($this->_dir)) {
773 while (false !== ($entry = readdir($dh))) {
774 if ($entry == '.' || $entry == '..') continue;
775 if ($this->_pattern && !preg_match($this->_pattern,$entry)) continue;
776
777 $file = (is_link($this->_dir.$entry)) ? readlink($this->_dir.$entry) : $entry;
778 if (is_dir($this->_dir.$file)) $list[] = $entry;
779 }
780 closedir($dh);
781 }
782 sort($list);
783 $this->_choices = $list;
784
785 parent::initialize($default,$local,$protected);
786 }
787 }
788}
789
790
791if (!class_exists('setting_hidden')) {
792 class setting_hidden extends setting {
793 // Used to explicitly ignore a setting in the configuration manager.
794 }
795}
796
797if (!class_exists('setting_fieldset')) {
798 class setting_fieldset extends setting {
799 // A do-nothing class used to detect the 'fieldset' type.
800 // Used to start a new settings "display-group".
801 }
802}
803
804if (!class_exists('setting_undefined')) {
805 class setting_undefined extends setting_hidden {
806 // A do-nothing class used to detect settings with no metadata entry.
807 // Used internaly to hide undefined settings, and generate the undefined settings list.
808 }
809}
810
811if (!class_exists('setting_no_class')) {
812 class setting_no_class extends setting_undefined {
813 // A do-nothing class used to detect settings with a missing setting class.
814 // Used internaly to hide undefined settings, and generate the undefined settings list.
815 }
816}
817
818if (!class_exists('setting_no_default')) {
819 class setting_no_default extends setting_undefined {
820 // A do-nothing class used to detect settings with no default value.
821 // Used internaly to hide undefined settings, and generate the undefined settings list.
822 }
823}
824
825if (!class_exists('setting_multicheckbox')) {
826 class setting_multicheckbox extends setting_string {
827
828 var $_choices = array();
829 var $_combine = array();
830
831 function update($input) {
832 if ($this->is_protected()) return false;
833
834 // split any combined values + convert from array to comma separated string
835 $input = ($input) ? $input : array();
836 $input = $this->_array2str($input);
837
838 $value = is_null($this->_local) ? $this->_default : $this->_local;
839 if ($value == $input) return false;
840
841 if ($this->_pattern && !preg_match($this->_pattern,$input)) {
842 $this->_error = true;
843 $this->_input = $input;
844 return false;
845 }
846
847 $this->_local = $input;
848 return true;
849 }
850
851 function html(&$plugin, $echo=false) {
852
853 $value = '';
854 $disable = '';
855
856 if ($this->is_protected()) {
857 $value = $this->_protected;
858 $disable = 'disabled="disabled"';
859 } else {
860 if ($echo && $this->_error) {
861 $value = $this->_input;
862 } else {
863 $value = is_null($this->_local) ? $this->_default : $this->_local;
864 }
865 }
866
867 $key = htmlspecialchars($this->_key);
868
869 // convert from comma separated list into array + combine complimentary actions
870 $value = $this->_str2array($value);
871 $default = $this->_str2array($this->_default);
872
873 $input = '';
874 foreach ($this->_choices as $choice) {
875 $idx = array_search($choice, $value);
876 $idx_default = array_search($choice,$default);
877
878 $checked = ($idx !== false) ? 'checked="checked"' : '';
879
880 // ideally this would be handled using a second class of "default", however IE6 does not
881 // correctly support CSS selectors referencing multiple class names on the same element
882 // (e.g. .default.selection).
883 $class = (($idx !== false) == (false !== $idx_default)) ? " selectiondefault" : "";
884
885 $prompt = ($plugin->getLang($this->_key.'_'.$choice) ?
886 $plugin->getLang($this->_key.'_'.$choice) : htmlspecialchars($choice));
887
888 $input .= '<div class="selection'.$class.'">'."\n";
889 $input .= '<label for="config___'.$key.'_'.$choice.'">'.$prompt."</label>\n";
890 $input .= '<input id="config___'.$key.'_'.$choice.'" name="config['.$key.'][]" type="checkbox" class="checkbox" value="'.$choice.'" '.$disable.' '.$checked."/>\n";
891 $input .= "</div>\n";
892
893 // remove this action from the disabledactions array
894 if ($idx !== false) unset($value[$idx]);
895 if ($idx_default !== false) unset($default[$idx_default]);
896 }
897
898 // handle any remaining values
899 $other = join(',',$value);
900
901 $class = (count($default == count($value)) && (count($value) == count(array_intersect($value,$default)))) ?
902 " selectiondefault" : "";
903
904 $input .= '<div class="other'.$class.'">'."\n";
905 $input .= '<label for="config___'.$key.'_other">'.$plugin->getLang($key.'_other')."</label>\n";
906 $input .= '<input id="config___'.$key.'_other" name="config['.$key.'][other]" type="text" class="edit" value="'.htmlspecialchars($other).'" '.$disable." />\n";
907 $input .= "</div>\n";
908
909 $label = '<label>'.$this->prompt($plugin).'</label>';
910 return array($label,$input);
911 }
912
913 /**
914 * convert comma separated list to an array and combine any complimentary values
915 */
916 function _str2array($str) {
917 $array = explode(',',$str);
918
919 if (!empty($this->_combine)) {
920 foreach ($this->_combine as $key => $combinators) {
921 $idx = array();
922 foreach ($combinators as $val) {
923 if (($idx[] = array_search($val, $array)) === false) break;
924 }
925
926 if (count($idx) && $idx[count($idx)-1] !== false) {
927 foreach ($idx as $i) unset($array[$i]);
928 $array[] = $key;
929 }
930 }
931 }
932
933 return $array;
934 }
935
936 /**
937 * convert array of values + other back to a comma separated list, incl. splitting any combined values
938 */
939 function _array2str($input) {
940
941 // handle other
942 $other = trim($input['other']);
943 $other = !empty($other) ? explode(',',str_replace(' ','',$input['other'])) : array();
944 unset($input['other']);
945
946 $array = array_unique(array_merge($input, $other));
947
948 // deconstruct any combinations
949 if (!empty($this->_combine)) {
950 foreach ($this->_combine as $key => $combinators) {
951
952 $idx = array_search($key,$array);
953 if ($idx !== false) {
954 unset($array[$idx]);
955 $array = array_merge($array, $combinators);
956 }
957 }
958 }
959
960 return join(',',array_unique($array));
961 }
962 }
963}
964
965/**
966 * Provide php_strip_whitespace (php5 function) functionality
967 *
968 * @author Chris Smith <[email protected]>
969 */
970if (!function_exists('php_strip_whitespace')) {
971
972 if (function_exists('token_get_all')) {
973
974 if (!defined('T_ML_COMMENT')) {
975 define('T_ML_COMMENT', T_COMMENT);
976 } else {
977 define('T_DOC_COMMENT', T_ML_COMMENT);
978 }
979
980 /**
981 * modified from original
982 * source Google Groups, php.general, by David Otton
983 */
984 function php_strip_whitespace($file) {
985 if (!@is_readable($file)) return '';
986
987 $in = join('',@file($file));
988 $out = '';
989
990 $tokens = token_get_all($in);
991
992 foreach ($tokens as $token) {
993 if (is_string ($token)) {
994 $out .= $token;
995 } else {
996 list ($id, $text) = $token;
997 switch ($id) {
998 case T_COMMENT : // fall thru
999 case T_ML_COMMENT : // fall thru
1000 case T_DOC_COMMENT : // fall thru
1001 case T_WHITESPACE :
1002 break;
1003 default : $out .= $text; break;
1004 }
1005 }
1006 }
1007 return ($out);
1008 }
1009
1010 } else {
1011
1012 function is_whitespace($c) { return (strpos("\t\n\r ",$c) !== false); }
1013 function is_quote($c) { return (strpos("\"'",$c) !== false); }
1014 function is_escaped($s,$i) {
1015 $idx = $i-1;
1016 while(($idx>=0) && ($s{$idx} == '\\')) $idx--;
1017 return (($i - $idx + 1) % 2);
1018 }
1019
1020 function is_commentopen($str, $i) {
1021 if ($str{$i} == '#') return "\n";
1022 if ($str{$i} == '/') {
1023 if ($str{$i+1} == '/') return "\n";
1024 if ($str{$i+1} == '*') return "*/";
1025 }
1026
1027 return false;
1028 }
1029
1030 function php_strip_whitespace($file) {
1031
1032 if (!@is_readable($file)) return '';
1033
1034 $contents = join('',@file($file));
1035 $out = '';
1036
1037 $state = 0;
1038 for ($i=0; $i<strlen($contents); $i++) {
1039 if (!$state && is_whitespace($contents{$i})) continue;
1040
1041 if (!$state && ($c_close = is_commentopen($contents, $i))) {
1042 $c_open_len = ($contents{$i} == '/') ? 2 : 1;
1043 $i = strpos($contents, $c_close, $i+$c_open_len)+strlen($c_close)-1;
1044 continue;
1045 }
1046
1047 $out .= $contents{$i};
1048 if (is_quote($contents{$i})) {
1049 if (($state == $contents{$i}) && !is_escaped($contents, $i)) { $state = 0; continue; }
1050 if (!$state) {$state = $contents{$i}; continue; }
1051 }
1052 }
1053
1054 return $out;
1055 }
1056 }
1057}
Note: See TracBrowser for help on using the repository browser.