PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
Config.php
1 <?php
2 
3 /*
4  *
5  * ____ _ _ __ __ _ __ __ ____
6  * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7  * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8  * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9  * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * @author PocketMine Team
17  * @link http://www.pocketmine.net/
18  *
19  *
20 */
21 
22 namespace pocketmine\utils;
23 
24 
30 class Config{
31  const DETECT = -1; //Detect by file extension
32  const PROPERTIES = 0; // .properties
33  const CNF = Config::PROPERTIES; // .cnf
34  const JSON = 1; // .js, .json
35  const YAML = 2; // .yml, .yaml
36  //const EXPORT = 3; // .export, .xport
37  const SERIALIZED = 4; // .sl
38  const ENUM = 5; // .txt, .list, .enum
39  const ENUMERATION = Config::ENUM;
40 
42  private $config = [];
44  private $file;
46  private $correct = false;
48  private $type = Config::DETECT;
49 
50  public static $formats = [
51  "properties" => Config::PROPERTIES,
52  "cnf" => Config::CNF,
53  "conf" => Config::CNF,
54  "config" => Config::CNF,
55  "json" => Config::JSON,
56  "js" => Config::JSON,
57  "yml" => Config::YAML,
58  "yaml" => Config::YAML,
59  //"export" => Config::EXPORT,
60  //"xport" => Config::EXPORT,
61  "sl" => Config::SERIALIZED,
62  "serialize" => Config::SERIALIZED,
63  "txt" => Config::ENUM,
64  "list" => Config::ENUM,
65  "enum" => Config::ENUM,
66  ];
67 
74  public function __construct($file, $type = Config::DETECT, $default = [], &$correct = null){
75  $this->load($file, $type, $default);
76  $correct = $this->correct;
77  }
78 
82  public function reload(){
83  $this->config = [];
84  $this->correct = false;
85  unset($this->type);
86  $this->load($this->file);
87  }
88 
94  public static function fixYAMLIndexes($str){
95  return preg_replace("#^([ ]*)([a-zA-Z_]{1}[^\:]*)\:#m", "$1\"$2\":", $str);
96  }
97 
105  public function load($file, $type = Config::DETECT, $default = []){
106  $this->correct = true;
107  $this->type = (int) $type;
108  $this->file = $file;
109  if(!is_array($default)){
110  $default = [];
111  }
112  if(!file_exists($file)){
113  $this->config = $default;
114  $this->save();
115  }else{
116  if($this->type === Config::DETECT){
117  $extension = explode(".", basename($this->file));
118  $extension = strtolower(trim(array_pop($extension)));
119  if(isset(Config::$formats[$extension])){
120  $this->type = Config::$formats[$extension];
121  }else{
122  $this->correct = false;
123  }
124  }
125  if($this->correct === true){
126  $content = @file_get_contents($this->file);
127  switch($this->type){
128  case Config::PROPERTIES:
129  case Config::CNF:
130  $this->parseProperties($content);
131  break;
132  case Config::JSON:
133  $this->config = json_decode($content, true);
134  break;
135  case Config::YAML:
136  $content = self::fixYAMLIndexes($content);
137  $this->config = yaml_parse($content);
138  break;
139  case Config::SERIALIZED:
140  $this->config = unserialize($content);
141  break;
142  case Config::ENUM:
143  $this->parseList($content);
144  break;
145  default:
146  $this->correct = false;
147 
148  return false;
149  }
150  if(!is_array($this->config)){
151  $this->config = $default;
152  }
153  if($this->fillDefaults($default, $this->config) > 0){
154  $this->save();
155  }
156  }else{
157  return false;
158  }
159  }
160 
161  return true;
162  }
163 
167  public function check(){
168  return $this->correct === true;
169  }
170 
174  public function save(){
175  if($this->correct === true){
176  $content = null;
177  switch($this->type){
178  case Config::PROPERTIES:
179  case Config::CNF:
180  $content = $this->writeProperties();
181  break;
182  case Config::JSON:
183  $content = json_encode($this->config, JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING);
184  break;
185  case Config::YAML:
186  $content = yaml_emit($this->config, YAML_UTF8_ENCODING);
187  break;
188  case Config::SERIALIZED:
189  $content = @serialize($this->config);
190  break;
191  case Config::ENUM:
192  $content = implode("\r\n", array_keys($this->config));
193  break;
194  }
195  @file_put_contents($this->file, $content, LOCK_EX);
196 
197  return true;
198  }else{
199  return false;
200  }
201  }
202 
208  public function __get($k){
209  return $this->get($k);
210  }
211 
216  public function __set($k, $v){
217  $this->set($k, $v);
218  }
219 
225  public function __isset($k){
226  return $this->exists($k);
227  }
228 
232  public function __unset($k){
233  $this->remove($k);
234  }
235 
240  public function setNested($key, $value){
241  $vars = explode(".", $key);
242  $base = array_shift($vars);
243 
244  if(!isset($this->config[$base])){
245  $this->config[$base] = [];
246  }
247 
248  $base =& $this->config[$base];
249 
250  while(count($vars) > 0){
251  $baseKey = array_shift($vars);
252  if(!isset($base[$baseKey])){
253  $base[$baseKey] = [];
254  }
255  $base =& $base[$baseKey];
256  }
257 
258  $base = $value;
259  }
260 
267  public function getNested($key, $default = null){
268  $vars = explode(".", $key);
269  $base = array_shift($vars);
270  if(isset($this->config[$base])){
271  $base = $this->config[$base];
272  }else{
273  return $default;
274  }
275 
276  while(count($vars) > 0){
277  $baseKey = array_shift($vars);
278  if(is_array($base) and isset($base[$baseKey])){
279  $base = $base[$baseKey];
280  }else{
281  return $default;
282  }
283  }
284 
285  return $base;
286  }
287 
294  public function get($k, $default = false){
295  return ($this->correct and isset($this->config[$k])) ? $this->config[$k] : $default;
296  }
297 
305  public function getPath($path){
306  $currPath =& $this->config;
307  foreach(explode(".", $path) as $component){
308  if(isset($currPath[$component])){
309  $currPath =& $currPath[$component];
310  }else{
311  $currPath = null;
312  }
313  }
314 
315  return $currPath;
316  }
317 
325  public function setPath($path, $value){
326  $currPath =& $this->config;
327  $components = explode(".", $path);
328  $final = array_pop($components);
329  foreach($components as $component){
330  if(!isset($currPath[$component])){
331  $currPath[$component] = [];
332  }
333  $currPath =& $currPath[$component];
334  }
335  $currPath[$final] = $value;
336  }
337 
342  public function set($k, $v = true){
343  $this->config[$k] = $v;
344  }
345 
349  public function setAll($v){
350  $this->config = $v;
351  }
352 
359  public function exists($k, $lowercase = false){
360  if($lowercase === true){
361  $k = strtolower($k); //Convert requested key to lower
362  $array = array_change_key_case($this->config, CASE_LOWER); //Change all keys in array to lower
363  return isset($array[$k]); //Find $k in modified array
364  }else{
365  return isset($this->config[$k]);
366  }
367  }
368 
372  public function remove($k){
373  unset($this->config[$k]);
374  }
375 
381  public function getAll($keys = false){
382  return ($keys === true ? array_keys($this->config) : $this->config);
383  }
384 
388  public function setDefaults(array $defaults){
389  $this->fillDefaults($defaults, $this->config);
390  }
391 
398  private function fillDefaults($default, &$data){
399  $changed = 0;
400  foreach($default as $k => $v){
401  if(is_array($v)){
402  if(!isset($data[$k]) or !is_array($data[$k])){
403  $data[$k] = [];
404  }
405  $changed += $this->fillDefaults($v, $data[$k]);
406  }elseif(!isset($data[$k])){
407  $data[$k] = $v;
408  ++$changed;
409  }
410  }
411 
412  return $changed;
413  }
414 
418  private function parseList($content){
419  foreach(explode("\n", trim(str_replace("\r\n", "\n", $content))) as $v){
420  $v = trim($v);
421  if($v == ""){
422  continue;
423  }
424  $this->config[$v] = true;
425  }
426  }
427 
431  private function writeProperties(){
432  $content = "#Properties Config file\r\n#" . date("D M j H:i:s T Y") . "\r\n";
433  foreach($this->config as $k => $v){
434  if(is_bool($v) === true){
435  $v = $v === true ? "on" : "off";
436  }elseif(is_array($v)){
437  $v = implode(";", $v);
438  }
439  $content .= $k . "=" . $v . "\r\n";
440  }
441 
442  return $content;
443  }
444 
448  private function parseProperties($content){
449  if(preg_match_all('/([a-zA-Z0-9\-_\.]*)=([^\r\n]*)/u', $content, $matches) > 0){ //false or 0 matches
450  foreach($matches[1] as $i => $k){
451  $v = trim($matches[2][$i]);
452  switch(strtolower($v)){
453  case "on":
454  case "true":
455  case "yes":
456  $v = true;
457  break;
458  case "off":
459  case "false":
460  case "no":
461  $v = false;
462  break;
463  }
464  if(isset($this->config[$k])){
465  MainLogger::getLogger()->debug("[Config] Repeated property " . $k . " on file " . $this->file);
466  }
467  $this->config[$k] = $v;
468  }
469  }
470  }
471 
472 }
setDefaults(array $defaults)
Definition: Config.php:388
load($file, $type=Config::DETECT, $default=[])
Definition: Config.php:105
set($k, $v=true)
Definition: Config.php:342
setNested($key, $value)
Definition: Config.php:240
getNested($key, $default=null)
Definition: Config.php:267
__construct($file, $type=Config::DETECT, $default=[], &$correct=null)
Definition: Config.php:74
setPath($path, $value)
Definition: Config.php:325
getAll($keys=false)
Definition: Config.php:381
exists($k, $lowercase=false)
Definition: Config.php:359
static fixYAMLIndexes($str)
Definition: Config.php:94