BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

env.class.php 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * ENV
  5. *
  6. * The PHP singleton is considered bad design for nebulous reasons,
  7. * but for securely loading a site config it does exactly what we need:
  8. *
  9. * - Ensure that only one instance of itself can ever exist
  10. * - Load the instance everywhere we need to do $ENV->VALUE
  11. * - No memory penalty because of multiple $ENV instances
  12. * - Static values in classes/config.php are immutable
  13. * - Site configs don't exist in the constants table
  14. * - Separate public and private config values
  15. *
  16. * @see https://stackoverflow.com/a/3724689
  17. * @see https://phpenthusiast.com/blog/the-singleton-design-pattern-in-php
  18. */
  19. class ENV
  20. {
  21. # Disinstantiates itself
  22. private static $ENV = null;
  23. # Config options receptacles
  24. private static $Priv = []; # Passwords, app keys, database, etc.
  25. private static $Pub = []; # Site meta, options, resources, etc.
  26. /**
  27. * __functions
  28. */
  29. # Prevents outside construction
  30. private function __construct()
  31. {
  32. # Would be expensive, e.g.,
  33. # $ENV = new ENV();
  34. return;
  35. }
  36. # Prevents multiple instances
  37. public function __clone()
  38. {
  39. return error('clone() not allowed.');
  40. }
  41. # Prevents unserializing
  42. public function __wakeup()
  43. {
  44. return error('wakeup() not allowed.');
  45. }
  46. # $this->key returns public->key
  47. public function __get($key)
  48. {
  49. return isset(self::$Pub[$key])
  50. ? self::$Pub[$key]
  51. : false;
  52. }
  53. # isset()
  54. public function __isset($key)
  55. {
  56. return isset(self::$Pub[$key]);
  57. }
  58. /**
  59. * Gets n' Sets
  60. */
  61. # Calls its self's creation or returns itself
  62. public static function go()
  63. {
  64. return (self::$ENV === null)
  65. ? self::$ENV = new ENV()
  66. : self::$ENV;
  67. }
  68. # get
  69. public static function getPriv($key)
  70. {
  71. return isset(self::$Priv[$key])
  72. ? self::$Priv[$key]
  73. : false;
  74. }
  75. public static function getPub($key)
  76. {
  77. return isset(self::$Pub[$key])
  78. ? self::$Pub[$key]
  79. : false;
  80. }
  81. # set
  82. public static function setPriv($key, $value)
  83. {
  84. return self::$Priv[$key] = $value;
  85. }
  86. public static function setPub($key, $value)
  87. {
  88. return self::$Pub[$key] = $value;
  89. }
  90. /**
  91. * convert
  92. *
  93. * Take a mixed input and returns a RecursiveArrayObject.
  94. * This function is the sausage grinder, so to speak.
  95. */
  96. public function convert($obj)
  97. {
  98. switch (gettype($obj)) {
  99. case 'string':
  100. $out = json_decode($obj, true);
  101. return (json_last_error() === JSON_ERROR_NONE)
  102. ? new RecursiveArrayObject($out)
  103. : error('json_last_error_msg(): ' . json_last_error_msg());
  104. break;
  105. case 'array':
  106. case 'object':
  107. return new RecursiveArrayObject($obj);
  108. default:
  109. return error('$ENV->convert() expects a JSON string, array, or object.');
  110. break;
  111. }
  112. }
  113. /**
  114. * toArray
  115. *
  116. * Takes an object and returns an array.
  117. * @param object|string $obj Thing to turn into an array
  118. * @return $new New recursive array with $obj contents
  119. * @see https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array
  120. */
  121. public function toArray($obj)
  122. {
  123. if (is_object($obj)) {
  124. $obj = (array) $obj;
  125. }
  126. if (is_array($obj)) {
  127. $new = array();
  128. foreach ($obj as $key => $value) {
  129. $new[$key] = $this->toArray($value);
  130. }
  131. } else {
  132. $new = $obj;
  133. }
  134. return $new;
  135. }
  136. /**
  137. * dedupe
  138. *
  139. * Takes a collection (usually an array) of various jumbled $ENV slices.
  140. * Returns a once-deduplicated RecursiveArrayObject with original nesting intact.
  141. * Simple and handy if you need to populate a form with arbitrary collections of metadata.
  142. */
  143. public function dedupe($obj)
  144. {
  145. if (is_object($obj)) {
  146. $obj = (array) $obj;
  147. }
  148. return new RecursiveArrayObject(
  149. array_unique($this->toArray($obj))
  150. );
  151. }
  152. /**
  153. * flatten
  154. *
  155. * Takes an $ENV node or array of them
  156. * and flattens out the multi-dimensionality.
  157. * It returns a flat array with keys intact.
  158. */
  159. public function flatten($arr, int $lvl = null)
  160. {
  161. if (!is_array($arr) && !is_object($arr)) {
  162. return error('$ENV->flatten() expects an array or object, got ' . gettype($arr));
  163. }
  164. $new = array();
  165. foreach ($arr as $k => $v) {
  166. /*
  167. if (is_object($v)) {
  168. $v = $this->toArray($v);
  169. }
  170. */
  171. if (is_array($v)) {
  172. $new = array_merge($new, $this->flatten($v));
  173. } else {
  174. $new[$k] = $v;
  175. }
  176. }
  177. return $new;
  178. }
  179. /**
  180. * map
  181. *
  182. * Simple array_map() object wrapper.
  183. * Maps a callback (or default) to an object.
  184. *
  185. * Example output:
  186. * $Hashes = $ENV->map('md5', $ENV->CATS->{6});
  187. *
  188. * var_dump($Hashes);
  189. * object(RecursiveArrayObject)#324 (1) {
  190. * ["storage":"ArrayObject":private]=>
  191. * array(6) {
  192. * ["ID"]=>
  193. * string(32) "28c8edde3d61a0411511d3b1866f0636"
  194. * ["Name"]=>
  195. * string(32) "fe83ccb5dc96dbc0658b3c4672c7d5fe"
  196. * ["Icon"]=>
  197. * string(32) "52963afccc006d2bce3c890ad9e8f73a"
  198. * ["Platforms"]=>
  199. * string(32) "d41d8cd98f00b204e9800998ecf8427e"
  200. * ["Formats"]=>
  201. * string(32) "d41d8cd98f00b204e9800998ecf8427e"
  202. * ["Description"]=>
  203. * string(32) "ca6628e8c13411c800d1d9d0eaccd849"
  204. * }
  205. * }
  206. *
  207. * var_dump($Hashes->Icon);
  208. * string(32) "52963afccc006d2bce3c890ad9e8f73a"
  209. *
  210. * @param string $fn Callback function
  211. * @param object|string $obj Object or property to operate on
  212. * @return object $RAO Mapped RecursiveArrayObject
  213. */
  214. public function map(string $fn = '', $obj = null)
  215. {
  216. # Set a default function if desired
  217. if (empty($fn) && !is_object($fn)) {
  218. $fn = 'array_filter';
  219. }
  220. # Quick sanity check
  221. if ($fn === 'array_map') {
  222. error("map() can't invoke the function it wraps.");
  223. }
  224. /**
  225. * $fn not a closure
  226. *
  227. * var_dump(
  228. * gettype(
  229. * (function() { return; })
  230. * ));
  231. * string(6) "object"
  232. */
  233. if (is_string($fn) && !is_object($fn)) {
  234. $fn = trim(strtok($fn, ' '));
  235. }
  236. # Map the sanitized function name
  237. # to a mapped array conversion
  238. return new RecursiveArrayObject(
  239. array_map(
  240. $fn,
  241. array_map(
  242. $fn,
  243. $this->toArray($obj)
  244. )
  245. )
  246. );
  247. }
  248. }
  249. /**
  250. * @author: etconsilium@github
  251. * @license: BSDLv2
  252. * @see https://github.com/etconsilium/php-recursive-array-object
  253. */
  254. class RecursiveArrayObject extends \ArrayObject
  255. {
  256. /**
  257. * __construct
  258. */
  259. public function __construct($input = null, $flags = self::ARRAY_AS_PROPS, $iterator_class = "ArrayIterator")
  260. {
  261. foreach ($input as $key => $value) {
  262. $this->__set($key, $value);
  263. }
  264. return $this;
  265. }
  266. /**
  267. * __set
  268. */
  269. public function __set($name, $value)
  270. {
  271. if (is_array($value) || is_object($value)) {
  272. $this->offsetSet($name, (new self($value)));
  273. } else {
  274. $this->offsetSet($name, $value);
  275. }
  276. }
  277. /**
  278. * __get
  279. */
  280. public function __get($name)
  281. {
  282. if ($this->offsetExists($name)) {
  283. return $this->offsetGet($name);
  284. } elseif (array_key_exists($name, $this)) {
  285. return $this[$name];
  286. } else {
  287. throw new \InvalidArgumentException(sprintf('$this have not prop `%s`', $name));
  288. }
  289. }
  290. /**
  291. * __isset
  292. */
  293. public function __isset($name)
  294. {
  295. return array_key_exists($name, $this);
  296. }
  297. /**
  298. * __unset
  299. */
  300. public function __unset($name)
  301. {
  302. unset($this[$name]);
  303. }
  304. }