system/classes/config.class.php
author Dirk Haun <dirk@haun-online.de>
Sun, 10 May 2009 09:30:30 +0200
branchHEAD
changeset 7019 a65dd04d595b
parent 6983 40a4e43583a5
child 7037 664a7d73ef34
permissions -rw-r--r--
Fixed notices in the config class, caused by the check to prevent people from locking themselves out of their site by disabling all 3 login methods.
     1 <?php
     2 
     3 /* Reminder: always indent with 4 spaces (no tabs). */
     4 // +---------------------------------------------------------------------------+
     5 // | Geeklog 1.6                                                               |
     6 // +---------------------------------------------------------------------------+
     7 // | config.class.php                                                          |
     8 // |                                                                           |
     9 // | Controls the UI and database for configuration settings                   |
    10 // +---------------------------------------------------------------------------+
    11 // | Copyright (C) 2007-2009 by the following authors:                         |
    12 // |                                                                           |
    13 // | Authors: Aaron Blankstein  - kantai AT gmail DOT com                      |
    14 // +---------------------------------------------------------------------------+
    15 // |                                                                           |
    16 // | This program is free software; you can redistribute it and/or             |
    17 // | modify it under the terms of the GNU General Public License               |
    18 // | as published by the Free Software Foundation; either version 2            |
    19 // | of the License, or (at your option) any later version.                    |
    20 // |                                                                           |
    21 // | This program is distributed in the hope that it will be useful,           |
    22 // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
    23 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
    24 // | GNU General Public License for more details.                              |
    25 // |                                                                           |
    26 // | You should have received a copy of the GNU General Public License         |
    27 // | along with this program; if not, write to the Free Software Foundation,   |
    28 // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
    29 // |                                                                           |
    30 // +---------------------------------------------------------------------------+
    31 
    32 class config {
    33     var $dbconfig_file;
    34     var $config_array;
    35 
    36     /**
    37      * This function will return an instance of the config class. If an
    38      * instance with the given group/reference name does not exist, then it
    39      * will create a new one. This function insures    that there is only one
    40      * instance for a given group name.
    41      *
    42      *    @param string group_name   This is simply the group name that this
    43      *                             config object will control - for the main gl
    44      *                             settings this is 'Core'
    45      *
    46      *    @return config                The newly created or referenced config object
    47      */
    48     function &get_instance()
    49     {
    50         static $instance;
    51 
    52         if (!$instance) {
    53             $instance = new config();
    54         }
    55 
    56         return $instance;
    57     }
    58 
    59     function config()
    60     {
    61         $this->config_array = array();
    62     }
    63 
    64     /**
    65      * This function sets the secure configuration file (database related
    66      * settings) for the configuration class to read. This should only need to
    67      * be called for the 'Core' group. It also must be called before
    68      * load_baseconfig()
    69      *
    70      * @param string sf        The filename and path of the secure db settings
    71      */
    72 
    73     function set_configfile($sf)
    74     {
    75         $this->dbconfig_file = $sf;
    76     }
    77 
    78     /**
    79      * This function reads the secure configuration file and loads
    80      * lib-database.php. This needs to be called in the 'Core' group before
    81      * &init_config() can be used. It only needs to be called once
    82      */
    83 
    84     function load_baseconfig()
    85     {
    86         global $_DB, $_TABLES, $_CONF;
    87 
    88         include $this->dbconfig_file;
    89         $this->config_array['Core'] =& $_CONF;
    90 
    91         include_once $_CONF['path_system'] . 'lib-database.php';
    92 
    93         // for backward compatibility
    94         $_CONF['ostype'] = PHP_OS;
    95     }
    96 
    97     /**
    98      * This function initializes the configuration array (i.e. $_CONF) and
    99      * will return a reference to the newly created array. The class keeps
   100      * track of this reference, and the set function will mutate it.
   101      *
   102      * @return array(string => mixed)      This is a reference to the
   103      *                                     config array
   104      */
   105     function &initConfig()
   106     {
   107         global $_TABLES;
   108 
   109         $false_str = serialize(false);
   110 
   111         $sql = "SELECT name, value, group_name FROM {$_TABLES['conf_values']} WHERE (type <> 'subgroup') AND (type <> 'fieldset')";
   112         $result = DB_query($sql);
   113         while ($row = DB_fetchArray($result)) {
   114             if ($row[1] !== 'unset') {
   115                 if (!array_key_exists($row[2], $this->config_array) ||
   116                     !array_key_exists($row[0], $this->config_array[$row[2]])) {
   117                     $value = @unserialize($row[1]);
   118                     if (($value === false) && ($row[1] != $false_str)) {
   119                         if (function_exists('COM_errorLog')) {
   120                             COM_errorLog("Unable to unserialize {$row[1]} for {$row[2]}:{$row[0]}");
   121                         }
   122                     } else {
   123                         $this->config_array[$row[2]][$row[0]] = $value;
   124                     }
   125                 }
   126             }
   127         }
   128         $this->_post_configuration();
   129 
   130         return $this->config_array;
   131     }
   132 
   133     function &get_config($group)
   134     {
   135         $retval = false;
   136 
   137         if (array_key_exists($group, $this->config_array)) {
   138 
   139             // an ugly little hack to ensure backward compatibility ...
   140             if ($group == 'Core') {
   141                 global $_DB_mysqldump_path;
   142 
   143                 $_DB_mysqldump_path = $this->config_array[$group]['mysqldump_path'];
   144             }
   145 
   146             return $this->config_array[$group];
   147         }
   148 
   149         return $retval;
   150     }
   151 
   152     function group_exists($group)
   153     {
   154         return array_key_exists($group, $this->config_array);
   155     }
   156 
   157     /**
   158      * This function sets a configuration variable to a value in the database
   159      * and in the current array. If the variable does not already exist,
   160      * nothing will happen.
   161      *
   162      * @param string name        Name of the config parameter to set
   163      * @param mixed value        The value to set the config parameter to
   164      */
   165     function set($name, $value, $group='Core')
   166     {
   167         global $_TABLES;
   168 
   169         $escaped_val = addslashes(serialize($value));
   170         $escaped_name = addslashes($name);
   171         $escaped_grp = addslashes($group);
   172         $sql = "UPDATE {$_TABLES['conf_values']} " .
   173                "SET value = '{$escaped_val}' WHERE " .
   174                "name = '{$escaped_name}' AND group_name = '{$escaped_grp}'";
   175         $this->_DB_escapedQuery($sql);
   176         $this->config_array[$group][$name] = $value;
   177         $this->_post_configuration();
   178     }
   179 
   180     /**
   181      * This function sets the default of a configuration variable to a value in
   182      * the database but not in the current array.
   183      * If the variable does not already exist, nothing will happen.
   184      *
   185      * @param string name        Name of the config parameter to set
   186      * @param mixed  value       The value to set the config parameter to
   187      * @param string group       Config group name ('Core' or plugin name)
   188      */
   189     function set_default($name, $value, $group = 'Core')
   190     {
   191         global $_TABLES;
   192 
   193         $escaped_val = addslashes(serialize($value));
   194         $escaped_name = addslashes($name);
   195         $escaped_grp = addslashes($group);
   196         $sql = "UPDATE {$_TABLES['conf_values']} " .
   197                "SET default_value = '{$escaped_val}' WHERE " .
   198                "name = '{$escaped_name}' AND group_name = '{$escaped_grp}'";
   199         $this->_DB_escapedQuery($sql);
   200     }
   201 
   202     function restore_param($name, $group)
   203     {
   204         global $_TABLES;
   205 
   206         $escaped_name = addslashes($name);
   207         $escaped_grp = addslashes($group);
   208 
   209         $result = DB_query("SELECT value, default_value FROM {$_TABLES['conf_values']} WHERE name = '{$escaped_name}' AND group_name = '{$escaped_grp}'");
   210         list($value, $default_value) = DB_fetchArray($result);
   211 
   212         $sql = "UPDATE {$_TABLES['conf_values']} ";
   213         if ($value == 'unset') {
   214             $default_value = addslashes($default_value);
   215             $sql .= "SET value = '{$default_value}', default_value = 'unset:{$default_value}'";
   216         } else {
   217             $sql .= "SET value = default_value";
   218         }
   219         $sql .= " WHERE name = '{$escaped_name}' AND group_name = '{$escaped_grp}'";
   220         $this->_DB_escapedQuery($sql);
   221     }
   222 
   223     function unset_param($name, $group)
   224     {
   225         global $_TABLES;
   226 
   227         $escaped_name = addslashes($name);
   228         $escaped_grp = addslashes($group);
   229         $default_value = DB_getItem($_TABLES['conf_values'], 'default_value',
   230                 "name = '{$escaped_name}' AND group_name = '{$escaped_grp}'");
   231         $sql = "UPDATE {$_TABLES['conf_values']} SET value = 'unset'";
   232         if (substr($default_value, 0, 6) == 'unset:') {
   233             $default_value = addslashes(substr($default_value, 6));
   234             $sql .= ", default_value = '{$default_value}'";
   235         }
   236         $sql .= " WHERE name = '{$escaped_name}' AND group_name = '{$escaped_grp}'";
   237         $this->_DB_escapedQuery($sql);
   238     }
   239 
   240     /**
   241      * Adds a configuration variable to the config object
   242      *
   243      * @param string $param_name        name of the parameter to add
   244      * @param mixed  $default_value     the default value of the parameter
   245      *                                  (also will be the initial value)
   246      * @param string $display_name      name that will be displayed on the
   247      *                                  user interface
   248      * @param string $type              the type of the configuration variable
   249      *
   250      *    If the configuration variable is an array, prefix this string with
   251      *    '@' if the administrator should NOT be able to add or remove keys
   252      *    '*' if the administrator should be able to add named keys
   253      *    '%' if the administrator should be able to add numbered keys
   254      *    These symbols can be repeated like such: @@text if the configuration
   255      *    variable is an array of arrays of text.
   256      *    The base variable types are:
   257      *    'text'    textbox displayed     string  value stored
   258      *    'select'  selectbox displayed   string  value stored
   259      *    'hidden'  no display            string  value stored
   260      *
   261      * @param string $subgroup          subgroup of the variable
   262      *                                  (the second row of tabs on the user interface)
   263      * @param string $fieldset          the fieldset to display the variable under
   264      * @param array  $selection_array   possible selections for the 'select' type
   265      *                                  this MUST be passed if you use the 'select'
   266      *                                  type
   267      * @param int    $sort              sort rank on the user interface (ascending)
   268      *
   269      * @param boolean $set              whether or not this parameter is set
   270      */
   271     function add($param_name, $default_value, $type, $subgroup, $fieldset,
   272          $selection_array=null, $sort=0, $set=true, $group='Core')
   273     {
   274         global $_TABLES;
   275 
   276         $Qargs = array($param_name,
   277                        $set ? serialize($default_value) : 'unset',
   278                        $type,
   279                        $subgroup,
   280                        $group,
   281                        ($selection_array === null ?
   282                         -1 : $selection_array),
   283                        $sort,
   284                        $fieldset,
   285                        serialize($default_value));
   286         $Qargs = array_map('addslashes', $Qargs);
   287         $sql = "INSERT INTO {$_TABLES['conf_values']} (name, value, type, " .
   288             "subgroup, group_name, selectionArray, sort_order,".
   289             " fieldset, default_value) VALUES ("
   290             ."'{$Qargs[0]}',"
   291             ."'{$Qargs[1]}',"
   292             ."'{$Qargs[2]}',"
   293             ."{$Qargs[3]},"
   294             ."'{$Qargs[4]}',"
   295             ."{$Qargs[5]},"
   296             ."{$Qargs[6]},"
   297             ."{$Qargs[7]},"
   298             ."'{$Qargs[8]}')";
   299 
   300         $this->_DB_escapedQuery($sql);
   301 
   302         $this->config_array[$group][$param_name] = $default_value;
   303     }
   304 
   305     /**
   306      * Permanently deletes a parameter
   307      * @param string  $param_name   This is the name of the parameter to delete
   308      */
   309     function del($param_name, $group)
   310     {
   311         DB_delete($GLOBALS['_TABLES']['conf_values'],
   312                   array('name', 'group_name'),
   313                   array(addslashes($param_name), addslashes($group)));
   314         unset($this->config_array[$group][$param_name]);
   315     }
   316 
   317     /**
   318      * Gets extended (GUI related) information from the database
   319      * @param string subgroup            filters by subgroup
   320      * @return array(string => string => array(string => mixed))
   321      *    Array keys are fieldset => parameter named => information array
   322      */
   323     function _get_extended($subgroup, $group)
   324     {
   325         global $_TABLES, $LANG_confignames, $LANG_configselects;
   326 
   327         $q_string = "SELECT name, type, selectionArray, "
   328             . "fieldset, value, default_value FROM {$_TABLES['conf_values']}" .
   329             " WHERE group_name='{$group}' AND subgroup='{$subgroup}' " .
   330             " AND (type <> 'fieldset' AND type <> 'subgroup') " .
   331             " ORDER BY fieldset,sort_order ASC";
   332         $Qresult = DB_query($q_string);
   333         $res = array();
   334         if (!array_key_exists($group, $LANG_configselects)) {
   335             $LANG_configselects[$group] = array();
   336         }
   337         if (!array_key_exists($group, $LANG_confignames)) {
   338             $LANG_confignames[$group] = array();
   339         }
   340         while ($row = DB_fetchArray($Qresult)) {
   341             $cur = $row;
   342             if (substr($cur[5], 0, 6) == 'unset:') {
   343                 $cur[5] = true;
   344             } else {
   345                 $cur[5] = false;
   346             }
   347             $res[$cur[3]][$cur[0]] =
   348                 array('display_name' =>
   349                       (array_key_exists($cur[0], $LANG_confignames[$group]) ?
   350                        $LANG_confignames[$group][$cur[0]]
   351                        : $cur[0]),
   352                       'type' =>
   353                       (($cur[4] == 'unset') ?
   354                        'unset' : $cur[1]),
   355                       'selectionArray' =>
   356                       (($cur[2] != -1) ?
   357                        //isset($LANG_configselects[$group][$cur[2]]) : null),
   358                        $LANG_configselects[$group][$cur[2]] : null),
   359                       'value' =>
   360                       (($cur[4] == 'unset') ?
   361                        'unset' : unserialize($cur[4])),
   362                       'reset' => $cur[5]);
   363         }
   364 
   365         return $res;
   366     }
   367 
   368     // Changes any config settings that depend on other configuration settings.
   369     function _post_configuration()
   370     {
   371         global $_USER;
   372 
   373         if (empty($_USER['theme'])) {
   374             if (! empty($this->config_array['Core']['theme'])) {
   375                 $theme = $this->config_array['Core']['theme'];
   376             }
   377         } else {
   378             $theme = $_USER['theme'];
   379         }
   380 
   381         if (! empty($theme)) {
   382             if (! empty($this->config_array['Core']['path_themes'])) {
   383                 $this->config_array['Core']['path_layout'] = $this->config_array['Core']['path_themes'] . $theme . '/';
   384             }
   385             if (! empty($this->config_array['Core']['site_url'])) {
   386                 $this->config_array['Core']['layout_url'] = $this->config_array['Core']['site_url'] . '/layout/' . $theme;
   387             }
   388         }
   389 
   390         $methods = array('standard', 'openid', '3rdparty');
   391         $methods_disabled = 0;
   392         foreach ($methods as $m) {
   393             if (isset($this->config_array['Core']['user_login_method'][$m]) &&
   394                     !$this->config_array['Core']['user_login_method'][$m]) {
   395                 $methods_disabled++;    
   396             }
   397         }
   398         if ($methods_disabled == count($methods)) {
   399             // just to make sure people don't lock themselves out of their site
   400             $this->config_array['Core']['user_login_method']['standard'] = true;
   401 
   402             // TBD: ensure that we have a Root user able to log in with the
   403             //      enabled login method(s)
   404         }
   405     }
   406 
   407     function _get_groups()
   408     {
   409         global $_TABLES;
   410 
   411         $groups = array_keys($this->config_array);
   412         $num_groups = count($groups);
   413         for ($i = 0; $i < $num_groups; $i++) {
   414             $g = $groups[$i];
   415             if ($g != 'Core') {
   416                 $enabled = DB_getItem($_TABLES['plugins'], 'pi_enabled',
   417                                       "pi_name = '$g'");
   418                 if (isset($enabled) && ($enabled == 0)) {
   419                     unset($groups[$i]);
   420                 }
   421             }
   422         }
   423 
   424         return $groups;
   425     }
   426 
   427     function _get_sgroups($group)
   428     {
   429         global $_TABLES;
   430 
   431         $q_string = "SELECT name,subgroup FROM {$_TABLES['conf_values']} WHERE "
   432                   . "type = 'subgroup' AND group_name = '$group' "
   433                   . "ORDER BY subgroup";
   434         $retval = array();
   435         $res = DB_query($q_string);
   436         while ($row = DB_fetchArray($res)) {
   437             $retval[$row['name']] = $row['subgroup'];
   438         }
   439 
   440         return $retval;
   441     }
   442 
   443     /**
   444      * This function is responsible for creating the configuration GUI
   445      *
   446      * @param string sg        This is the subgroup name to load the gui for.
   447      *                        If nothing is passed, it will display the first
   448      *                         (alpha) subgroup
   449      *
   450      * @param array(string=>boolean) change_result
   451      *                        This is an array of what changes were made to the
   452      *                        configuration - if it is passed, it will display
   453      *                        the "Changes" message box.
   454      */
   455     function get_ui($grp, $sg='0', $change_result=null)
   456     {
   457         global $_CONF, $LANG_CONFIG, $LANG_configsubgroups;
   458 
   459         if(!array_key_exists($grp, $LANG_configsubgroups)) {
   460             $LANG_configsubgroups[$grp] = array();
   461         }
   462         if (!SEC_inGroup('Root')) {
   463             return config::_UI_perm_denied();
   464         }
   465 
   466         if (!isset($sg) OR empty($sg)) {
   467             $sg = '0';
   468         }
   469         $t = new Template($_CONF['path_layout'] . 'admin/config');
   470         $t->set_file(array('main' => 'configuration.thtml',
   471                            'menugroup' => 'menu_element.thtml'));
   472 
   473         $t->set_var('site_url', $_CONF['site_url']);
   474         $t->set_var('site_admin_url', $_CONF['site_admin_url']);
   475         $t->set_var('layout_url', $_CONF['layout_url']);
   476         $t->set_var('xhtml', XHTML);
   477         $t->set_var('gltoken_name', CSRF_TOKEN);
   478         $t->set_var('gltoken', SEC_createToken());
   479 
   480         $t->set_var('lang_save_changes', $LANG_CONFIG['save_changes']);
   481         $t->set_var('lang_reset_form', $LANG_CONFIG['reset_form']);
   482         $t->set_var('lang_changes_made', $LANG_CONFIG['changes_made']);
   483 
   484         $t->set_var('open_group', $grp);
   485 
   486         $groups = $this->_get_groups();
   487         $outerloopcntr = 1;
   488         if (count($groups) > 0) {
   489             $t->set_block('menugroup', 'subgroup-selector', 'subgroups');
   490             foreach ($groups as $group) {
   491                 $t->set_var("select_id", ($group === $grp ? 'id="current"' : ''));
   492                 $t->set_var("group_select_value", $group);
   493                 $t->set_var("group_display", ucwords($group));
   494                 $subgroups = $this->_get_sgroups($group);
   495                 $innerloopcntr = 1;
   496                 foreach ($subgroups as $sgname => $sgroup) {
   497                     if ($grp == $group AND $sg == $sgroup) {
   498                         $t->set_var('group_active_name', ucwords($group));
   499                         if (isset($LANG_configsubgroups[$group][$sgname])) {
   500                             $t->set_var('subgroup_active_name',
   501                                     $LANG_configsubgroups[$group][$sgname]);
   502                         } else if (isset($LANG_configsubgroups[$group][$sgroup])) {
   503                             $t->set_var('subgroup_active_name',
   504                                     $LANG_configsubgroups[$group][$sgroup]);
   505                         } else {
   506                             $t->set_var('subgroup_active_name', $sgname);
   507                         }
   508                         $t->set_var('select_id', 'id="current"');
   509                     } else {
   510                         $t->set_var('select_id', '');
   511                     }
   512                     $t->set_var('subgroup_name', $sgroup);
   513                     if (isset($LANG_configsubgroups[$group][$sgname])) {
   514                         $t->set_var('subgroup_display_name',
   515                                     $LANG_configsubgroups[$group][$sgname]);
   516                     } else {
   517                         $t->set_var('subgroup_display_name', $sgname);
   518                     }
   519                     if ($innerloopcntr == 1) {
   520                         $t->parse('subgroups', "subgroup-selector");
   521                     } else {
   522                         $t->parse('subgroups', "subgroup-selector", true);
   523                     }
   524                     $innerloopcntr++;
   525                 }
   526                 $t->set_var('cntr',$outerloopcntr);
   527                 $t->parse("menu_elements", "menugroup", true);
   528                 $outerloopcntr++;
   529             }
   530         } else {
   531             $t->set_var('hide_groupselection','none');
   532         }
   533 
   534         $t->set_var('open_sg', $sg);
   535         $t->set_block('main','fieldset','sg_contents');
   536         $t->set_block('fieldset', 'notes', 'fs_notes');
   537 
   538         $ext_info = $this->_get_extended($sg, $grp);
   539         foreach ($ext_info as $fset => $params) {
   540             $fs_contents = '';
   541             foreach ($params as $name => $e) {
   542                 $fs_contents .=
   543                     $this->_UI_get_conf_element($grp, $name,
   544                                                $e['display_name'],
   545                                                $e['type'],
   546                                                $e['value'],
   547                                                $e['selectionArray'], false,
   548                                                $e['reset']);
   549             }
   550             $this->_UI_get_fs($grp, $fs_contents, $fset, $t);
   551         }
   552 
   553         $display  = COM_siteHeader('none', $LANG_CONFIG['title']);
   554         $t->set_var('config_menu',$this->_UI_configmanager_menu($grp,$sg));
   555         if ($change_result != null AND $change_result !== array()) {
   556             $t->set_var('change_block',$this->_UI_get_change_block($change_result));
   557         } else {
   558             $t->set_var('show_changeblock','none');
   559         }
   560         $display .= $t->finish($t->parse("OUTPUT", "main"));
   561         $display .= COM_siteFooter(false);
   562 
   563         return $display;
   564     }
   565 
   566     function _UI_get_change_block($changes)
   567     {
   568         if ($changes != null AND $changes !== array()) {
   569             $display = '<ul style="margin-top:5px;">';
   570             foreach ($changes as $param_name => $success)
   571                 $display .= '<li>' . $param_name . '</li>';
   572             $display .= '</ul>';
   573 
   574             return $display;
   575         }
   576     }
   577 
   578     function _UI_get_fs($group, $contents, $fs_id, &$t)
   579     {
   580         global $_TABLES, $LANG_fs;
   581 
   582         if (!array_key_exists($group, $LANG_fs)) {
   583             $LANG_fs[$group] = array();
   584         }
   585         $t->set_var('fs_contents', $contents);
   586         $fs_index = DB_getItem($_TABLES['conf_values'], 'name',
   587                         "type = 'fieldset' AND fieldset = $fs_id AND group_name = '$group'");
   588         if (empty($fs_index)) {
   589             $t->set_var('fs_display', $LANG_fs[$group][$fs_id]);
   590         } else if (isset($LANG_fs[$group][$fs_index])) {
   591             $t->set_var('fs_display', $LANG_fs[$group][$fs_index]);
   592         } else {
   593             $t->set_var('fs_display', $fs_index);
   594         }
   595         $t->set_var('fs_notes', '');
   596         $t->parse('sg_contents', 'fieldset', true);
   597     }
   598 
   599     function _UI_perm_denied()
   600     {
   601         global $_USER, $MESSAGE;
   602 
   603         $display = COM_siteHeader('menu', $MESSAGE[30])
   604                  . COM_showMessageText($MESSAGE[29], $MESSAGE[30])
   605                  . COM_siteFooter();
   606         COM_accessLog("User {$_USER['username']} tried to illegally access the config administration screen.");
   607 
   608         return $display;
   609     }
   610 
   611     function _UI_get_conf_element($group, $name, $display_name, $type, $val,
   612                                   $selectionArray = null , $deletable = false,
   613                                   $allow_reset = false)
   614     {
   615         global $_CONF, $LANG_CONFIG;
   616 
   617         $t = new Template($GLOBALS['_CONF']['path_layout'] . 'admin/config');
   618         $t -> set_file('element', 'config_element.thtml');
   619 
   620         $blocks = array('delete-button', 'text-element', 'placeholder-element',
   621                         'select-element', 'list-element', 'unset-param',
   622                         'keyed-add-button', 'unkeyed-add-button');
   623         foreach ($blocks as $block) {
   624             $t->set_block('element', $block);
   625         }
   626 
   627         $t->set_var('site_url', $_CONF['site_url']);
   628         $t->set_var('site_admin_url', $_CONF['site_admin_url']);
   629         $t->set_var('layout_url', $_CONF['layout_url']);
   630         $t->set_var('xhtml', XHTML);
   631 
   632         $t->set_var('lang_restore', $LANG_CONFIG['restore']);
   633         $t->set_var('lang_enable', $LANG_CONFIG['enable']);
   634         $t->set_var('lang_add_element', $LANG_CONFIG['add_element']);
   635 
   636         $t->set_var('name', $name);
   637         $t->set_var('display_name', $display_name);
   638         if (!is_array($val)) {
   639             $t->set_var('value', htmlspecialchars($val));
   640         }
   641         if ($deletable) {
   642             $t->set_var('delete', $t->parse('output', 'delete-button'));
   643         } else {
   644             if ($allow_reset) {
   645                 $t->set_var('unset_link',
   646                         "(<a href='#' onClick='unset(\"{$name}\");' title='"
   647                         . $LANG_CONFIG['disable'] . "'>X</a>)");
   648             }
   649             if (($a = strrchr($name, '[')) !== FALSE) {
   650                 $on = substr($a, 1, -1);
   651                 $o = str_replace(array('[', ']'), array('_', ''), $name);
   652             } else {
   653                 $o = $name;
   654                 $on = $name;
   655             }
   656             if (! is_numeric($on)) {
   657                 $descUrl = $this->_get_ConfigHelp($group, $o);
   658                 if (! empty($descUrl)) {
   659                     $t->set_var('doc_url', $descUrl);
   660                     $t->set_var('doc_link',
   661                             '(<a href="' . $descUrl . '" target="help">?</a>)');
   662                 }
   663             }
   664         }
   665         if ($type == "unset") {
   666             return $t->finish($t->parse('output', 'unset-param'));
   667         } elseif ($type == "text") {
   668             return $t->finish($t->parse('output', 'text-element'));
   669         } elseif ($type == "placeholder") {
   670             return $t->finish($t->parse('output', 'placeholder-element'));
   671         } elseif ($type == 'select') {
   672             $type_name = $type . '_' . $name;
   673             if ($group == 'Core') {
   674                 $fn = 'configmanager_' . $type_name . '_helper';
   675             } else {
   676                 $fn = 'plugin_configmanager_' . $type_name . '_' . $group;
   677             }
   678             if (function_exists($fn)) {
   679                 $selectionArray = $fn();
   680             } else if (is_array($selectionArray)) {
   681                 // leave sorting to the function otherwise
   682                 uksort($selectionArray, 'strcasecmp');
   683             }
   684             if (! is_array($selectionArray)) {
   685                 return $t->finish($t->parse('output', 'text-element'));
   686             }
   687 
   688             $t->set_block('select-element', 'select-options', 'myoptions');
   689             foreach ($selectionArray as $sName => $sVal) {
   690                 if (is_bool($sVal)) {
   691                     $t->set_var('opt_value', $sVal ? 'b:1' : 'b:0');
   692                 } else {
   693                     $t->set_var('opt_value', $sVal);
   694                 }
   695                 $t->set_var('opt_name', $sName);
   696                 $t->set_var('selected', ($val == $sVal ? 'selected="selected"' : ''));
   697                 $t->parse('myoptions', 'select-options', true);
   698             }
   699             return $t->parse('output', 'select-element');
   700         } elseif (strpos($type, '@') === 0) {
   701             $result = '';
   702             foreach ($val as $valkey => $valval) {
   703                 $result .= config::_UI_get_conf_element($group,
   704                                 $name . '[' . $valkey . ']',
   705                                 $display_name . '[' . $valkey . ']',
   706                                 substr($type, 1), $valval, $selectionArray,
   707                                 false);
   708             }
   709             return $result;
   710         } elseif (strpos($type, "*") === 0 || strpos($type, "%") === 0) {
   711             $t->set_var('arr_name', $name);
   712             $t->set_var('array_type', $type);
   713             $button = $t->parse('output', (strpos($type, "*") === 0 ?
   714                                            'keyed-add-button' :
   715                                            'unkeyed-add-button'));
   716             $t->set_var('my_add_element_button', $button);
   717             $result = "";
   718             foreach ($val as $valkey => $valval) {
   719                 $result .= config::_UI_get_conf_element($group,
   720                                 $name . '[' . $valkey . ']', $valkey,
   721                                 substr($type, 1), $valval, $selectionArray,
   722                                 true);
   723             }
   724             $t->set_var('my_elements', $result);
   725             return $t->parse('output', 'list-element');
   726         }
   727     }
   728 
   729     /**
   730      * This function takes $_POST input and evaluates it
   731      *
   732      * param array(string=>mixed)       $change_array this is the $_POST array
   733      * return array(string=>boolean)    this is the change_array
   734      */
   735     function updateConfig($change_array, $group)
   736     {
   737         global $_TABLES;
   738 
   739         if (!SEC_inGroup('Root')) {
   740             return null;
   741         }
   742 
   743         if ($group == 'Core') {
   744             /**
   745              * $_CONF['theme'] and $_CONF['language'] are overwritten with
   746              * the user's preferences in lib-common.php. Re-read values from
   747              * the database so that we're comparing the correct values below.
   748              */
   749             $value = DB_getItem($_TABLES['conf_values'], 'value',
   750                                 "group_name='Core' AND name='theme'");
   751             $this->config_array['Core']['theme'] = unserialize($value);
   752             $value = DB_getItem($_TABLES['conf_values'], 'value',
   753                                 "group_name='Core' AND name='language'");
   754             $this->config_array['Core']['language'] = unserialize($value);
   755 
   756             /**
   757              * Same with $_CONF['cookiedomain'], which is overwritten in
   758              * in lib-sessions.php (if empty).
   759              */
   760             $value = DB_getItem($_TABLES['conf_values'], 'value',
   761                                 "group_name='Core' AND name='cookiedomain'");
   762             $this->config_array['Core']['cookiedomain'] = unserialize($value);
   763         }
   764 
   765         $success_array = array();
   766         foreach ($this->config_array[$group] as $param_name => $param_value) {
   767             if (array_key_exists($param_name, $change_array)) {
   768                 $change_array[$param_name] =
   769                     $this->_validate_input($change_array[$param_name]);
   770                 if ($change_array[$param_name] != $param_value) {
   771                     $this->set($param_name, $change_array[$param_name], $group);
   772                     $success_array[$param_name] = true;
   773                 }
   774             }
   775         }
   776 
   777         return $success_array;
   778     }
   779 
   780     function _validate_input(&$input_val)
   781     {
   782         if (is_array($input_val)) {
   783             $r = array();
   784             foreach ($input_val as $key => $val) {
   785                 if ($key !== 'placeholder') {
   786                     $r[$key] = $this->_validate_input($val);
   787                 }
   788             }
   789         } else {
   790             $r = COM_stripslashes($input_val);
   791             if ($r == 'b:0' OR $r == 'b:1') {
   792                 $r = ($r == 'b:1');
   793             }
   794             if (is_numeric($r)) {
   795                 $r = $r + 0;
   796             }
   797         }
   798 
   799         return $r;
   800     }
   801 
   802 
   803     function _UI_configmanager_menu($conf_group,$sg=0)
   804     {
   805         global $_CONF, $LANG_ADMIN, $LANG_CONFIG,
   806                $LANG_configsections, $LANG_configsubgroups;
   807 
   808         $retval = COM_startBlock($LANG_CONFIG['sections'], '',
   809                         COM_getBlockTemplate('configmanager_block', 'header'));
   810         $link_array = array();
   811 
   812         $groups = $this->_get_groups();
   813         if (count($groups) > 0) {
   814             foreach ($groups as $group) {
   815                 if (empty($LANG_configsections[$group]['label'])) {
   816                     $group_display = ucwords($group);
   817                 } else {
   818                     $group_display = $LANG_configsections[$group]['label'];
   819                 }
   820                 // Create a menu item for each config group - disable the link for the current selected one
   821                 if ($conf_group == $group) {
   822                     $link = "<div>$group_display</div>";
   823                 } else {
   824                     $link = "<div><a href=\"#\" onclick='open_group(\"$group\")'>$group_display</a></div>";
   825                 }
   826 
   827                 if ($group == 'Core') {
   828                     $retval .= $link;
   829                 } else {
   830                     $link_array[$group_display] = $link;
   831                 }
   832             }
   833         }
   834 
   835         uksort($link_array, 'strcasecmp');
   836         foreach ($link_array as $link) {
   837             $retval .= $link;
   838         }
   839 
   840         $retval .= '<div><a href="' . $_CONF['site_admin_url'] . '">'
   841                 . $LANG_ADMIN['admin_home'] . '</a></div>';
   842         $retval .= COM_endBlock(COM_getBlockTemplate('configmanager_block',
   843                                                      'footer'));
   844 
   845 
   846         /* Now display the sub-group menu for the selected config group */
   847         if (empty($LANG_configsections[$conf_group]['title'])) {
   848             $subgroup_title = ucwords($conf_group);
   849         } else {
   850             $subgroup_title = $LANG_configsections[$conf_group]['title'];
   851         }
   852         $retval .= COM_startBlock($subgroup_title, '',
   853                     COM_getBlockTemplate('configmanager_subblock', 'header'));
   854 
   855         $sgroups = $this->_get_sgroups($conf_group);
   856         if (count($sgroups) > 0) {
   857             $i = 0;
   858             foreach ($sgroups as $sgname => $sgroup) {
   859                 if (isset($LANG_configsubgroups[$conf_group][$sgname])) {
   860                     $group_display = $LANG_configsubgroups[$conf_group][$sgname];
   861                 } else if (isset($LANG_configsubgroups[$conf_group][$sgroup])) {
   862                     $group_display = $LANG_configsubgroups[$conf_group][$sgroup];
   863                 } else {
   864                     $group_display = $sgname;
   865                 }
   866                 // Create a menu item for each sub config group - disable the link for the current selected one
   867                 if ($i == $sg) {
   868                     $retval .= "<div>$group_display</div>";
   869                 } else {
   870                     $retval .= "<div><a href=\"#\" onclick='open_subgroup(\"$conf_group\",\"$sgroup\")'>$group_display</a></div>";
   871                 }
   872                 $i++;
   873             }
   874         }
   875         $retval .= COM_endBlock(COM_getBlockTemplate('configmanager_block',
   876                                                      'footer'));
   877 
   878         return $retval;
   879     }
   880 
   881     /**
   882      * Helper function: Fix escaped SQL requests for MS SQL, if necessary
   883      *
   884      */
   885     function _DB_escapedQuery($sql)
   886     {
   887         global $_DB, $_DB_dbms;
   888 
   889         if ($_DB_dbms == 'mssql') {
   890             $sql = str_replace("\\'", "''", $sql);
   891             $sql = str_replace('\\"', '"', $sql);
   892             $_DB->dbQuery($sql, 0, 1);
   893         } else {
   894             DB_query($sql);
   895         }
   896     }
   897 
   898     /**
   899     * Helper function: Get the URL to the help section for a config option
   900     *
   901     * @param    string  $group      'Core' or plugin name
   902     * @param    string  $option     name of the config option
   903     * @return   string              full URL to help or empty string
   904     *
   905     */
   906     function _get_ConfigHelp($group, $option)
   907     {
   908         static $coreUrl;
   909 
   910         $retval = '';
   911 
   912         $descUrl = '';
   913         if ($group == 'Core') {
   914             if (isset($coreUrl)) {
   915                 $descUrl = $coreUrl;
   916             } elseif (!empty($GLOBALS['_CONF']['site_url']) &&
   917                     !empty($GLOBALS['_CONF']['path_html'])) {
   918                 $baseUrl = $GLOBALS['_CONF']['site_url'];
   919                 $doclang = COM_getLanguageName();
   920                 $cfg = 'docs/' . $doclang . '/config.html';
   921                 if (file_exists($GLOBALS['_CONF']['path_html'] . $cfg)) {
   922                     $descUrl = $baseUrl . '/' . $cfg;
   923                 } else {
   924                     $descUrl = $baseUrl . '/docs/english/config.html';
   925                 }
   926                 $coreUrl = $descUrl;
   927             } else {
   928                 $descUrl = 'http://www.geeklog.net/docs/english/config.html';
   929             }
   930         } else {
   931             $descUrl = PLG_getDocumentationUrl($group, 'config');
   932         }
   933 
   934         if (! empty($descUrl)) {
   935             $retval = $descUrl . '#desc_' . $option;
   936         }
   937 
   938         return $retval;
   939     }
   940 }
   941 
   942 ?>