fundamentals.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. <?php
  2. // This Source Code Form is subject to the terms of the Mozilla Public
  3. // License, v. 2.0. If a copy of the MPL was not distributed with this
  4. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. // == | Setup | =======================================================================================================
  6. // Check if the basic defines have been defined in the including script
  7. foreach (['ROOT_PATH', 'DEBUG_MODE', 'SOFTWARE_NAME', 'SOFTWARE_VERSION'] as $_value) {
  8. if (!defined($_value)) {
  9. die('Binary Outcast Metropolis Fundamentals: ' . $_value . ' must be defined before including this script.');
  10. }
  11. }
  12. // Do not allow this to be included more than once...
  13. if (defined('BINOC_FUNCTIONS')) {
  14. die('Binary Outcast Metropolis Fundamentals: You may not include this more than once.');
  15. }
  16. // Define that this is a thing.
  17. define('BINOC_FUNCTIONS', 1);
  18. // ====================================================================================================================
  19. // == | Global Constants | ============================================================================================
  20. const PHP_ERROR_CODES = array(
  21. E_ERROR => 'Fatal Error',
  22. E_WARNING => 'Warning',
  23. E_PARSE => 'Parse',
  24. E_NOTICE => 'Notice',
  25. E_CORE_ERROR => 'Fatal Error (Core)',
  26. E_CORE_WARNING => 'Warning (Core)',
  27. E_COMPILE_ERROR => 'Fatal Error (Compile)',
  28. E_COMPILE_WARNING => 'Warning (Compile)',
  29. E_USER_ERROR => 'Fatal Error (User Generated)',
  30. E_USER_WARNING => 'Warning (User Generated)',
  31. E_USER_NOTICE => 'Notice (User Generated)',
  32. E_STRICT => 'Strict',
  33. E_RECOVERABLE_ERROR => 'Fatal Error (Recoverable)',
  34. E_DEPRECATED => 'Deprecated',
  35. E_USER_DEPRECATED => 'Deprecated (User Generated)',
  36. E_ALL => 'All'
  37. );
  38. const HTTP_HEADERS = array(
  39. 404 => 'HTTP/1.1 404 Not Found',
  40. 501 => 'HTTP/1.1 501 Not Implemented',
  41. 'text' => 'Content-Type: text/plain',
  42. 'html' => 'Content-Type: text/html',
  43. 'css' => 'Content-Type: text/css',
  44. 'xml' => 'Content-Type: text/xml',
  45. 'json' => 'Content-Type: application/json',
  46. 'bin' => 'Content-Type: application/octet-stream',
  47. 'xpi' => 'Content-Type: application/x-xpinstall',
  48. );
  49. // --------------------------------------------------------------------------------------------------------------------
  50. const NEW_LINE = "\n";
  51. const EMPTY_STRING = "";
  52. const EMPTY_ARRAY = [];
  53. const SPACE = " ";
  54. const WILDCARD = "*";
  55. const SLASH = "/";
  56. const DOT = ".";
  57. const DASH = "-";
  58. const UNDERSCORE = "_";
  59. const DOTDOT = DOT . DOT;
  60. // --------------------------------------------------------------------------------------------------------------------
  61. const DASH_SEPARATOR = SPACE . DASH . SPACE;
  62. const SCHEME_SUFFIX = "://";
  63. const PHP_EXTENSION = DOT . 'php';
  64. const INI_EXTENSION = DOT . 'ini';
  65. const HTML_EXTENSION = DOT . 'html';
  66. const XML_EXTENSION = DOT . 'xml';
  67. const RDF_EXTENSION = DOT . 'rdf';
  68. const JSON_EXTENSION = DOT . 'json';
  69. const CONTENT_EXTENSION = DOT . 'content';
  70. const XPINSTALL_EXTENSION = DOT . 'xpi';
  71. const TEMP_EXTENSION = DOT . 'temp';
  72. // --------------------------------------------------------------------------------------------------------------------
  73. const XML_TAG = '<?xml version="1.0" encoding="utf-8" ?>';
  74. // --------------------------------------------------------------------------------------------------------------------
  75. const RDF_INSTALL_MANIFEST = 'install' . DOT . RDF_EXTENSION;
  76. const JSON_INSTALL_MANIFEST = 'install' . DOT . JSON_EXTENSION;
  77. // --------------------------------------------------------------------------------------------------------------------
  78. const JSON_ENCODE_FLAGS = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
  79. const FILE_WRITE_FLAGS = "w+";
  80. // --------------------------------------------------------------------------------------------------------------------
  81. const REGEX_GET_FILTER = "/[^-a-zA-Z0-9_\-\/\{\}\@\.\%\s\,]/";
  82. const REGEX_YAML_FILTER = "/\A---(.|\n)*?---/";
  83. const REGEX_GUID = "/^\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}$/i";
  84. const REGEX_HOST = "/[a-z0-9-\._]+\@[a-z0-9-\._]+/i";
  85. // ====================================================================================================================
  86. // == | Global Functions | ============================================================================================
  87. /**********************************************************************************************************************
  88. * Polyfills for str_starts_with, str_ends_with, str_contains
  89. *
  90. * @param $haystack string
  91. * @param $needle substring
  92. * @returns true if substring exists in string else false
  93. **********************************************************************************************************************/
  94. if (!function_exists('str_starts_with')) {
  95. function str_starts_with($haystack, $needle) {
  96. $length = strlen($needle);
  97. return (substr($haystack, 0, $length) === $needle);
  98. }
  99. // Compatibility with previously used polyfill function name
  100. function startsWith(...$aArgs) {
  101. return str_starts_with(...$aArgs);
  102. }
  103. }
  104. // --------------------------------------------------------------------------------------------------------------------
  105. if (!function_exists('str_ends_with')) {
  106. function str_ends_with($haystack, $needle) {
  107. $length = strlen($needle);
  108. if ($length == 0) {
  109. return true;
  110. }
  111. return (substr($haystack, -$length) === $needle);
  112. }
  113. // Compatibility with previously used polyfill function name
  114. function endsWith(...$aArgs) {
  115. return str_ends_with(...$aArgs);
  116. }
  117. }
  118. // --------------------------------------------------------------------------------------------------------------------
  119. if (!function_exists('str_contains')) {
  120. function str_contains($haystack, $needle) {
  121. if (strpos($haystack, $needle) > -1) {
  122. return true;
  123. }
  124. else {
  125. return false;
  126. }
  127. }
  128. // Compatibility with previously used polyfill function name
  129. function contains(...$aArgs) {
  130. return str_contains(...$aArgs);
  131. }
  132. }
  133. /**********************************************************************************************************************
  134. * Error function that will display data (Error Message)
  135. *
  136. * This version of the function can emit the error as xml or text depending on the environment.
  137. * It also can use gfGenContent() if defined and has the same signature.
  138. * It also has its legacy ability for generic output if the error message is not a string as formatted json
  139. * regardless of the environment.
  140. *
  141. * @dep gfGenContent() - conditional
  142. * @dep NEW_LINE
  143. * @dep XML_TAG
  144. * @dep JSON_ENCODE_FLAGS
  145. **********************************************************************************************************************/
  146. function gfError($aValue, $phpError = false) {
  147. $pageHeader = array(
  148. 'default' => 'Unable to Comply',
  149. 'fatal' => 'Fatal Error',
  150. 'php' => 'PHP Error',
  151. 'output' => 'Output'
  152. );
  153. $externalOutput = function_exists('gfGenContent');
  154. $isCLI = (php_sapi_name() == "cli");
  155. $isOutput = false;
  156. if (is_string($aValue) || is_int($aValue)) {
  157. $eContentType = 'text/xml';
  158. $ePrefix = $phpError ? $pageHeader['php'] : $pageHeader['default'];
  159. if ($externalOutput || $isCLI) {
  160. $eMessage = $aValue;
  161. }
  162. else {
  163. $eMessage = XML_TAG . NEW_LINE . '<error title="' . $ePrefix . '">' . $aValue . '</error>';
  164. }
  165. }
  166. else {
  167. $isOutput = true;
  168. $eContentType = 'application/json';
  169. $ePrefix = $pageHeader['output'];
  170. $eMessage = json_encode($aValue, JSON_ENCODE_FLAGS);
  171. }
  172. if ($externalOutput) {
  173. if ($phpError) {
  174. gfGenContent($ePrefix, $eMessage, null, true, true);
  175. }
  176. if ($isOutput) {
  177. gfGenContent($ePrefix, $eMessage, true, false, true);
  178. }
  179. gfGenContent($ePrefix, $eMessage);
  180. }
  181. elseif ($isCLI) {
  182. print('========================================' . NEW_LINE .
  183. $ePrefix . NEW_LINE .
  184. '========================================' . NEW_LINE .
  185. $eMessage . NEW_LINE);
  186. }
  187. else {
  188. header('Content-Type: ' . $eContentType, false);
  189. print($eMessage);
  190. }
  191. // We're done here.
  192. exit();
  193. }
  194. /**********************************************************************************************************************
  195. * PHP Error Handler
  196. *
  197. * @dep SPACE
  198. * @dep PHP_ERROR_CODES
  199. * @dep gfError()
  200. **********************************************************************************************************************/
  201. function gfErrorHandler($eCode, $eString, $eFile, $eLine) {
  202. $eType = PHP_ERROR_CODES[$eCode] ?? $eCode;
  203. $eMessage = $eType . ': ' . $eString . SPACE . 'in' . SPACE .
  204. str_replace(ROOT_PATH, '', $eFile) . SPACE . 'on line' . SPACE . $eLine;
  205. if (!(error_reporting() & $eCode)) {
  206. // Don't do jack shit because the developers of PHP think users shouldn't be trusted.
  207. return;
  208. }
  209. gfError($eMessage, true);
  210. }
  211. // Set error handler fairly early...
  212. set_error_handler("gfErrorHandler");
  213. /**********************************************************************************************************************
  214. * Unified Var Checking
  215. *
  216. * @dep DASH_SEPARATOR
  217. * @dep UNDERSCORE
  218. * @dep EMPTY_STRING
  219. * @dep REGEX_GET_FILTER
  220. * @dep gfError()
  221. * @param $aVarType Type of var to check
  222. * @param $aVarValue GET/SERVER/EXISTING Normal Var
  223. * @param $aFalsy Optional - Allow falsey returns on var/direct
  224. * @returns Value or null
  225. **********************************************************************************************************************/
  226. function gfSuperVar($aVarType, $aVarValue, $aFalsy = null) {
  227. // Set up the Error Message Prefix
  228. $ePrefix = __FUNCTION__ . DASH_SEPARATOR;
  229. $rv = null;
  230. // Turn the variable type into all caps prefixed with an underscore
  231. $varType = UNDERSCORE . strtoupper($aVarType);
  232. // General variable absolute null check unless falsy is allowed
  233. if ($varType == "_VAR" || $varType == "_DIRECT"){
  234. $rv = $aVarValue ?? null;
  235. if ($rv && !$aFalsy) {
  236. if (empty($rv) || $rv === 'none' || $rv === EMPTY_STRING) {
  237. return null;
  238. }
  239. }
  240. return $rv;
  241. }
  242. // This handles the superglobals
  243. switch($varType) {
  244. case '_SERVER':
  245. case '_GET':
  246. case '_FILES':
  247. case '_POST':
  248. case '_COOKIE':
  249. case '_SESSION':
  250. $rv = $GLOBALS[$varType][$aVarValue] ?? null;
  251. break;
  252. default:
  253. // We don't know WHAT was requested but it is obviously wrong...
  254. gfError($ePrefix . 'Incorrect Var Check');
  255. }
  256. // We always pass $_GET values through a general regular expression
  257. // This allows only a-z A-Z 0-9 - / { } @ % whitespace and ,
  258. if ($rv && $varType == "_GET") {
  259. $rv = preg_replace(REGEX_GET_FILTER, EMPTY_STRING, $rv);
  260. }
  261. // Files need special handling.. In principle we hard fail if it is anything other than
  262. // OK or NO FILE
  263. if ($rv && $varType == "_FILES") {
  264. if (!in_array($rv['error'], [UPLOAD_ERR_OK, UPLOAD_ERR_NO_FILE])) {
  265. gfError($ePrefix . 'Upload of ' . $aVarValue . ' failed with error code: ' . $rv['error']);
  266. }
  267. // No file is handled as merely being null
  268. if ($rv['error'] == UPLOAD_ERR_NO_FILE) {
  269. return null;
  270. }
  271. // Cursory check the actual mime-type and replace whatever the web client sent
  272. $rv['type'] = mime_content_type($rv['tmp_name']);
  273. }
  274. return $rv;
  275. }
  276. /**********************************************************************************************************************
  277. * Sends HTTP Headers to client using a short name
  278. *
  279. * @dep HTTP_HEADERS
  280. * @dep DEBUG_MODE
  281. * @dep gfError()
  282. * @param $aHeader Short name of header
  283. **********************************************************************************************************************/
  284. function gfHeader($aHeader) {
  285. $ePrefix = __FUNCTION__ . DASH_SEPARATOR;
  286. $debugMode = DEBUG_MODE;
  287. $isErrorPage = in_array($aHeader, [404, 501]);
  288. if (array_key_exists('gaRuntime', $GLOBALS)) {
  289. if (array_key_exists('debugMode', $GLOBALS['gaRuntime'])) {
  290. $debugMode = $GLOBALS['gaRuntime']['debugMode'];
  291. }
  292. }
  293. if (!array_key_exists($aHeader, HTTP_HEADERS)) {
  294. gfError($ePrefix . 'Unknown' . SPACE . $aHeader . SPACE . 'header');
  295. }
  296. if ($debugMode && $isErrorPage) {
  297. gfError($ePrefix . HTTP_HEADERS[$aHeader]);
  298. }
  299. if (!headers_sent()) {
  300. header(HTTP_HEADERS[$aHeader]);
  301. if ($isErrorPage) {
  302. exit();
  303. }
  304. }
  305. }
  306. /**********************************************************************************************************************
  307. * Sends HTTP Header to redirect the client to another URL
  308. *
  309. * @param $_strURL URL to redirect to
  310. **********************************************************************************************************************/
  311. // This function sends a redirect header
  312. function gfRedirect($aURL) {
  313. header('Location: ' . $aURL , true, 302);
  314. // We are done here
  315. exit();
  316. }
  317. /**********************************************************************************************************************
  318. * Explodes a string to an array without empty elements if it starts or ends with the separator
  319. *
  320. * @dep DASH_SEPARATOR
  321. * @dep gfError()
  322. * @param $aSeparator Separator used to split the string
  323. * @param $aString String to be exploded
  324. * @returns Array of string parts
  325. ***********************************************************************************************************************/
  326. function gfExplodeString($aSeparator, $aString) {
  327. $ePrefix = __FUNCTION__ . DASH_SEPARATOR;
  328. if (!is_string($aString)) {
  329. gfError($ePrefix . 'Specified string is not a string type');
  330. }
  331. if (!str_contains($aString, $aSeparator)) {
  332. gfError($ePrefix . 'String does not contain the separator');
  333. }
  334. $explodedString = array_values(array_filter(explode($aSeparator, $aString), 'strlen'));
  335. return $explodedString;
  336. }
  337. /**********************************************************************************************************************
  338. * Splits a path into an indexed array of parts
  339. *
  340. * @dep SLASH
  341. * @dep gfExplodeString()
  342. * @param $aPath URI Path
  343. * @returns array of uri parts in order
  344. ***********************************************************************************************************************/
  345. function gfExplodePath($aPath) {
  346. if ($aPath == SLASH) {
  347. return ['root'];
  348. }
  349. return gfExplodeString(SLASH, $aPath);
  350. }
  351. /**********************************************************************************************************************
  352. * Builds a path from a list of arguments
  353. *
  354. * @dep ROOT_PATH
  355. * @dep SLASH
  356. * @dep DOT
  357. * @param ...$aPathParts Path Parts
  358. * @returns Path string
  359. ***********************************************************************************************************************/
  360. function gfBuildPath(...$aPathParts) {
  361. $path = implode(SLASH, $aPathParts);
  362. $filesystem = str_starts_with($path, ROOT_PATH);
  363. // Add a prepending slash if this is not a filesystem path
  364. if (!$filesystem) {
  365. $path = SLASH . $path;
  366. }
  367. // Add a trailing slash if the last part does not contain a dot
  368. // If it is a filesystem path then we will also add a trailing slash if the last part starts with a dot
  369. if (!str_contains(basename($path), DOT) || ($filesystem && str_starts_with(basename($path), DOT))) {
  370. $path .= SLASH;
  371. }
  372. return $path;
  373. }
  374. /**********************************************************************************************************************
  375. * Strips the constant ROOT_PATH from a string
  376. *
  377. * @dep ROOT_PATH
  378. * @dep EMPTY_STRING
  379. * @param $aPath Path to be stripped
  380. * @returns Stripped path
  381. ***********************************************************************************************************************/
  382. function gfStripRootPath($aPath) {
  383. return str_replace(ROOT_PATH, EMPTY_STRING, $aPath);
  384. }
  385. /**********************************************************************************************************************
  386. * Get a subdomain or base domain from a host
  387. *
  388. * @dep DOT
  389. * @dep gfExplodeString()
  390. * @param $aHost Hostname
  391. * @param $aReturnSub Should return subdmain
  392. * @returns domain or subdomain
  393. ***********************************************************************************************************************/
  394. function gfGetDomain($aHost, $aReturnSub = null) {
  395. $host = gfExplodeString(DOT, $aHost);
  396. $domainSlice = $aReturnSub ? array_slice($host, 0, -2) : array_slice($host, -2, 2);
  397. $domainString = implode(DOT, $domainSlice);
  398. return $domainString;
  399. }
  400. /**********************************************************************************************************************
  401. * Includes a module
  402. *
  403. * @dep MODULES - Phoebus-Style Array Constant
  404. * @dep gfError()
  405. * @param $aModules List of modules
  406. **********************************************************************************************************************/
  407. function gfImportModules(...$aModules) {
  408. if (!defined('MODULES')) {
  409. funcError('MODULES is not defined');
  410. }
  411. foreach ($aModules as $_value) {
  412. if (!array_key_exists($_value, MODULES)) {
  413. gfError('Unable to import unknown module ' . $_value);
  414. }
  415. $className = 'class' . ucfirst($_value);
  416. $moduleName = 'gm' . ucfirst($_value);
  417. if (array_key_exists($moduleName, $GLOBALS)) {
  418. gfError('Module ' . $_value . ' has already been imported');
  419. }
  420. // Special case for nsIVersionComparator because it is static
  421. if ($_value == 'vc') {
  422. $GLOBALS['gmVC'] = true;
  423. require(MODULES['vc']);
  424. continue;
  425. }
  426. require(MODULES[$_value]);
  427. $GLOBALS[$moduleName] = new $className();
  428. }
  429. }
  430. /**********************************************************************************************************************
  431. * Check if a module has been included
  432. *
  433. * @dep EMPTY_ARRAY
  434. * @dep gfError()
  435. * @param $aClass Class name
  436. * @param $aIncludes List of includes
  437. **********************************************************************************************************************/
  438. function gfEnsureModules($aClass, ...$aIncludes) {
  439. if (!$aClass) {
  440. $aClass = "Global";
  441. }
  442. if (empty($aIncludes)) {
  443. gfError('You did not specify any modules');
  444. }
  445. $unloadedModules = EMPTY_ARRAY;
  446. $indicative = ' is ';
  447. foreach ($aIncludes as $_value) {
  448. $moduleName = 'gm' . ucfirst($_value);
  449. if ($_value == 'vc') {
  450. $moduleName = 'gm' . strtoupper($_value);
  451. }
  452. if (!array_key_exists($moduleName, $GLOBALS)) {
  453. $unloadedModules[] = $_value;
  454. }
  455. }
  456. if (count($unloadedModules) > 0) {
  457. if (count($unloadedModules) > 1) {
  458. $indicative = ' are ';
  459. }
  460. gfError(implode(', ', $unloadedModules) . $indicative . 'required for ' . $aClass);
  461. }
  462. }
  463. /**********************************************************************************************************************
  464. * Read file (decode json if the file has that extension or parse install.rdf if that is the target file)
  465. *
  466. * @dep JSON_EXTENSION
  467. * @dep gfError()
  468. * @dep gfSuperVar()
  469. * @dep $gmMozillaRDF - Conditional
  470. * @param $aFile File to read
  471. * @returns file contents or array if json
  472. null if error, empty string, or empty array
  473. **********************************************************************************************************************/
  474. function gfReadFile($aFile) {
  475. $file = @file_get_contents($aFile);
  476. // Automagically decode json
  477. if (str_ends_with($aFile, JSON_EXTENSION)) {
  478. $file = json_decode($file, true);
  479. }
  480. // If it is a mozilla install manifest and the module has been included then parse it
  481. if (str_ends_with($aFile, RDF_INSTALL_MANIFEST) && array_key_exists('gmMozillaRDF', $GLOBALS)) {
  482. global $gmMozillaRDF;
  483. $file = $gmMozillaRDF->parseInstallManifest($file);
  484. if (is_string($file)) {
  485. gfError('RDF Parsing Error: ' . $file);
  486. }
  487. }
  488. return gfSuperVar('var', $file);
  489. }
  490. /**********************************************************************************************************************
  491. * Read file from zip-type archive
  492. *
  493. * @dep gfReadFile()
  494. * @param $aArchive Archive to read
  495. * @param $aFile File in archive
  496. * @returns file contents or array if json
  497. null if error, empty string, or empty array
  498. **********************************************************************************************************************/
  499. function gfReadFileFromArchive($aArchive, $aFile) {
  500. return gfReadFile('zip://' . $aArchive . "#" . $aFile);
  501. }
  502. /**********************************************************************************************************************
  503. * Write file (encodes json if the file has that extension)
  504. *
  505. * @dep JSON_EXTENSION
  506. * @dep JSON_ENCODE_FLAGS
  507. * @dep FILE_WRITE_FLAGS
  508. * @dep gfSuperVar()
  509. * @param $aData Data to be written
  510. * @param $aFile File to write
  511. * @returns true else return error string
  512. **********************************************************************************************************************/
  513. function gfWriteFile($aData, $aFile, $aRenameFile = null) {
  514. if (!gfSuperVar('var', $aData)) {
  515. return 'No useful data to write';
  516. }
  517. if (file_exists($aFile)) {
  518. return 'File already exists';
  519. }
  520. if (str_ends_with($aFile, JSON_EXTENSION)) {
  521. $aData = json_encode($aData, JSON_ENCODE_FLAGS);
  522. }
  523. $file = fopen($aFile, FILE_WRITE_FLAGS);
  524. fwrite($file, $aData);
  525. fclose($file);
  526. if ($aRenameFile) {
  527. rename($aFile, $aRenameFile);
  528. }
  529. return true;
  530. }
  531. /**********************************************************************************************************************
  532. * Generate a random hexadecimal string
  533. *
  534. * @param $aLength Desired number of final chars
  535. * @returns Random hexadecimal string of desired lenth
  536. **********************************************************************************************************************/
  537. function gfHexString($aLength = 40) {
  538. if ($aLength <= 1) {
  539. $length = 1;
  540. }
  541. else {
  542. $length = (int)($aLength / 2);
  543. }
  544. return bin2hex(random_bytes($length));
  545. }
  546. /**********************************************************************************************************************
  547. * Basic Filter Substitution of a string
  548. *
  549. * @dep EMPTY_STRING
  550. * @dep SLASH
  551. * @dep SPACE
  552. * @dep gfError()
  553. * @param $aSubsts multi-dimensional array of keys and values to be replaced
  554. * @param $aString string to operate on
  555. * @param $aRegEx set to true if pcre
  556. * @returns bitwise int value representing applications
  557. ***********************************************************************************************************************/
  558. function gfSubst($aMode, $aSubsts, $aString) {
  559. $ePrefix = __FUNCTION__ . DASH_SEPARATOR;
  560. if (!is_array($aSubsts)) {
  561. gfError($ePrefix . '$aSubsts must be an array');
  562. }
  563. if (!is_string($aString)) {
  564. gfError($ePrefix . '$aString must be a string');
  565. }
  566. $rv = $aString;
  567. switch ($aMode) {
  568. case 'simple':
  569. foreach ($aSubsts as $_key => $_value) { $rv = str_replace($_key, $_value, $rv); }
  570. break;
  571. case 'regex':
  572. foreach ($aSubsts as $_key => $_value) { $rv = preg_replace(SLASH . $_key . SLASH . 'iU', $_value, $rv); }
  573. break;
  574. default:
  575. gfError($ePrefix . 'Unknown mode');
  576. }
  577. if (!$rv) {
  578. gfError($ePrefix . 'Something has gone wrong...');
  579. }
  580. return $rv;
  581. }
  582. /**********************************************************************************************************************
  583. * Hack to turn an object into an array
  584. *
  585. * @param $aObject Object to be transformed
  586. * @returns Array
  587. **********************************************************************************************************************/
  588. function gfObjectToArray($aObject) {
  589. $rv = json_encode($aObject, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
  590. $rv = json_decode($rv, true);
  591. return $rv;
  592. }
  593. /**********************************************************************************************************************
  594. * Request HTTP Basic Authentication
  595. *
  596. * @dep SOFTWARE_NAME
  597. * @dep gfError()
  598. ***********************************************************************************************************************/
  599. function gfBasicAuthPrompt() {
  600. header('WWW-Authenticate: Basic realm="' . SOFTWARE_NAME . '"');
  601. header('HTTP/1.0 401 Unauthorized');
  602. gfError('You need to enter a valid username and password.');
  603. }
  604. // ====================================================================================================================
  605. ?>