ocPortal Developer's Guide: Options and values
» Return to Contents
The configuration interface defines two types of configuration datum:
- Options; these are options that a user chooses the value of and determine ocPortals behaviour
- Values; these are stored values that usually represent pre-calculated information (such as the download bandwidth tracking value)
sources/config.php
Global_functions_config.php
void init__config()
Standard code module initialisation function.
Parameters…
(No return value)
function init__config()
{
global $VALUES,$IN_MINIKERNEL_VERSION;
if ($IN_MINIKERNEL_VERSION==0)
{
load_options();
$VALUES=persistant_cache_get('VALUES');
if ($VALUES===NULL)
{
$VALUES=$GLOBALS['SITE_DB']->query_select('values',array('*'));
$VALUES=list_to_map('the_name',$VALUES);
persistant_cache_set('VALUES',$VALUES);
}
} else $VALUES=array();
global $GET_OPTION_LOOP;
$GET_OPTION_LOOP=0;
global $MULTI_LANG;
$MULTI_LANG=NULL;
// Enforce XML db synching
if ((get_db_type()=='xml') && (!running_script('xml_db_import')) && (is_file(get_file_base().'/data_custom/xml_db_import.php')) && (is_dir(get_file_base().'/.svn')))
{
$last_xml_import=get_value('last_xml_import');
$mod_time=filemtime(get_file_base().'/.svn');
if ((is_null($last_xml_import)) || (intval($last_xml_import)<$mod_time))
{
set_value('last_xml_import',strval(time()));
header('Location: '.get_base_url().'/data_custom/xml_db_import.php');
exit();
}
}
}
boolean multi_lang()
Find whether to run in multi-lang mode.
Parameters…
Returns…
| Description |
Whether to run in multi-lang mode. |
| Type |
boolean |
function multi_lang()
{
global $MULTI_LANG;
if ($MULTI_LANG!==NULL) return $MULTI_LANG;
$MULTI_LANG=false;
if (get_option('allow_international',true)!=='1') return false;
$_dir=opendir(get_file_base().'/lang/');
$_langs=array();
while (false!==($file=readdir($_dir)))
{
if (($file!=fallback_lang()) && ($file[0]!='.') && ($file[0]!='_') && ($file!='index.html') && ($file!='langs.ini') && ($file!='map.ini'))
{
if (is_dir(get_file_base().'/lang/'.$file)) $_langs[$file]='lang';
}
}
closedir($_dir);
if (!in_safe_mode())
{
$_dir=@opendir(get_custom_file_base().'/lang_custom/');
if ($_dir!==false)
{
while (false!==($file=readdir($_dir)))
{
if (($file!=fallback_lang()) && ($file[0]!='.') && ($file[0]!='_') && ($file!='index.html') && ($file!='langs.ini') && ($file!='map.ini') && (!isset($_langs[$file])))
{
if (is_dir(get_custom_file_base().'/lang_custom/'.$file)) $_langs[$file]='lang_custom';
}
}
closedir($_dir);
}
if (get_custom_file_base()!=get_file_base())
{
$_dir=opendir(get_file_base().'/lang_custom/');
while (false!==($file=readdir($_dir)))
{
if (($file!=fallback_lang()) && ($file[0]!='.') && ($file[0]!='_') && ($file!='index.html') && ($file!='langs.ini') && ($file!='map.ini') && (!isset($_langs[$file])))
{
if (is_dir(get_file_base().'/lang_custom/'.$file)) $_langs[$file]='lang_custom';
}
}
closedir($_dir);
}
}
foreach ($_langs as $lang=>$dir)
{
if (/*optimisation*/is_file((($dir=='lang_custom')?get_custom_file_base():get_file_base()).'/'.$dir.'/'.$lang.'/global.ini'))
{
$MULTI_LANG=true;
break;
}
$_dir2=@opendir((($dir=='lang_custom')?get_custom_file_base():get_file_base()).'/'.$dir.'/'.$lang);
if ($_dir2!==false)
{
while (false!==($file2=readdir($_dir2)))
{
if ((substr($file2,-4)=='.ini') || (substr($file2,-3)=='.po'))
{
$MULTI_LANG=true;
break;
}
}
}
}
return $MULTI_LANG;
}
void load_options()
Load all config options.
Parameters…
(No return value)
function load_options()
{
global $OPTIONS;
$OPTIONS=function_exists('persistant_cache_get')?persistant_cache_get('OPTIONS'):NULL;
if (is_array($OPTIONS)) return;
if (strpos(get_db_type(),'mysql')!==false)
{
global $SITE_INFO;
$OPTIONS=$GLOBALS['SITE_DB']->query_select('config c LEFT JOIN '.$GLOBALS['SITE_DB']->get_table_prefix().'translate t ON (c.config_value=t.id AND '.db_string_equal_to('t.language',array_key_exists('default_lang',$SITE_INFO)?$SITE_INFO['default_lang']:'EN').' AND ('.db_string_equal_to('c.the_type','transtext').' OR '.db_string_equal_to('c.the_type','transline').'))',array('c.the_name','c.config_value','c.the_type','c.c_set','t.text_original AS config_value_translated'),array(),'',NULL,NULL,true);
} else
{
$OPTIONS=$GLOBALS['SITE_DB']->query_select('config',array('the_name','config_value','the_type','c_set'),NULL,'',NULL,NULL,true);
}
if ($OPTIONS===NULL) critical_error('DATABASE_FAIL');
$OPTIONS=list_to_map('the_name',$OPTIONS);
if (function_exists('persistant_cache_set')) persistant_cache_set('OPTIONS',$OPTIONS);
}
?SHORT_TEXT get_tutorial_link(ID_TEXT name)
Find a specified tutorial link identifier.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
Returns…
| Description |
The value (NULL: value not found) |
| Type |
?SHORT_TEXT |
function get_tutorial_link($name)
{
return $GLOBALS['SITE_DB']->query_value_null_ok('tutorial_links','the_value',array('the_name'=>$name));
}
void set_tutorial_link(ID_TEXT name, SHORT_TEXT value)
Set the specified value to the specified tutorial link identifier.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
value |
| Description |
The value |
| Type |
SHORT_TEXT |
(No return value)
function set_tutorial_link($name,$value)
{
$GLOBALS['SITE_DB']->query_delete('tutorial_links',array('the_name'=>$name),'',1);
$GLOBALS['SITE_DB']->query_insert('tutorial_links',array('the_value'=>$value,'the_name'=>$name),false,true); // Allow failure, if there is a race condition
}
?SHORT_TEXT get_long_value(ID_TEXT name)
Find a specified long value. Long values are either really long strings, or just ones you don't want on each page load (i.e. it takes a query to read them, because you don't always need them).
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
Returns…
| Description |
The value (NULL: value not found) |
| Type |
?SHORT_TEXT |
function get_long_value($name)
{
return $GLOBALS['SITE_DB']->query_value_null_ok('long_values','the_value',array('the_name'=>$name));
}
?SHORT_TEXT get_long_value_newer_than(ID_TEXT name, TIME cutoff)
Find the specified configuration option if it is younger than a specified time.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
cutoff |
| Description |
The cutoff time (an absolute time, not a relative "time ago" |
| Type |
TIME |
Returns…
| Description |
The value (NULL: value newer than not found) |
| Type |
?SHORT_TEXT |
function get_long_value_newer_than($name,$cutoff)
{
return $GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT the_value FROM '.$GLOBALS['SITE_DB']->get_table_prefix().'long_values WHERE date_and_time>'.strval($cutoff).' AND '.db_string_equal_to('the_name',$name));
}
void set_long_value(ID_TEXT name, ?SHORT_TEXT value)
Set the specified situational value to the specified long value. Long values are either really long strings, or just ones you don't want on each page load (i.e. it takes a query to read them, because you don't always need them).
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
value |
| Description |
The value (NULL: delete it) |
| Type |
?SHORT_TEXT |
(No return value)
function set_long_value($name,$value)
{
$GLOBALS['SITE_DB']->query_delete('long_values',array('the_name'=>$name),'',1);
if ($value!==NULL)
{
$GLOBALS['SITE_DB']->query_insert('long_values',array('date_and_time'=>time(),'the_value'=>$value,'the_name'=>$name));
}
}
?SHORT_TEXT get_value(ID_TEXT name, ?ID_TEXT default, boolean env_also)
Find a specified value.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
default |
| Description |
Value to return if value not found (NULL: return NULL) |
| Default value |
|
| Type |
?ID_TEXT |
| Name |
env_also |
| Description |
Whether to also check server environmental variables |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The value (NULL: value not found and default is NULL) |
| Type |
?SHORT_TEXT |
function get_value($name,$default=NULL,$env_also=false)
{
global $IN_MINIKERNEL_VERSION,$VALUES;
if ($IN_MINIKERNEL_VERSION==1) return $default;
if (isset($VALUES[$name])) return $VALUES[$name]['the_value'];
if ($env_also)
{
$value=getenv($name);
if (($value!==false) && ($value!='')) return $value;
}
return $default;
}
?SHORT_TEXT get_value_newer_than(ID_TEXT name, TIME cutoff)
Find the specified configuration option if it is younger than a specified time.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
cutoff |
| Description |
The cutoff time (an absolute time, not a relative "time ago" |
| Type |
TIME |
Returns…
| Description |
The value (NULL: value newer than not found) |
| Type |
?SHORT_TEXT |
function get_value_newer_than($name,$cutoff)
{
$cutoff-=mt_rand(0,200); // Bit of scattering to stop locking issues if lots of requests hit this at once in the middle of a hit burst (whole table is read each page requests, and mysql will lock the table on set_value - causes horrible out-of-control buildups)
global $VALUES;
if ((array_key_exists($name,$VALUES)) && ($VALUES[$name]['date_and_time']>$cutoff)) return $VALUES[$name]['the_value'];
return NULL;
}
void set_value(ID_TEXT name, SHORT_TEXT value)
Set the specified situational value to the specified value.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
value |
| Description |
The value |
| Type |
SHORT_TEXT |
(No return value)
function set_value($name,$value)
{
global $VALUES;
$existed_before=array_key_exists($name,$VALUES);
$VALUES[$name]['the_value']=$value;
$VALUES[$name]['date_and_time']=time();
if ($existed_before)
{
$GLOBALS['SITE_DB']->query_update('values',array('date_and_time'=>time(),'the_value'=>$value),array('the_name'=>$name));
} else
{
$GLOBALS['SITE_DB']->query_insert('values',array('date_and_time'=>time(),'the_value'=>$value,'the_name'=>$name),false,true); // Allow failure, if there is a race condition
}
if (function_exists('persistant_cache_set')) persistant_cache_set('VALUES',$VALUES);
}
void delete_value(ID_TEXT name)
Delete a situational value.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
(No return value)
function delete_value($name)
{
$GLOBALS['SITE_DB']->query_delete('values',array('the_name'=>$name),'',1);
if (function_exists('persistant_cache_delete')) persistant_cache_delete('VALUES');
}
?SHORT_TEXT get_option(ID_TEXT name, boolean missing_ok)
Find the value of the specified configuration option.
Parameters…
| Name |
name |
| Description |
The name of the option |
| Type |
ID_TEXT |
| Name |
missing_ok |
| Description |
Where to accept a missing option (and return NULL) |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The value (NULL: either null value, or no option found whilst $missing_ok set) |
| Type |
?SHORT_TEXT |
function get_option($name,$missing_ok=false)
{
global $OPTIONS;
if (!isset($OPTIONS[$name]))
{
if ($missing_ok) return NULL;
require_code('config2');
find_lost_option($name);
}
$option=&$OPTIONS[$name];
// The master of redundant quick exit points. Has to be after the above IF due to weird PHP isset/NULL bug on some 5.1.4 (and possibly others)
if (isset($option['config_value_translated']))
{
if ($option['config_value_translated']=='<null>') return NULL;
return $option['config_value_translated'];
}
// Redundant, quick exit points
$type=$option['the_type'];
if (!isset($option['c_set'])) $option['c_set']=($option['config_value']===NULL)?0:1; // for compatibility during upgrades
if (($option['c_set']==1) && ($type!='transline') && ($type!='transtext'))
{
//@print_r($OPTIONS); exit($name.'='.gettype($option['config_value_translated']));
$option['config_value_translated']=$option['config_value']; // Allows slightly better code path next time
if ($option['config_value_translated']===NULL) $option['config_value_translated']='<null>';
$OPTIONS[$name]=$option;
if (function_exists('persistant_cache_set')) persistant_cache_set('OPTIONS',$OPTIONS);
if ($option['config_value']=='<null>') return NULL;
return $option['config_value'];
}
global $GET_OPTION_LOOP;
$GET_OPTION_LOOP=1;
// Find default if not set
if ($option['c_set']==0)
{
if (($type=='transline') || ($type=='transtext'))
{
if (defined('HIPHOP_PHP'))
{
require_code('hooks/systems/config_default/'.$name);
$hook=object_factory('Hook_config_default_'.$name);
$option['config_value_translated']=$hook->get_default();
} else
{
if (!isset($option['eval']))
{
global $SITE_INFO;
$OPTIONS=$GLOBALS['SITE_DB']->query_select('config c LEFT JOIN '.$GLOBALS['SITE_DB']->get_table_prefix().'translate t ON (c.config_value=t.id AND '.db_string_equal_to('t.language',array_key_exists('default_lang',$SITE_INFO)?$SITE_INFO['default_lang']:'EN').' AND ('.db_string_equal_to('c.the_type','transtext').' OR '.db_string_equal_to('c.the_type','transline').'))',array('c.the_name','c.config_value','c.eval','c.the_type','c.c_set','t.text_original AS config_value_translated'),array(),'');
$OPTIONS=list_to_map('the_name',$OPTIONS);
$option=&$OPTIONS[$name];
}
$option['config_value_translated']=eval($option['eval'].';');
if (is_object($option['config_value_translated'])) $option['config_value_translated']=$option['config_value_translated']->evaluate();
if (get_value('setup_wizard_completed')==='1')
{
require_code('config2');
set_option($name,($option['config_value_translated']===NULL)?'<null>':$option['config_value_translated']);
}
}
if (is_object($option['config_value_translated'])) $option['config_value_translated']=$option['config_value_translated']->evaluate();
$GET_OPTION_LOOP=0;
return $option['config_value_translated'];
}
// if ((!function_exists('do_lang')) && (strpos($option['eval'],'do_lang')!==false)) @debug_print_backtrace();
if (defined('HIPHOP_PHP'))
{
require_code('hooks/systems/config_default/'.$name);
$hook=object_factory('Hook_config_default_'.$name);
$option['config_value']=$hook->get_default();
} else
{
if (!isset($option['eval']))
{
global $SITE_INFO;
$OPTIONS=$GLOBALS['SITE_DB']->query_select('config c LEFT JOIN '.$GLOBALS['SITE_DB']->get_table_prefix().'translate t ON (c.config_value=t.id AND '.db_string_equal_to('t.language',array_key_exists('default_lang',$SITE_INFO)?$SITE_INFO['default_lang']:'EN').' AND ('.db_string_equal_to('c.the_type','transtext').' OR '.db_string_equal_to('c.the_type','transline').'))',array('c.the_name','c.config_value','c.eval','c.the_type','c.c_set','t.text_original AS config_value_translated'),array(),'');
$OPTIONS=list_to_map('the_name',$OPTIONS);
$option=&$OPTIONS[$name];
}
require_code('lang');
$option['config_value']=eval($option['eval'].';');
if (get_value('setup_wizard_completed')==='1')
{
require_code('config2');
set_option($name,($option['config_value']===NULL)?'<null>':$option['config_value']);
}
}
if (is_object($option['config_value'])) $option['config_value']=$option['config_value']->evaluate(); elseif (is_integer($option['config_value'])) $option['config_value']=strval($option['config_value']);
$GET_OPTION_LOOP=0;
$option['c_set']=1;
return $option['config_value'];
}
// Translations if needed
if (($type=='transline') || ($type=='transtext'))
{
if (!isset($option['config_value_translated']))
{
$option['config_value_translated']=get_translated_text(intval($option['config_value']));
$OPTIONS[$name]=$option;
persistant_cache_set('OPTIONS',$OPTIONS);
}
// Answer
$GET_OPTION_LOOP=0;
return $option['config_value_translated'];
}
// Answer
$GET_OPTION_LOOP=0;
return $option['config_value'];
}
void update_stat(ID_TEXT stat, integer increment)
Increment the specified stored value, by the specified amount.
Parameters…
| Name |
stat |
| Description |
The codename for the stat |
| Type |
ID_TEXT |
| Name |
increment |
| Description |
What to increment the statistic by |
| Type |
integer |
(No return value)
function update_stat($stat,$increment)
{
if (running_script('stress_test_loader')) return;
$current=get_value($stat);
if (is_null($current)) $current='0';
$new=intval($current)+$increment;
set_value($stat,strval($new));
}
ID_TEXT invert_value(ID_TEXT old)
Very simple function to invert the meaning of an old hidden option. We often use this when we've promoted a hidden option into a new proper option but inverted the meaning in the process - we use this in the default value generation code, as an in-line aid to preserve existing hidden option settings.
Parameters…
| Name |
old |
| Description |
The old value |
| Type |
ID_TEXT |
| Values restricted to |
0 1 |
Returns…
| Description |
The inverted value |
| Type |
ID_TEXT |
function invert_value($old)
{
if ($old=='1') return '0';
return '1';
}
sources/config2.php
Global_functions_config2.php
void find_lost_option(ID_TEXT name)
An option has dissappeared somehow - find it via searching our code-base for it's install code. It doesn't get returned, just loaded up. This function will produce a fatal error if we cannot find it.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
(No return value)
function find_lost_option($name)
{
global $OPTIONS;
// In the dark dark past, we'd bomb out...
if ((function_exists('find_all_zones')) && (!defined('HIPHOP_PHP')))
{
// However times are pleasant, the grass is green, the sun high is the summer sky. Let's perform some voodoo magic...
$all_zones=find_all_zones();
$search=array();
$types=array('modules_custom','modules');
foreach ($all_zones as $zone)
{
foreach ($types as $type)
{
$pages=find_all_pages($zone,$type);
foreach ($pages as $page=>$type)
{
$search[]=zone_black_magic_filterer(get_file_base().'/'.$zone.(($zone!='')?'/':'').'pages/'.$type.'/'.$page.'.php');
}
}
}
require_code('zones2');
require_code('zones3');
$all_blocks=find_all_blocks();
foreach ($all_blocks as $block=>$type)
{
$search[]=get_file_base().'/'.$type.'/blocks/'.$block.'.php';
}
if (file_exists(get_file_base().'/sources_custom/ocf_install.php'))
$search[]=get_file_base().'/sources_custom/ocf_install.php';
$search[]=get_file_base().'/sources/ocf_install.php';
$matches=array();
foreach ($search as $s)
{
// echo $s.'<br />';
$code=file_get_contents($s);
if (preg_match('#add_config_option\(\'\w+\',\''.str_replace('#','\#',preg_quote($name)).'\',\'\w+\',\'.+\',\'\w+\',\'\w+\'(,1)?\);#',$code,$matches)>0)
{
require_code('database_action');
$upgrade_from=NULL; // In case referenced in add_config_option line
eval($matches[0]);
load_options();
break;
// fatal_exit(do_ lang_tempcode('CONFIG_OPTION_FETCHED',escape_html($name))); CONFIG_OPTION_FETCHED=A config option ({1}) was missing, but has been hunted down and installed. This is an unexpected inconsistency, please refresh the page, and hopefully it has been permanently corrected.
}
}
}
if (!array_key_exists($name,$OPTIONS)) fatal_exit(do_lang_tempcode('_MISSING_OPTION',escape_html($name)));
}
void set_option(ID_TEXT name, LONG_TEXT value, ?ID_TEXT type, ?LONG_TEXT current_value)
Set a configuration option with the specified values.
Parameters…
| Name |
name |
| Description |
The name of the value |
| Type |
ID_TEXT |
| Name |
value |
| Description |
The value |
| Type |
LONG_TEXT |
| Name |
type |
| Description |
The type of the option. This is normally ommited, but to save a DB lookup, may be passed through (NULL: work out the type) |
| Default value |
|
| Type |
?ID_TEXT |
| Values restricted to |
float integer tick line text transline transtext list date forum category usergroup |
| Name |
current_value |
| Description |
The current value of the config option (NULL: unknown). This is just for efficiency for remapping language config options. |
| Default value |
|
| Type |
?LONG_TEXT |
(No return value)
function set_option($name,$value,$type=NULL,$current_value=NULL)
{
global $OPTIONS;
if (is_null($type))
{
global $GET_OPTION_LOOP;
if ($GET_OPTION_LOOP!=1)
get_option($name); // Ensure it's installed
$type=$OPTIONS[$name]['the_type']; //$type=$GLOBALS['SITE_DB']->query_value('config','the_type',array('the_name'=>$name));
}
if (($type=='transline') || ($type=='transtext'))
{
// $current_value=$GLOBALS['SITE_DB']->query_value('config','config_value',array('the_name'=>$name));
if ((array_key_exists('c_set',$OPTIONS[$name])) && ($OPTIONS[$name]['c_set']==0))
{
$GLOBALS['SITE_DB']->query_update('config',array('config_value'=>strval(insert_lang($value,1)),'c_set'=>1),array('the_name'=>$name),'',1);
} else
{
$current_value=$OPTIONS[$name]['config_value'];
if (!is_null($current_value)) // Should never happen, but might during upgrading
lang_remap(intval($current_value),$value);
}
} else
{
$map=array('config_value'=>$value);
if (array_key_exists('c_set',$OPTIONS[$name])) $map['c_set']=1;
$GLOBALS['SITE_DB']->query_update('config',$map,array('the_name'=>$name),'',1);
$OPTIONS[$name]['config_value']=$value;
}
$OPTIONS[$name]['config_value_translated']=$value;
if (function_exists('log_it'))
{
require_lang('config');
log_it('CONFIGURATION',$name,$value);
}
if (function_exists('persistant_cache_delete'))
persistant_cache_delete('OPTIONS');
}
Tutorial - Adding a Configuration Option
Adding a configuration option is necessary for many modules, so I will show you how to do so in this tutorial.
1) Open up your module, and find the install function.
2) Add the following code:
Code (php)
do_config_option('SECTION_CHAT','is_on_chat','tick','return 1;','FEATURE','SECTION_CHAT');
Explanation:
Argument 1: The human-readable name for this configuration, this is a language INI file entry.
Argument 2: The actual backend name for this option; this is the name you will use to refer to it in code.
Argument 3: The type of the option (i.e. the type of form element used), see the
templates section for further details
Argument 4: The default value, this is actually PHP code that is stored in the database and evaluated as required, so don't forget the semicolon (';')!
Argument 5: The configuration page that this option will be on.
Argument 6: The section this configuration option will be in, this is a language INI file entry.
0 reviews: Unrated (average)
There have been no comments yet