git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@6095 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
515 lines
18 KiB
PHP
515 lines
18 KiB
PHP
<?php
|
|
/** DomFramework
|
|
* @package domframework
|
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
|
*/
|
|
|
|
/** Manage the configurations of the module done by administrator in a config
|
|
* file
|
|
* It is based on the module configuration defaults
|
|
* The DocType allow to define the configuration HTML page. It must contains
|
|
* @param : the name of the parameter
|
|
* @description : the textual description of the parameter
|
|
* @type : the type of the parameter (string, integer, array)
|
|
* @values : an array containing the allowed values to the parameter. Can be
|
|
* a function like timezone_identifiers_list
|
|
* @default : the default value (can be an array or a string or a number)
|
|
* @group : Group all the parameters in a group
|
|
* POC :
|
|
* $config = new config();
|
|
* $config->default = array ("param"=>"default",
|
|
* "param2"=>array (1,2,3),
|
|
* "param3"=>null);
|
|
* $var = $config->get ("param");
|
|
*/
|
|
class config
|
|
{
|
|
/** All the parameters allowed with their default value */
|
|
public $default = array ();
|
|
/** Use the .php to protect the information */
|
|
public $confFile = null;
|
|
|
|
/** Select the configuration file
|
|
*/
|
|
public function selectConfFile ()
|
|
{
|
|
if ($this->confFile !== null)
|
|
$this->confFile = $this->confFile;
|
|
elseif (defined("CONFIGFILE"))
|
|
$this->confFile = CONFIGFILE;
|
|
elseif (file_exists ("./datas/configuration.php"))
|
|
$this->confFile = "./datas/configuration.php";
|
|
elseif (file_exists ("./data/configuration.php"))
|
|
$this->confFile = "./data/configuration.php";
|
|
else
|
|
$this->confFile = "./data/configuration.php";
|
|
}
|
|
|
|
/** List all the parameters configurable in the software
|
|
*/
|
|
public function params ()
|
|
{
|
|
$this->selectConfFile ();
|
|
return $this->default;
|
|
}
|
|
|
|
/** Return the defined values in array format
|
|
*/
|
|
public function getAll ()
|
|
{
|
|
$this->selectConfFile ();
|
|
$conf = array ();
|
|
$rc = include ($this->confFile);
|
|
if ($rc !== 1)
|
|
throw new Exception ("Error in configuration file", 500);
|
|
return $conf;
|
|
}
|
|
|
|
/** Return the defined values in Slash format
|
|
*/
|
|
public function getAllInSlash ()
|
|
{
|
|
$conf = $this->getAll ();
|
|
$vals = array ();
|
|
foreach ($this->docComment () as $key)
|
|
{
|
|
if (! key_exists ("param", $key))
|
|
continue;
|
|
if (substr ($key["param"], 0, 1) !== "/")
|
|
throw new \Exception ("Config param '".$key["param"].
|
|
"' don't start by /");
|
|
$exp = explode ("/", $key["param"]);
|
|
unset ($exp[0]);
|
|
if (count ($exp) === 1 && key_exists ($exp[1], $conf))
|
|
$vals[$key["param"]] = $conf[$exp[1]];
|
|
elseif (count ($exp) === 2 && key_exists ($exp[1], $conf) &&
|
|
key_exists ($exp[2], $conf[$exp[1]]))
|
|
$vals[$key["param"]] = $conf[$exp[1]][$exp[2]];
|
|
elseif (count ($exp) === 3 && key_exists ($exp[1], $conf) &&
|
|
key_exists ($exp[2], $conf[$exp[1]]) &&
|
|
key_exists ($exp[3], $conf[$exp[1]][$exp[2]]))
|
|
$vals[$key["param"]] = $conf[$exp[1]][$exp[2]][$exp[3]];
|
|
}
|
|
return $vals;
|
|
}
|
|
|
|
/** Get the value of the provided parameter recorded in .php file
|
|
* If it is not set in .php file, use the default value
|
|
* @param string $param The option name to be returned
|
|
*/
|
|
public function get ($param)
|
|
{
|
|
$this->selectConfFile ();
|
|
if (!array_key_exists ($param, $this->default))
|
|
throw new Exception ("Unknown configuration parameter '$param'", 500);
|
|
if (!file_exists ($this->confFile))
|
|
{
|
|
if (@file_put_contents ($this->confFile,
|
|
"<?php\r\n\$conf = array ();\r\n")
|
|
=== FALSE)
|
|
throw new Exception (sprintf (dgettext ("domframework",
|
|
"No configuration file '%s' available and it can't be created"),
|
|
$this->confFile), 500);
|
|
}
|
|
elseif (! is_readable ($this->confFile))
|
|
throw new Exception (sprintf ( dgettext ("domframework",
|
|
"The configuration file '%s' is not readable"),
|
|
$this->confFile));
|
|
$conf = array ();
|
|
$rc = include ($this->confFile);
|
|
if ($rc !== 1)
|
|
throw new Exception ("Error in configuration file", 500);
|
|
if (! array_key_exists ($param, $this->default))
|
|
throw new Exception (sprintf ("Configuration parameter '%s' not defined",
|
|
$param), 500);
|
|
// Create a conf where all the keys are defined. If the keys are already
|
|
// define, use them, or use the default ones
|
|
// Don't allow keys not defined in default ones
|
|
if (! is_array ($this->default[$param]))
|
|
{
|
|
if (! array_key_exists ($param, $conf))
|
|
return $this->default[$param];
|
|
return $conf[$param];
|
|
}
|
|
foreach ($this->default[$param] as $key=>$val)
|
|
{
|
|
if ($key === "not configured")
|
|
{
|
|
if (! array_key_exists ($param, $conf))
|
|
continue;
|
|
foreach ($conf[$param] as $k=>$v)
|
|
{
|
|
$conf[$param][$k] = array_replace_recursive ($val,
|
|
$conf[$param][$k]);
|
|
}
|
|
continue;
|
|
}
|
|
if (! isset ($conf[$param][$key]))
|
|
$conf[$param][$key] = $val;
|
|
elseif (is_array ($val))
|
|
$conf[$param][$key] = array_replace_recursive ($val,
|
|
$conf[$param][$key]);
|
|
}
|
|
if (! array_key_exists ($param, $conf))
|
|
return $this->default[$param];
|
|
return $conf[$param];
|
|
}
|
|
|
|
/** Define a value for the parameter in the config file. Add all the default
|
|
* values if they are not defined
|
|
* @param string $param The option name
|
|
* @param mixed $value The option value
|
|
* @return TRUE if the parameter is saved or an exception
|
|
*/
|
|
public function set ($param, $value)
|
|
{
|
|
$this->selectConfFile ();
|
|
if (!array_key_exists ($param, $this->default))
|
|
throw new Exception ("Unknown parameter '$param'", 500);
|
|
if (!file_exists ($this->confFile))
|
|
{
|
|
if (@file_put_contents ($this->confFile,
|
|
"<?php\r\n\$conf =array ();\r\n")
|
|
=== FALSE)
|
|
throw new Exception (sprintf (
|
|
"No configuration file '%s' available and it can't be created",
|
|
$this->confFile));
|
|
}
|
|
elseif (! is_readable ($this->confFile))
|
|
throw new Exception (sprintf (
|
|
dgettext ("domframework",
|
|
"The configuration file '%s' is not readable"),
|
|
$this->confFile), 500);
|
|
if (!is_writeable ($this->confFile))
|
|
throw new Exception (sprintf (dgettext ("domframework",
|
|
"Configuration file '%s' is write protected"),
|
|
$this->confFile), 500);
|
|
$conf = array ();
|
|
$rc = include ($this->confFile);
|
|
if ($rc !== 1)
|
|
throw new Exception (dgettext ("domframework",
|
|
"Error in configuration file"), 500);
|
|
$newconf = array_merge ($this->default, $conf, array ($param=>$value));
|
|
$txt = "<?php\r\n";
|
|
$txt .= "\$conf = array(\r\n";
|
|
$txt = $this->writePHP ($newconf, $txt, 4);
|
|
$txt .= ");\r\n";
|
|
|
|
if (@file_put_contents ($this->confFile, $txt, LOCK_EX) === FALSE)
|
|
throw new Exception (sprintf (dgettext ("domframework",
|
|
"Can't save configuration file '%s'"),
|
|
$this->confFile), 500);
|
|
return TRUE;
|
|
}
|
|
|
|
/** Display the $values in PHP format to be "require" easily
|
|
* @param mixed $values Values to be recorded
|
|
* @param string $phpcode Actual value of the php code
|
|
* @param integer $indent Number of spaces in the indentation of config
|
|
*/
|
|
private function writePHP ($values, $phpcode, $indent)
|
|
{
|
|
foreach ($values as $key=>$val)
|
|
{
|
|
$phpcode .= str_pad (" ", $indent);
|
|
$phpcode .= (is_numeric ($key)) ? $key : "\"$key\"";
|
|
$phpcode .= " => ";
|
|
if (is_bool ($val))
|
|
{
|
|
if ($val === FALSE) $phpcode .= "FALSE,\r\n";
|
|
else $phpcode .= "TRUE,\r\n";
|
|
}
|
|
elseif (is_null ($val))
|
|
$phpcode .= "NULL,\r\n";
|
|
elseif (is_int ($val) || is_float ($val))
|
|
$phpcode .= "$val,\r\n";
|
|
elseif (is_string ($val))
|
|
$phpcode .= "\"$val\",\r\n";
|
|
elseif (is_array ($val))
|
|
{
|
|
$phpcode .= "array (\r\n";
|
|
$phpcode = $this->writePHP ($val, $phpcode, $indent+4);
|
|
$phpcode .= str_pad (" ", $indent);
|
|
$phpcode .= "),\r\n";
|
|
}
|
|
else
|
|
throw new Exception (dgettext ("domframework",
|
|
"Config : missing type ").gettype ($val), 500);
|
|
}
|
|
|
|
return $phpcode;
|
|
}
|
|
|
|
/** Convert a string to the right PHP type, without using the eval function
|
|
* @param string $values The string to convert
|
|
*/
|
|
private function strToType ($values)
|
|
{
|
|
$values = str_replace ("array (", "array(", $values);
|
|
if (stripos ($values, "array(") !== false)
|
|
{
|
|
$values = substr ($values, 6, -1);
|
|
$values = explode (",", $values);
|
|
$new = array ();
|
|
foreach ($values as $key=>$val)
|
|
{
|
|
$val = trim ($val);
|
|
if (strpos ($val, "=>") !== false)
|
|
{
|
|
// Associated array
|
|
unset ($values[$key]);
|
|
list ($key1, $val1) = explode ("=>", $val);
|
|
$key1 = trim ($key1);
|
|
$val1 = trim ($val1);
|
|
if ($val1[0] === "\"" || $val1[0] === "'")
|
|
$val1 = substr($val1, 1, -1);
|
|
elseif (strpos ($val1, "."))
|
|
$val1 = floatval ($val1);
|
|
else
|
|
$val1 = intval ($val1);
|
|
$new[$key1] = $val1;
|
|
}
|
|
else
|
|
{
|
|
// Unique value (string or integer or float)
|
|
if ($val[0] === "\"" || $val[0] === "'")
|
|
$val = substr($val, 1, -1);
|
|
elseif (strpos ($val, "."))
|
|
$val = floatval ($val);
|
|
else
|
|
$val = intval ($val);
|
|
$new[$key] = $val;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($values[0] === "\"" || $values[0] === "'" )
|
|
$new = substr ($values, 1, -1);
|
|
elseif (strpos ($values, "."))
|
|
$new = floatval ($values);
|
|
elseif ($values === "null")
|
|
$new = null;
|
|
elseif ($values === "false")
|
|
$new = "false";
|
|
elseif ($values === "true")
|
|
$new = "true";
|
|
else
|
|
$new = intval ($values);
|
|
}
|
|
return $new;
|
|
}
|
|
|
|
/** Update the configuration file with the provided parameters
|
|
* @param array $paramsSlash The parameters to analyze for updating the file
|
|
* The params are in an array like array ("/authentication/html" => "value")
|
|
* All the parameters are not needed
|
|
* To remove a parameter, set it to default value
|
|
*/
|
|
public function updateParamsSlash ($paramsSlash)
|
|
{
|
|
$debug = 0;
|
|
if ($debug) echo "<pre>";
|
|
if ($debug) echo "########## BEFORE\n";
|
|
if ($debug) echo "PARAMSLASH=";
|
|
if ($debug) var_dump ($paramsSlash);
|
|
// Check if the provided slash parameters are defined
|
|
$definitions = $this->docComment ();
|
|
// Actually stored values
|
|
$stored = $this->getAllInSlash ();
|
|
if ($debug) echo "stored =";
|
|
if ($debug) var_dump ($stored);
|
|
$new = array ();
|
|
// Update the stored values with the provided ones
|
|
foreach ($definitions as $key=>$unused)
|
|
{
|
|
if ($debug) echo "CHECK $key\n";
|
|
if (! key_exists ($key, $paramsSlash) && key_exists ($key, $stored))
|
|
{
|
|
if ($debug) echo "COPY the OLD value fo '$key' to the new array\n";
|
|
$new[$key] = $this->cast ($stored[$key]);
|
|
continue;
|
|
}
|
|
if (! key_exists ($key, $paramsSlash))
|
|
{
|
|
if ($debug) echo "Param $key not provided : skipped\n";
|
|
continue;
|
|
}
|
|
$val = $paramsSlash[$key];
|
|
if ($val === "")
|
|
{
|
|
if ($debug) echo "MUST REMOVE $key => Empty val\n";
|
|
}
|
|
// Do NOT use the === as the $val is always a string and must be compared
|
|
// with default integers
|
|
elseif (key_exists ("default", $definitions[$key]) &&
|
|
$this->cast ($val) ===
|
|
$this->cast ($definitions[$key]["default"]))
|
|
{
|
|
if ($debug) echo "MUST REMOVE $key => default\n";
|
|
}
|
|
elseif (key_exists ($key, $paramsSlash) && key_exists ($key, $stored) &&
|
|
$paramsSlash[$key] === $stored[$key])
|
|
{
|
|
if ($debug) echo "MUST COPY $key\n";
|
|
$new[$key] = $this->cast ($val);
|
|
}
|
|
elseif (key_exists ($key, $stored) && $stored[$key] !== $val)
|
|
{
|
|
if ($debug) echo "MUST OVERWRITE $key WITH NEW VALUE\n";
|
|
$new[$key] = $this->cast ($val);
|
|
}
|
|
elseif (! key_exists ($key, $stored))
|
|
{
|
|
if ($debug) echo "MUST ADD $key without DEFAULT\n";
|
|
$new[$key] = $this->cast ($val);
|
|
}
|
|
else
|
|
{
|
|
if ($debug) echo "NOT CATCHED !!!\n";
|
|
if ($debug) echo " STORED=";var_dump ($stored);
|
|
if ($debug) echo " DEFS=";var_dump ($definitions[$key]);
|
|
if ($debug) echo " SLASH=";var_dump ($val);
|
|
}
|
|
}
|
|
|
|
// Save the new stored values in the file
|
|
$txt = "<?php\n";
|
|
$txt .= "\$conf = array ();\n";
|
|
foreach ($new as $key=>$val)
|
|
{
|
|
$exp = explode ("/", substr ($key, 1));
|
|
$txt .= "\$conf['".implode ("']['", $exp)."'] = ".
|
|
var_export ($val, true).";\n";
|
|
}
|
|
if (file_put_contents ($this->confFile, $txt, LOCK_EX) === FALSE)
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Can't save configuration file '%s'"),
|
|
$this->confFile), 500);
|
|
// The next command clear the include cache file and force the PHP to
|
|
// read it again on next request.
|
|
// If it is not used, include () return the old value
|
|
opcache_invalidate ($this->confFile);
|
|
return TRUE;
|
|
}
|
|
|
|
/** Cast the provided string into the associated value
|
|
* @param string $val The val to cast
|
|
*/
|
|
private function cast ($val)
|
|
{
|
|
if (isset ($val[0]) && ($val[0] === "\"" || $val[0] === "'" ))
|
|
$new = substr ($val, 1, -1);
|
|
elseif ($val === "null")
|
|
$new = null;
|
|
elseif ($val === "false")
|
|
$new = false;
|
|
elseif ($val === "true")
|
|
$new = true;
|
|
elseif ($val === "")
|
|
$new = "";
|
|
elseif (is_array ($val))
|
|
$new = $val;
|
|
elseif (strspn ($val, "0123456789") === strlen ($val))
|
|
$new = intval ($val);
|
|
elseif (strspn ($val, "0123456789.") === strlen ($val))
|
|
$new = floatval ($val);
|
|
else
|
|
$new = $val;
|
|
return $new;
|
|
}
|
|
|
|
/** Return an array containing the definitions read from the default config
|
|
* file
|
|
* The definition of param are in Slash format
|
|
*/
|
|
public function docComment ()
|
|
{
|
|
$debug = 0;
|
|
$reflector = new ReflectionClass (get_class ($this));
|
|
$modelFile = $reflector->getFileName();
|
|
if (! file_exists ($modelFile))
|
|
throw new \Exception (dgettext ("domframework",
|
|
"The configuration model file is missing"), 500);
|
|
if (! is_readable ($modelFile))
|
|
throw new \Exception (dgettext ("domframework",
|
|
"The configuration model file is not readable"),
|
|
500);
|
|
$filecontent = file_get_contents ($modelFile);
|
|
$tokens = token_get_all ($filecontent);
|
|
$foundDefault = "";
|
|
$parenthesis = 0;
|
|
$params = array ();
|
|
$path = "";
|
|
$group = dgettext ("domframework", "Default parameters");
|
|
foreach ($tokens as $token)
|
|
{
|
|
if (is_array ($token))
|
|
{
|
|
list ($id, $text) = $token;
|
|
if ($debug) echo "ARRAY : $id (".token_name ($id)."), $text\n";
|
|
if ($foundDefault === "" && $text === "->")
|
|
$foundDefault = $text;
|
|
if ($id === T_DOC_COMMENT)
|
|
{
|
|
// Look at @param, @description, @type, @values, @default
|
|
if ($debug) echo "DOC_COMMENT : $text\n";
|
|
// Append the not completed lines
|
|
$text = trim (substr ($text, 3, -2));
|
|
$text = preg_replace ("/\n\s+\*?\s*/", " ", $text);
|
|
$text = preg_replace (
|
|
"/(@(param|description|type|values|default|group|prefix))/",
|
|
"\n\${1}", $text);
|
|
$text = ltrim ($text);
|
|
// Look at each parameter and save them in a data array
|
|
$data = array ();
|
|
foreach (explode ("\n", $text) as $line)
|
|
{
|
|
$tmp = explode (" ", $line);
|
|
$key = reset ($tmp);
|
|
$key = substr ($key, 1);
|
|
$data[$key] = trim (implode (" ", array_slice ($tmp, 1)));
|
|
}
|
|
if (isset ($data["group"]))
|
|
$group = $data["group"];
|
|
if (! isset ($data["param"]))
|
|
continue;
|
|
if (substr ($data["param"], 0, 1) !== "/")
|
|
throw new Exception (sprintf (dgettext ("domframework",
|
|
"Parameter '%s' doesn't start by slash"), $data["param"]), 500);
|
|
$data["depth"] = $parenthesis;
|
|
$data["group"] = $group;
|
|
//if (isset ($data["values"]) && $data["values"][0] !== "\"")
|
|
if (isset ($data["values"]))
|
|
{
|
|
// A function or an array or a number is provided
|
|
if ( function_exists ($data["values"]))
|
|
$data["values"] = call_user_func ($data["values"]);
|
|
elseif (is_string ($data["values"]))
|
|
$data["values"] = $this->strToType ($data["values"]);
|
|
}
|
|
if (isset ($data["default"]))
|
|
$data["default"] = $this->strToType ($data["default"]);
|
|
if ($debug) var_dump ($data);
|
|
$params[$data["param"]] = $data;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($debug) echo "TEXT : $token\n";
|
|
if ($foundDefault !== "" && $token === "(")
|
|
{
|
|
$parenthesis++;
|
|
}
|
|
if ($foundDefault !== "" && $token === ")")
|
|
{
|
|
$parenthesis--;
|
|
if ($parenthesis === 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return $params;
|
|
}
|
|
}
|