1: <?php
2: /**
3: * This file is part of the PHPLucidFrame library.
4: * Core utility for general purpose functions.
5: *
6: * @package PHPLucidFrame\Core
7: * @since PHPLucidFrame v 1.0.0
8: * @copyright Copyright (c), PHPLucidFrame.
9: * @link http://phplucidframe.com
10: * @license http://www.opensource.org/licenses/mit-license.php MIT License
11: *
12: * This source file is subject to the MIT license that is bundled
13: * with this source code in the file LICENSE
14: */
15:
16: use LucidFrame\Console\Command;
17: use LucidFrame\Console\Console;
18: use LucidFrame\Console\ConsoleTable;
19: use LucidFrame\Core\Middleware;
20: use LucidFrame\Core\Pager;
21: use LucidFrame\File\AsynFileUploader;
22: use LucidFrame\File\File;
23: use LucidFrame\Core\SchemaManager;
24: use LucidFrame\Core\App;
25:
26: /**
27: * Set/Get a global variable/object
28: * @param string $name The name of the variable/object
29: * @param mixed $value The value or the variable or object
30: * @return mixed The value stored globally
31: */
32: function _app($name, $value = null)
33: {
34: if (count(func_get_args()) == 2) {
35: return App::$$name = $value;
36: } else {
37: return App::$$name;
38: }
39: }
40:
41: /**
42: * Returns the current PHPLucidFrame version
43: * @return string
44: */
45: function _version()
46: {
47: $findIn = array(LIB, ROOT);
48: foreach ($findIn as $dir) {
49: $versionFile = $dir . 'VERSION';
50: if (is_file($versionFile) && file_exists($versionFile)) {
51: return trim(file_get_contents($versionFile));
52: }
53: }
54:
55: return 'Unknown';
56: }
57:
58: /**
59: * @internal
60: * @ignore
61: *
62: * ob_start callback function to output buffer
63: * It also adds the following to <html>
64: *
65: * - a class for IE "ie ieX"
66: * - lang="xx" for multi-lingual site
67: * - itemscope and itemtype attribute
68: *
69: * Hook to implement `__flush()` at app/helpers/utility_helper.php
70: *
71: * @param string $buffer Contents of the output buffer.
72: * @param int $phase Bitmask of PHP_OUTPUT_HANDLER_* constants.
73: *
74: * PHP_OUTPUT_HANDLER_CLEANABLE
75: * PHP_OUTPUT_HANDLER_FLUSHABLE
76: * PHP_OUTPUT_HANDLER_REMOVABLE
77: *
78: * @return string
79: * @see php.net/ob_start
80: */
81: function _flush($buffer, $phase)
82: {
83: if (function_exists('__flush')) {
84: $buffer = __flush($buffer, $phase); # Run the hook if any
85: } else {
86: $posHtml = stripos($buffer, '<html');
87: $posHead = stripos($buffer, '<head');
88:
89: $beforeHtmlTag = substr($buffer, 0, $posHtml);
90: $afterHtmlTag = substr($buffer, $posHead);
91: $htmlTag = trim(str_ireplace($beforeHtmlTag, '', substr($buffer, 0, $posHead)));
92:
93: if (trim($htmlTag)) {
94: $htmlTag = trim(ltrim($htmlTag, '<html.<HTML'), '>. ');
95: $attributes = array();
96: $attrList = explode(' ', $htmlTag);
97: foreach ($attrList as $list) {
98: $attr = explode('=', $list);
99: $attr[0] = trim($attr[0]);
100: if (count($attr) == 2) {
101: $attr[1] = trim($attr[1], '".\'');
102: }
103: $attributes[$attr[0]] = $attr;
104: }
105:
106: $IE = false;
107: $IEVersion = '';
108: $userAgent = $_SERVER['HTTP_USER_AGENT'];
109: if (strpos($userAgent, 'MSIE') !== false || strpos($userAgent, 'Trident') !== false) {
110: $IE = true;
111: if (preg_match('/(MSIE|rv)\s(\d+)/i', $userAgent, $m)) {
112: $IEVersion = 'ie' . $m[2];
113: }
114: }
115:
116: if (array_key_exists('class', $attributes)) {
117: # if there is class attribute provided
118: if ($IE) {
119: $attributes['class'][1] .= ' ie ' . $IEVersion;
120: }
121: if (_multilingual()) {
122: $attributes['class'][1] .= ' ' . _lang();
123: }
124: } else {
125: # if there is not class attributes provided
126: if ($IE || _multilingual()) {
127: $value = array();
128: if ($IE) {
129: $value[] = 'ie ' . $IEVersion; # ie class
130: }
131: if (_multilingual()) {
132: $value[] = _lang(); # lang class
133: }
134: if (count($value)) {
135: $attributes['class'] = array('class', implode(' ', $value));
136: }
137: }
138: }
139:
140: if (_multilingual()) {
141: # lang attributes
142: if (!array_key_exists('lang', $attributes)) {
143: # if there is no lang attribute provided
144: $attributes['lang'] = array('lang', _lang());
145: }
146: }
147:
148: if (!array_key_exists('itemscope', $attributes)) {
149: $attributes['itemscope'] = array('itemscope');
150: }
151:
152: if (!array_key_exists('itemtype', $attributes)) {
153: # if there is no itemtype attribute provided
154: # default to "WebPage"
155: $attributes['itemtype'] = array('itemtype', "http://schema.org/WebPage");
156: }
157:
158: ksort($attributes);
159: $html = '<html';
160: foreach ($attributes as $key => $value) {
161: $html .= ' '.$key;
162: if (isset($value[1])) {
163: # some attribute may not have value, such as itemscope
164: $html .= '="' . $value[1] . '"';
165: }
166: }
167: $html .= '>' . "\r\n";
168: $buffer = $beforeHtmlTag . $html . $afterHtmlTag;
169: }
170: }
171:
172: # compress the output
173: $buffer = _minifyHTML($buffer);
174:
175: $posDoc = stripos($buffer, '<!DOCTYPE');
176:
177: return substr($buffer, $posDoc);
178: }
179:
180: /**
181: * Minify and compress the given HTML according to the configuration `$lc_minifyHTML`
182: * @param string $html HTML to be compressed or minified
183: * @return string The compressed or minifed HTML
184: */
185: function _minifyHTML($html)
186: {
187: if (_cfg('minifyHTML')) {
188: # 1. strip whitespaces after tags, except space
189: # 2. strip whitespaces before tags, except space
190: # 3. shorten multiple whitespace sequences
191: return preg_replace(array('/\>[^\S ]+/s', '/[^\S ]+\</s', '/(\s)+/s'), array('>', '<', '\\1'), $html);
192: }
193:
194: return $html;
195: }
196:
197: /**
198: * Get a full path directory
199: * @param string $name The short code for directory
200: * @return string Full path directory
201: */
202: function _dir($name)
203: {
204: switch($name) {
205: case 'inc':
206: return ROOT . 'inc' . _DS_;
207: case 'db':
208: return ROOT . 'db' . _DS_;
209: case 'lib':
210: return ROOT . 'lib' . _DS_;
211: case 'helper':
212: return ROOT . 'lib' . _DS_ . 'helpers' . _DS_;
213: case 'class':
214: return ROOT . 'lib' . _DS_ . 'classes' . _DS_;
215: case 'i18n':
216: return ROOT . 'i18n' . _DS_;
217: case 'vendor':
218: return ROOT . 'vendor' . _DS_;
219: case 'business':
220: return ROOT . 'business' . _DS_;
221: case 'asset':
222: return ROOT . 'assets' . _DS_;
223: case 'image':
224: return ROOT . 'assets' . _DS_ . 'images' . _DS_;
225: case 'file':
226: return ROOT . 'files' . _DS_;
227: case 'cache':
228: return ROOT . 'files' . _DS_ . 'cache' . _DS_;
229: case 'test':
230: return ROOT . 'tests' . _DS_;
231: }
232:
233: return ROOT;
234: }
235:
236: /**
237: * Auto-load a library, script or file
238: * @param string $name The file name without extension
239: * @param string $path The directory path for the library, script or file; default to helpers/
240: * @return void
241: */
242: function _loader($name, $path = HELPER)
243: {
244: global $lc_autoload;
245:
246: $path = rtrim($path, _DS_) . _DS_;
247:
248: $dir = $path . $name . _DS_;
249: if (is_dir($dir)) {
250: // include all files from the library
251: $files = scandir($dir);
252: foreach ($files as $fileName) {
253: $dir = rtrim(rtrim($dir, '/'), '\\');
254: $file = $dir . _DS_ . $fileName;
255:
256: if (!in_array(substr($fileName, -3), array('php', 'inc')) || !is_file($file)) {
257: continue;
258: }
259:
260: if (file_exists($file)) {
261: $lc_autoload[] = $file;
262: }
263: }
264: } else {
265: // include one file from the library
266: $name = rtrim($name, '.php');
267: $lc_autoload[] = $path . $name . '.php';
268: }
269:
270: $lc_autoload = array_unique($lc_autoload);
271: }
272:
273: /**
274: * Removing a library, script or file from auto-load
275: * @param string $name The file name without extension
276: * @param string $path The directory path for the library, script or file; default to helpers/
277: * @return void
278: */
279: function _unloader($name, $path = HELPER)
280: {
281: global $lc_autoload;
282:
283: $file = $path . $name . '.php';
284: $key = array_search($file, $lc_autoload);
285: if ($key !== false) {
286: unset($lc_autoload[$key]);
287: $lc_autoload = array_values($lc_autoload);
288: }
289: }
290:
291: /**
292: * @internal
293: * @ignore
294: *
295: * Check a library, script or file is ready to load
296: * @param string $name The file name without extension
297: * @param string $path The directory path for the library, script or file; default to helpers/
298: * @return mixed The file name if it is ready to load, otherwise FALSE
299: */
300: function _readyloader($name, $path = HELPER)
301: {
302: global $lc_autoload;
303:
304: if (stripos($name, '.php') === false) {
305: $file = $path . $name . '.php';
306: } else {
307: $file = $name;
308: }
309:
310: return (array_search($file, $lc_autoload) !== false && is_file($file) && file_exists($file)) ? $file : false;
311: }
312:
313: /**
314: * Autoload classes from directory
315: * @param string $dir Directory path from which all files to be included
316: * @param string $scope The sub-site scope/namespace (if it is given, the directory will only be loaded under that scope)
317: * @return void
318: */
319: function _autoloadDir($dir, $scope = '')
320: {
321: $scope = trim($scope, '/');
322:
323: if (is_dir($dir)) {
324: $files = scandir($dir);
325: foreach ($files as $fileName) {
326: $dir = rtrim(rtrim($dir, '/'), '\\');
327: $file = $dir . _DS_ . $fileName;
328:
329: if (!in_array(substr($fileName, -3), array('php', 'inc')) || !is_file($file)) {
330: continue;
331: }
332:
333: if (file_exists($file) && (empty($scope) || $scope == LC_NAMESPACE)) {
334: require_once $file;
335: }
336: }
337: }
338: }
339:
340: /**
341: * Declare global JS variables
342: * Hook to implement `__script()` at app/helpers/utility_helper.php
343: *
344: * @return void
345: */
346: function _script()
347: {
348: $sitewideWarnings = _cfg('sitewideWarnings');
349: $sites = _cfg('sites');
350: $script = '<script type="text/javascript">';
351: $script .= 'var LC = {};';
352: if (WEB_ROOT) {
353: $script .= 'var WEB_ROOT = "'.WEB_ROOT.'";';
354: $script .= 'LC.root = WEB_ROOT;';
355: }
356: if (WEB_APP_ROOT) {
357: $script .= 'var WEB_APP_ROOT = "'.WEB_APP_ROOT.'";';
358: $script .= 'LC.appRoot = WEB_ROOT;';
359: }
360: $script .= 'LC.self = "'._self().'";';
361: $script .= 'LC.lang = "'._lang().'";';
362: $script .= 'LC.baseURL = "'._cfg('baseURL').'/";';
363: $script .= 'LC.route = "'._r().'";';
364: $script .= 'LC.cleanRoute = "'._cfg('cleanRoute').'";';
365: $script .= 'LC.namespace = "'.LC_NAMESPACE.'";';
366: $script .= 'LC.sites = '.(is_array($sites) && count($sites) ? json_encode($sites) : 'false').';';
367: $script .= 'LC.sitewideWarnings = '.json_encode($sitewideWarnings).';';
368: # run hook
369: if (function_exists('__script')) {
370: __script();
371: }
372:
373: # user defined variables
374: $jsVars = _cfg('jsVars');
375: $script .= 'LC.vars = {};';
376: $script .= 'LC.vars.baseDir = "' . _cfg('baseDir') . '";';
377: if (count($jsVars)) {
378: foreach ($jsVars as $name => $val) {
379: if (is_object($val)) {
380: $val = (array) $val;
381: }
382:
383: if (is_array($val)) {
384: $script .= 'LC.vars.'.$name.' = '.json_encode($val).';';
385: } elseif (is_numeric($val)) {
386: $script .= 'LC.vars.'.$name.' = '.$val.';';
387: } else {
388: $script .= 'LC.vars.'.$name.' = "'.$val.'";';
389: }
390: }
391: }
392: $script .= '</script>';
393: echo $script;
394: }
395:
396: /**
397: * Passing values from PHP to Javascript making available to `LC.vars`
398: * @param string $name The JS variable name
399: * @param mixed $value The value for the JS variable
400: */
401: function _addJsVar($name, $value = '')
402: {
403: global $lc_jsVars;
404: $lc_jsVars[$name] = $value;
405: }
406:
407: /**
408: * JS file include helper
409: *
410: * @param string $file An absolute file path or just file name.
411: * The file name only will be prepended the folder name js/ and it will be looked in every sub-sites "js" folder
412: * @param string $subDir The sub-directory under assets directory, where the file exists
413: * @param bool $return [optional] If you would like to capture the output of _js, use the return parameter.
414: * If this parameter is set to true, _js will return its output, instead of printing it (which it does by default).
415: * @return boolean Return true if the file found and included, otherwise false
416: */
417: function _js($file, $subDir = '', $return = false)
418: {
419: $version = '?v' . _cfg('assetVersion');
420:
421: if (stripos($file, 'http') === 0 || stripos($file, '//') === 0) {
422: $html = '<script src="' . $file . '" type="text/javascript"></script>';
423: if ($return) {
424: return $html;
425: }
426:
427: echo $html;
428: return true;
429: }
430:
431: if ($subDir) {
432: $subDir = trim('assets/' . $subDir, '/') . '/';
433: } else {
434: $subDir = 'assets/js/';
435: }
436:
437: $includeFiles = array();
438: if ($file == 'jquery.ui' || $file == 'jquery-ui') {
439: # jQuery UI
440: $file = (stripos($file, '.js') !== false) ? $file : 'jquery-ui.min.js';
441: $includeFiles[] = $subDir . 'vendor/jquery-ui/' . $file;
442: } elseif ($file == 'jquery') {
443: # jQuery
444: $file = (stripos($file, '.js') !== false) ? $file : 'jquery.min.js';
445: $includeFiles[] = $subDir . 'vendor/jquery/' . $file;
446: } else {
447: # Other files
448: $includeFiles[] = $subDir . $file;
449: }
450:
451: foreach ($includeFiles as $includeFile) {
452: $includeFile = _i($includeFile);
453: if (stripos($includeFile, 'http') === 0) {
454: if (stripos($includeFile, WEB_APP_ROOT) === 0) {
455: $fileWithSystemPath = APP_ROOT . str_replace(WEB_APP_ROOT, '', $includeFile);
456: } else {
457: $fileWithSystemPath = ROOT . str_replace(WEB_ROOT, '', $includeFile);
458: }
459: if (file_exists($fileWithSystemPath)) {
460: $html = '<script src="' . $includeFile . $version . '" type="text/javascript"></script>';
461: if ($return) {
462: return $html;
463: }
464:
465: echo $html;
466: return true;
467: }
468: }
469: }
470:
471: return false;
472: }
473:
474: /**
475: * CSS file include helper
476: *
477: * @param string $file An absolute file path or file name only.
478: * The file name only will be prepended the folder name css/ and it will be looked in every sub-sites "css" folder
479: * @param string $subDir The sub-directory under assets directory, where the file exists
480: * @param bool $return [optional] If you would like to capture the output of _js, use the return parameter.
481: * If this parameter is set to true, _js will return its output, instead of printing it (which it does by default).
482: * @return boolean Return true if the file found and included, otherwise false
483: */
484: function _css($file, $subDir = '', $return = false)
485: {
486: $version = '?v' . _cfg('assetVersion');
487:
488: if (stripos($file, 'http') === 0 || stripos($file, '//') === 0) {
489: $html = '<link href="' . $file . '" rel="stylesheet" type="text/css" />';
490: if ($return) {
491: return $html;
492: }
493:
494: echo $html;
495: return true;
496: }
497:
498: if ($subDir) {
499: $subDir = trim('assets/' . $subDir, '/') . '/';
500: } else {
501: $subDir = 'assets/css/';
502: }
503:
504: $includeFiles = array();
505: if ($file == 'jquery.ui' || $file == 'jquery-ui') {
506: # jQuery UI
507: $includeFiles[] = 'assets/js/vendor/jquery-ui/jquery-ui.min.css';
508: } else {
509: # Other files
510: $includeFiles[] = $subDir . $file;
511: }
512:
513: foreach ($includeFiles as $includeFile) {
514: $includeFile = _i($includeFile);
515: if (stripos($includeFile, 'http') === 0) {
516: if (stripos($includeFile, WEB_APP_ROOT) === 0) {
517: $fileWithSystemPath = APP_ROOT . str_replace(WEB_APP_ROOT, '', $includeFile);
518: } else {
519: $fileWithSystemPath = ROOT . str_replace(WEB_ROOT, '', $includeFile);
520: }
521:
522: if (file_exists($fileWithSystemPath)) {
523: $html = '<link href="' . $includeFile . $version . '" rel="stylesheet" type="text/css" />';
524: if ($return) {
525: return $html;
526: }
527:
528: echo $html;
529: return true;
530: }
531: }
532: }
533:
534: return false;
535: }
536:
537: /**
538: * Get the image file name with absolute web path
539: *
540: * @param string $file An image file name only (no need directory path)
541: * @return string The absolute image URL if the file found or empty string if it is not found
542: */
543: function _img($file)
544: {
545: $fileWithPath = 'assets/images/' . $file;
546: $fileWithPath = _i($fileWithPath);
547:
548: if (empty($fileWithPath)) {
549: return '';
550: }
551:
552: if (stripos($fileWithPath, APP_ROOT) === 0) {
553: return WEB_APP_ROOT . str_replace(APP_ROOT, '', $fileWithPath);
554: } else {
555: return WEB_ROOT . str_replace(ROOT, '', $fileWithPath);
556: }
557: }
558:
559: if (!function_exists('_image')) {
560: /**
561: * Display an image fitting into the desired dimension
562: * It expects the file existing in one of the directories `./files` (the constant `FILE`)
563: * and `./images` (the constant `IMAGE`)
564: * This function has dependency on file_helper. If there is no file_helper found,
565: * the arguments `$dimension` and `$attributes` will be ignored.
566: *
567: * @param string $file The image file name with path excluding
568: * the base directory name (FILE or IMAGE) without leading slash.
569: * @param string $caption The image caption
570: * @param string $dimension The desired dimension in "widthxheight"
571: * @param array $attributes The HTML attributes in array like key => value
572: *
573: * @return void
574: */
575: function _image($file, $caption = '', $dimension = '0x0', array $attributes = array())
576: {
577: $directory = array(
578: 'images' => IMAGE,
579: 'files' => FILE,
580: );
581: # find the image in the two directories - ./files and ./images
582: foreach ($directory as $dir => $path) {
583: $image = $path . $file;
584: if (is_file($image) && file_exists($image)) {
585: list($width, $height) = getimagesize($image);
586: if (strpos($path, 'assets') !== false) {
587: $dir = 'assets/images';
588: }
589: break;
590: }
591: }
592: if (isset($width) && isset($height)) {
593: # if the image is found
594: $image = WEB_ROOT . $dir . '/' . $file;
595: echo File::img($image, $caption, $width.'x'.$height, $dimension, $attributes);
596: } else {
597: # if the image is not found
598: echo '<div class="image404" align="center">';
599: echo function_exists('_t') ? _t('No Image') : 'No Image';
600: echo '</div>';
601: }
602: }
603: }
604:
605: if (!function_exists('_pr')) {
606: /**
607: * Convenience method for `print_r`.
608: * Displays information about a variable in a way that's readable by humans.
609: * If given a string, integer or float, the value itself will be printed.
610: * If given an array, values will be presented in a format that shows keys and elements.
611: *
612: * @param mixed $input The variable to debug
613: * @param boolean $pre TRUE to print using `<pre>`, otherwise FALSE
614: *
615: * @return void
616: */
617: function _pr($input, $pre = true)
618: {
619: if ($pre) {
620: echo '<pre>';
621: }
622: if (is_array($input) || is_object($input)) {
623: print_r($input);
624: } else {
625: if (is_bool($input)) {
626: var_dump($input);
627: } else {
628: echo $input;
629: }
630: if ($pre == false) {
631: echo '<br>';
632: }
633: }
634: if ($pre) {
635: echo '</pre>';
636: }
637: }
638: }
639:
640: if (!function_exists('_dpr')) {
641: /**
642: * Convenience method for `print_r` + `die`.
643: * Displays information about a variable in a way that's readable by humans.
644: * If given a string, integer or float, the value itself will be printed.
645: * If given an array, values will be presented in a format that shows keys and elements.
646: *
647: * @param mixed $input The variable to debug
648: * @param boolean $pre TRUE to print using `<pre>`, otherwise FALSE
649: *
650: * @return void
651: */
652: function _dpr($input, $pre = true)
653: {
654: _pr($input);
655: exit;
656: }
657: }
658:
659: if (!function_exists('_dump')) {
660: /**
661: * Convenience method for `var_dump`.
662: * Dumps information about a variable
663: *
664: * @param mixed $input mixed The variable to debug
665: * @param boolean $pre boolean TRUE to print using `<pre>`, otherwise FALSE
666: *
667: * @return void
668: */
669: function _dump($input, $pre = true)
670: {
671: if ($pre) {
672: echo '<pre>';
673: }
674: var_dump($input);
675: if ($pre) {
676: echo '</pre>';
677: }
678: }
679: }
680:
681: /**
682: * Convenience method to get/set a global variable
683: *
684: * @param string $key The global variable name
685: * @param mixed $value The value to set to the global variable; if it is not given, it is Getter method.
686: * @return mixed The value of the global variable
687: */
688: function _g($key, $value = '')
689: {
690: if (empty($key)) {
691: return null;
692: }
693:
694: if (count(func_get_args()) == 2) {
695: return __dotNotationToArray($key, 'global', $value);
696: } else {
697: return __dotNotationToArray($key);
698: }
699: }
700:
701: /**
702: * Convenience method for htmlspecialchars.
703: *
704: * @param string $string The string being converted
705: * @return string The converted string
706: */
707: function _h($string)
708: {
709: if (empty($string)) {
710: return $string;
711: }
712:
713: $string = stripslashes($string);
714: $string = htmlspecialchars_decode($string, ENT_QUOTES);
715:
716: return htmlspecialchars($string, ENT_QUOTES); # ENT_QUOTES will convert both double and single quotes.
717: }
718:
719: /**
720: * Get the current site language code
721: * @return string The language code
722: */
723: function _lang()
724: {
725: return _cfg('lang');
726: }
727:
728: /**
729: * Get the language to process
730: * Read "lang" from query string; if it is not found, get the default language code
731: * Basically, it is useful for admin content management by language
732: * Hook to implement `__getLang()` at app/helpers/utility_helper.php
733: *
734: * @return string The language code
735: */
736: function _getLang()
737: {
738: if (function_exists('__getLang')) {
739: return __getLang(); # run the hook if any
740: }
741:
742: $lang = (_arg('lang')) ? _arg('lang') : _defaultLang();
743:
744: return ($lang) ? $lang : _defaultLang();
745: }
746:
747: /**
748: * Get the default site language code
749: * @return string The default site language code
750: */
751: function _defaultLang()
752: {
753: return _cfg('defaultLang');
754: }
755:
756: /**
757: * Get array of the defined languages
758: * @param string|array $excepts The exceptional langauges to exclude
759: * @return array|boolean The filtered language array or FALSE for no multi-language
760: */
761: function _langs($excepts = null)
762: {
763: global $lc_languages;
764:
765: $langs = array();
766: if ($excepts) {
767: foreach ($lc_languages as $lcode => $lname) {
768: if (is_array($excepts) && in_array($lcode, $excepts)) {
769: continue;
770: }
771: if (is_string($excepts) && $lcode == $excepts) {
772: continue;
773: }
774: $langs[$lcode] = $lname;
775: }
776: } else {
777: $langs = $lc_languages;
778: }
779:
780: return count($langs) ? $langs : false;
781: }
782:
783: /**
784: * Get the current site language code by converting dash (URL-friendly) to underscore (db-friendly)
785: * @param string $lang The language code (optional - if not provided, the current language code will be used)
786: * @return string The language code
787: */
788: function _queryLang($lang = null)
789: {
790: if (!$lang) {
791: $lang = _cfg('lang');;
792: }
793:
794: return str_replace('-', '_', $lang);
795: }
796:
797: /**
798: * Get the current site language code by converting underscore (db-friendly) to dash (URL-friendly)
799: * @param string $lang The language code (optional - if not provided, the current language code will be used)
800: * @return string The language code
801: */
802: function _urlLang($lang = null)
803: {
804: if (!$lang) {
805: $lang = _cfg('lang');
806: }
807:
808: return str_replace('_', '-', $lang);
809: }
810:
811: /**
812: * Get the default site language code by converting dash to underscore
813: * @return string The language code
814: */
815: function _defaultQueryLang()
816: {
817: return str_replace('-', '_', _cfg('defaultLang'));
818: }
819:
820: /**
821: * Get the current site language name of the given language code
822: * If the site is multilingual, return empty
823: * If no given code, return the language name of the default language code
824: *
825: * @param string $lang The language code (optional - if not provided,
826: * the default language code from $lc_defaultLang will be used)
827: * @return string The language name as per defined in /inc/config.php
828: */
829: function _langName($lang = '')
830: {
831: if (!_multilingual()) {
832: return '';
833: }
834:
835: global $lc_languages;
836: $lang = str_replace('_', '-', $lang);
837:
838: if (isset($lc_languages[$lang])) {
839: return $lc_languages[$lang];
840: } else {
841: return $lc_languages[_cfg('defaultLang')];
842: }
843: }
844:
845: /**
846: * Get the current site is multi-lingual or not
847: * @return boolean
848: */
849: function _multilingual()
850: {
851: if (_cfg('languages')) {
852: return (count(_cfg('languages')) > 1) ? true : false;
853: } else {
854: return false;
855: }
856: }
857:
858: /**
859: * Get the server protocol
860: * For example, http, https, ftp, etc.
861: *
862: * @return string The protocol - http, https, ftp, etc.
863: */
864: function _protocol()
865: {
866: $protocol = current(explode('/', $_SERVER['SERVER_PROTOCOL']));
867:
868: return strtolower($protocol);
869: }
870:
871: /**
872: * Check SSL or not
873: *
874: * @return boolean TRUE if https otherwise FALSE
875: */
876: function _ssl()
877: {
878: return _cfg('ssl');
879: }
880:
881: /**
882: * Get the current routing path
883: * For example,
884: *
885: * - example.com/foo/bar would return foo/bar
886: * - example.com/en/foo/bar would also return foo/bar
887: * - example.com/1/this-is-slug (if accomplished by RewriteRule) would return the underlying physical path
888: *
889: * @return string The route path starting from the site root
890: */
891: function _r()
892: {
893: return route_path();
894: }
895:
896: /**
897: * The more realistic function to get the current routing path on the address bar regardless of RewriteRule behind
898: * For example,
899: *
900: * - example.com/foo/bar would return foo/bar
901: * - example.com/en/foo/bar would also return foo/bar
902: * - example.com/foo/bar?id=1 would also return foo/bar
903: * - example.com/1/this-is-slug would return 1/this-is-slug
904: *
905: * @return string The route path starting from the site root
906: */
907: function _rr()
908: {
909: if (!_isRewriteRule()) {
910: return _r();
911: }
912:
913: $uri = REQUEST_URI;
914: if (strpos($uri, '?') !== false) { // exclude query string
915: $uri = substr($uri, 0, strpos($uri, '?'));
916: }
917:
918: return $uri;
919: }
920:
921: /**
922: * Get the clean routing path without the query string
923: * For example, `example.com/post/1/edit` would return `post`
924: * @return string The route path starting from the site root
925: */
926: function _cr()
927: {
928: return _cfg('cleanRoute');
929: }
930:
931: /**
932: * Get the absolute URL path
933: * @param string $path Routing path such as "foo/bar"; null for the current path
934: * @param array $queryStr Query string as
935: *
936: * array(
937: * $value1, // no key here
938: * 'key1' => $value2,
939: * 'key3' => $value3 or array($value3, $value4)
940: * )
941: *
942: * @param string $lang Language code to be prepended to $path such as "en/foo/bar".
943: * It will be useful for site language switch redirect
944: * @return string
945: */
946: function _url($path = null, $queryStr = array(), $lang = '')
947: {
948: return route_url($path, $queryStr, $lang);
949: }
950:
951: /**
952: * Get the absolute URL path
953: * @param array $queryStr Query string as
954: *
955: * array(
956: * $value1, // no key here
957: * 'key1' => $value2,
958: * 'key3' => $value3 or array($value3, $value4)
959: * )
960: *
961: * @param string $lang Languague code to be prepended to $path such as "en/foo/bar".
962: * It will be useful for site language switch redirect
963: * @return string
964: */
965: function _self($queryStr = array(), $lang = '')
966: {
967: return route_url(null, $queryStr, $lang);
968: }
969:
970: /**
971: * Send HTTP header
972: * @param int $status The HTTP status code
973: * @param string $message Message along with status code
974: * @return void
975: */
976: function _header($status, $message = null)
977: {
978: _g('httpStatusCode', $status);
979:
980: if (PHP_SAPI != 'cli' && _cfg('env') != ENV_TEST && __env() != ENV_TEST) {
981: header('HTTP/1.1 ' . $status . ($message ? ' ' . $message : ''));
982: }
983: }
984:
985: /**
986: * Header redirect to a specific location
987: * @param string $path Routing path such as "foo/bar"; null for the current path
988: * @param array $queryStr Query string as
989: *
990: * array(
991: * $value1, // no key here
992: * 'key1' => $value2,
993: * 'key3' => $value3 or array($value3, $value4)
994: * )
995: *
996: * @param string $lang The Language code to be prepended to $path such as "en/foo/bar".
997: * It will be useful for site language switch redirect
998: * @param int $status The HTTP status code
999: * use `_redirect301()` instead; do not provide this for default 302 redirect.
1000: * @return void
1001: */
1002: function _redirect($path = null, $queryStr = array(), $lang = '', $status = null)
1003: {
1004: if (stripos($path, 'http') === 0) {
1005: if ($status === 301) {
1006: _header(301, 'Moved Permanently');
1007: }
1008: header('Location: ' . $path);
1009: exit;
1010: }
1011:
1012: if ($path == 'self') {
1013: $url = _self(null, $lang);
1014: } else {
1015: $url = route_url($path, $queryStr, $lang);
1016: }
1017:
1018: if ($status === 301) {
1019: _header(301, 'Moved Permanently');
1020: }
1021:
1022: header('Location: ' . $url);
1023: exit;
1024: }
1025:
1026: /**
1027: * Header redirect to a specific location by sending 301 status code
1028: * @param string $path Routing path such as "foo/bar"; null for the current path
1029: * @param array $queryStr Query string as
1030: *
1031: * array(
1032: * $value1, // no key here
1033: * 'key1' => $value2,
1034: * 'key3' => $value3 or array($value3, $value4)
1035: * )
1036: *
1037: * @param string $lang Languague code to be prepended to $path such as "en/foo/bar".
1038: * It will be useful for site language switch redirect
1039: * @return void
1040: */
1041: function _redirect301($path = null, $queryStr = array(), $lang = '')
1042: {
1043: _redirect($path, $queryStr, $lang, 301);
1044: }
1045:
1046: /**
1047: * Display 401 page
1048: * @param string $message The error message
1049: * @return void
1050: */
1051: function _page401($message = '')
1052: {
1053: $message = $message ?: _t('Access Denied');
1054:
1055: if (_isContentType('application/json')) {
1056: _jsonError($message, '', 401);
1057: }
1058:
1059: _cfg('layoutMode', true);
1060: include(INC . 'tpl/401.php');
1061: exit;
1062: }
1063:
1064: /**
1065: * Display 403 page
1066: * @param string $message The error message
1067: * @return void
1068: */
1069: function _page403($message = '')
1070: {
1071: $message = $message ?: _t('403 Forbidden');
1072:
1073: if (_isContentType('application/json')) {
1074: _jsonError($message, '', 403);
1075: }
1076:
1077: _cfg('layoutMode', true);
1078: include(INC . 'tpl/403.php');
1079: exit;
1080: }
1081:
1082: /**
1083: * Display 404 page
1084: * @param string $message The error message
1085: * @param string $entity The entity name
1086: * @return void
1087: */
1088: function _page404($message = '', $entity = '')
1089: {
1090: $message = $message ?: _t('404 Not Found');
1091:
1092: if (_isContentType('application/json')) {
1093: _jsonError($message, $entity, 404);
1094: }
1095:
1096: _cfg('layoutMode', true);
1097: include(INC . 'tpl/404.php');
1098: exit;
1099: }
1100:
1101: /**
1102: * Display error page
1103: * @param string $message The error message
1104: * @param int $code The error code
1105: * @param int $status HTTP status code
1106: * @return void
1107: */
1108: function _error($message, $code, $status = 500)
1109: {
1110: if (_isContentType('application/json')) {
1111: _json(['error' => $message], $status);
1112: }
1113:
1114: _cfg('layoutMode', true);
1115: _g('httpStatusCode', $status);
1116: $type = __kernelErrorTypes($code);
1117:
1118: _header($status);
1119:
1120: include(INC . 'tpl/exception.php');
1121: exit;
1122: }
1123:
1124: /**
1125: * Check if the current routing is a particular URL RewriteRule processing or not
1126: * @return boolean
1127: */
1128: function _isRewriteRule()
1129: {
1130: return (strcasecmp(REQUEST_URI, _r()) !== 0) ? true : false;
1131: }
1132:
1133: /**
1134: * Setter for canonical URL if the argument is given and print the canonical link tag if the argument is not given
1135: * @param string $url The specific URL
1136: * @return void|string
1137: */
1138: function _canonical($url = null)
1139: {
1140: global $lc_canonical;
1141: if (!is_null($url)) {
1142: $lc_canonical = $url;
1143: } else {
1144: return (_cfg('canonical')) ? _cfg('canonical') : _url();
1145: }
1146: }
1147:
1148: /**
1149: * Print hreflang for language and regional URLs
1150: * @return void
1151: */
1152: function _hreflang()
1153: {
1154: global $lc_languages;
1155: if (_multilingual()) {
1156: foreach ($lc_languages as $hrefLang => $langDesc) {
1157: if (_canonical() == _url()) {
1158: $alternate = _url('', null, $hrefLang);
1159: $xdefault = _url('', null, false);
1160: } else {
1161: $alternate = preg_replace('/\/'._lang().'\b/', '/'.$hrefLang, _canonical());
1162: $xdefault = preg_replace('/\/'._lang().'\b/', '', _canonical());
1163: }
1164: echo '<link rel="alternate" hreflang="'.$hrefLang.'" href="'.$alternate.'" />'."\n";
1165: }
1166: echo '<link rel="alternate" hreflang="x-default" href="'.$xdefault.'" />'."\n";
1167: }
1168: }
1169:
1170: /**
1171: * Check if the URI has a language code and return it when it matches
1172: * For example,
1173: *
1174: * - /LucidFrame/en/....
1175: * - /LucidFrame/....
1176: * - /en/...
1177: * - /....
1178: *
1179: * @return mixed The language code if it has one, otherwise return FALSE
1180: */
1181: function _getLangInURI()
1182: {
1183: global $lc_languages;
1184:
1185: if (!isset($_SERVER['REQUEST_URI'])) {
1186: return false;
1187: }
1188:
1189: if (!is_array($lc_languages)) {
1190: $lc_languages = array('en' => 'English');
1191: }
1192:
1193: $baseURL = trim(_cfg('baseURL'), '/');
1194: $baseURL = ($baseURL) ? "/$baseURL/" : '/';
1195: $baseURL = str_replace('/', '\/', $baseURL); // escape literal `/`
1196: $baseURL = str_replace('.', '\.', $baseURL); // escape literal `.`
1197: $regex = '/^('.$baseURL.')\b('.implode('|', array_keys($lc_languages)).'){1}\b(\/?)/i';
1198:
1199: if (preg_match($regex, $_SERVER['REQUEST_URI'], $matches)) {
1200: return $matches[2];
1201: }
1202:
1203: return false;
1204: }
1205:
1206: /**
1207: * Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
1208: *
1209: * @param string $host The host name
1210: * @return boolean TRUE if only containing valid characters, or FALSE otherwise.
1211: */
1212: function _validHost($host)
1213: {
1214: return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
1215: }
1216:
1217: /**
1218: * Get the page title glued by a separator
1219: *
1220: * @param mixed $args multiple arguments or array of arguments
1221: * @return string The formatted page title
1222: */
1223: function _title()
1224: {
1225: global $lc_siteName;
1226: global $lc_titleSeparator;
1227:
1228: $args = func_get_args();
1229:
1230: if (count($args) == 0) {
1231: $title = _app('title');
1232: if (is_array($title)) {
1233: $args = $title;
1234: }
1235:
1236: if (is_string($title)) {
1237: $args = array($title);
1238: }
1239: }
1240:
1241: if (count($args) == 0) {
1242: return $lc_siteName;
1243: }
1244:
1245: if (count($args) == 1) {
1246: if (is_array($args[0])) {
1247: $args = _filterArrayEmpty($args[0]);
1248: $title = $args;
1249: } else {
1250: $title = ($args[0]) ? array($args[0]) : array();
1251: }
1252: } else {
1253: $args = _filterArrayEmpty($args);
1254: $title = $args;
1255: }
1256:
1257: $lc_titleSeparator = trim($lc_titleSeparator);
1258: if ($lc_titleSeparator) {
1259: $lc_titleSeparator = ' '.$lc_titleSeparator.' ';
1260: } else {
1261: $lc_titleSeparator = ' ';
1262: }
1263:
1264: if (count($title)) {
1265: $title = implode($lc_titleSeparator, $title);
1266: if ($lc_siteName) {
1267: $title .= ' | '.$lc_siteName;
1268: }
1269: return $title;
1270: }
1271:
1272: return $lc_siteName;
1273: }
1274:
1275: /**
1276: * Filters elements of an array which have empty values
1277: *
1278: * @param array $input The input array
1279: * @return array The filtered array
1280: */
1281: function _filterArrayEmpty($input)
1282: {
1283: return array_filter($input, '_notEmpty');
1284: }
1285:
1286: /**
1287: * Check the given value is not empty
1288: *
1289: * @param string $value The value to be checked
1290: * @return boolean TRUE if not empty; FALSE if empty
1291: */
1292: function _notEmpty($value)
1293: {
1294: return trim($value) !== '';
1295: }
1296:
1297: /**
1298: * Generate breadcrumb by a separator
1299: *
1300: * @param mixed $args Array of string arguments or multiple string arguments
1301: * @return void
1302: */
1303: function _breadcrumb()
1304: {
1305: global $lc_breadcrumbSeparator;
1306:
1307: $args = func_get_args();
1308:
1309: if (!$lc_breadcrumbSeparator) {
1310: $lc_breadcrumbSeparator = '&raquo;';
1311: }
1312:
1313: if (count($args) == 1 && is_array($args[0])) {
1314: $args = $args[0];
1315: }
1316:
1317: echo implode(" {$lc_breadcrumbSeparator} ", $args);
1318: }
1319:
1320: /**
1321: * Shorten a string for the given length
1322: *
1323: * @param string $str A plain text string to be shortened
1324: * @param integer $length The character count
1325: * @param string $trail To append `...` or not. `null` to not show
1326: *
1327: * @return string The shorten text string
1328: */
1329: function _shorten($str, $length = 50, $trail = '...')
1330: {
1331: if (empty($str)) {
1332: return $str;
1333: }
1334:
1335: $str = strip_tags(trim($str));
1336: if (strlen($str) <= $length) {
1337: return $str;
1338: }
1339:
1340: $short = trim(substr($str, 0, $length));
1341: $lastSpacePos = strrpos($short, ' ');
1342: if ($lastSpacePos !== false) {
1343: $short = substr($short, 0, $lastSpacePos);
1344: }
1345:
1346: if ($trail) {
1347: $short = rtrim($short, '.') . $trail;
1348: }
1349:
1350: return $short;
1351: }
1352:
1353: if (!function_exists('_fstr')) {
1354: /**
1355: * Format a string
1356: *
1357: * @param string|array $value A text string or array of text strings to be formatted
1358: * @param string $glue The glue string between each element
1359: * @param string $lastGlue The glue string between the last two elements
1360: *
1361: * @return string The formatted text string
1362: */
1363: function _fstr($value, $glue = ', ', $lastGlue = 'and')
1364: {
1365: if (empty($value)) {
1366: return $value;
1367: }
1368:
1369: if (!is_array($value)) {
1370: return $value == '' ? _nullFill($value) : nl2br($value);
1371: } elseif (is_array($value) && sizeof($value) > 1) {
1372: $last = array_slice($value, -2, 2);
1373: $lastImplode = implode(' '.$lastGlue.' ', $last);
1374: $first = array_slice($value, 0, sizeof($value)-2);
1375: $firstImplode = implode($glue, $first);
1376:
1377: return $firstImplode ? $firstImplode.$glue.$lastImplode : $lastImplode;
1378: } else {
1379: return nl2br($value[0]);
1380: }
1381: }
1382: }
1383:
1384: if (!function_exists('_fnum')) {
1385: /**
1386: * Format a number
1387: *
1388: * @param int $value A number to be formatted
1389: * @param int $decimals The decimal places. Default is 2.
1390: * @param string $unit The unit appended to the number (optional)
1391: *
1392: * @return string The formatted number
1393: */
1394: function _fnum($value, $decimals = 2, $unit = '')
1395: {
1396: if ($value === '') {
1397: return _nullFill($value);
1398: } elseif (is_numeric($value)) {
1399: $value = number_format($value, $decimals, '.', ',');
1400:
1401: return $unit ? $value . ' ' . $unit : $value;
1402: }
1403:
1404: return $value;
1405: }
1406: }
1407:
1408: if (!function_exists('_fnumSmart')) {
1409: /**
1410: * Format a number in a smarter way, i.e., decimal places are omitted when necessary.
1411: * Given the 2 decimal places, the value 5.00 will be shown 5 whereas the value 5.01 will be shown as it is.
1412: *
1413: * @param int $value A number to be formatted
1414: * @param int $decimals The decimal places. Default is 2.
1415: * @param string $unit The unit appended to the number (optional)
1416: *
1417: * @return string The formatted number
1418: */
1419: function _fnumSmart($value, $decimals = 2, $unit = '')
1420: {
1421: $value = _fnum($value, $decimals, $unit);
1422: $v = explode('.', $value);
1423: if ($decimals > 0 && isset($v[1])) {
1424: if (preg_match('/0{'.$decimals.'}/i', $v[1])) {
1425: $value = $v[0];
1426: }
1427: }
1428:
1429: return $value;
1430: }
1431: }
1432:
1433: if (!function_exists('_fnumReverse')) {
1434: /**
1435: * Remove the number formatting (e.g., thousand separator) from the given number
1436: *
1437: * @param mixed $num A number to remove the formatting
1438: * @return mixed The number
1439: */
1440: function _fnumReverse($num)
1441: {
1442: return str_replace(',', '', $num);
1443: }
1444: }
1445:
1446: if (!function_exists('_fdate')) {
1447: /**
1448: * Format a date
1449: *
1450: * @param string $date A date to be formatted
1451: * @param string $format The date format; The config variable will be used if it is not passed
1452: * @return string The formatted date
1453: */
1454: function _fdate($date = '', $format = '')
1455: {
1456: if (!$format) {
1457: $format = _cfg('dateFormat');
1458: }
1459:
1460: if (func_num_args() === 0) {
1461: return date($format);
1462: }
1463:
1464: if (empty($date)) {
1465: return '';
1466: }
1467:
1468: return is_string($date) ? date($format, strtotime($date)) : date($format, $date);
1469: }
1470: }
1471:
1472: if (!function_exists('_fdatetime')) {
1473: /**
1474: * Format a date/time
1475: *
1476: * @param string $dateTime A date/time to be formatted
1477: * @param string $format The date/time format; The config variable will be used if it is not passed
1478: * @return string The formatted date/time
1479: */
1480: function _fdatetime($dateTime = '', $format = '')
1481: {
1482: if (!$format) {
1483: $format = _cfg('dateTimeFormat');
1484: }
1485:
1486: if (func_num_args() == 0) {
1487: return date($format);
1488: }
1489:
1490: if (empty($dateTime)) {
1491: return '';
1492: }
1493:
1494: return date($format, strtotime($dateTime));
1495: }
1496: }
1497:
1498: if (!function_exists('_ftimeAgo')) {
1499: /**
1500: * Display elapsed time in wording, e.g., 2 hours ago, 1 year ago, etc.
1501: *
1502: * @param string|int $time The elapsed time in unix timestamp or date/time string
1503: * @param string $format The date/time format to show when 4 days passed
1504: * @return string
1505: */
1506: function _ftimeAgo($time, $format = 'M j Y')
1507: {
1508: if (empty($time)) {
1509: return '';
1510: }
1511:
1512: $now = time();
1513: if (!is_numeric($time)) {
1514: $time = strtotime($time);
1515: }
1516:
1517: $secElapsed = $now - $time;
1518: if ($secElapsed <= 60) {
1519: return _t('just now');
1520: } elseif ($secElapsed <= 3540) {
1521: $min = $now - $time;
1522: $min = round($min/60);
1523: return _t('%d minutes ago', $min);
1524: } elseif ($secElapsed <= 3660) {
1525: return _t('1 hour ago');
1526: } elseif (date('j-n-y', $now) == date('j-n-y', $time)) {
1527: return date("g:i a", $time);
1528: } elseif (date('j-n-y', mktime(0, 0, 0, date('n', $now), date('j', $now)-1, date('Y', $now))) == date('j-n-y', $time)) {
1529: return _t('yesterday');
1530: } elseif ($secElapsed <= 345600) {
1531: return date('l', $time);
1532: } else {
1533: return date($format, $time);
1534: }
1535: }
1536: }
1537:
1538: if (!function_exists('_msg')) {
1539: /**
1540: * Print or return the message formatted with HTML
1541: *
1542: * @param mixed $msg A message string or Array of message strings
1543: * @param string $class The CSS class name
1544: * @param mixed $return What is expected to return from this function.
1545: * `null` (default) no return and just print it.
1546: * `html` return HTML.
1547: * @param string $display CSs display property value - block, none, inline-block, etc.
1548: *
1549: * @return string The formatted date
1550: */
1551: function _msg($msg, $class = 'error', $return = null, $display = null)
1552: {
1553: $class = $class ?: 'error';
1554: $return = strtolower($return);
1555:
1556: $html = '';
1557: $html .= '<div class="message"';
1558: if ($display) {
1559: $html .= ' style="display:' . $display . '"';
1560: }
1561: $html .= '>';
1562: $html .= '<div class="message-'. $class . ' alert alert-' . ($class == 'error' ? 'danger' : $class) . '">';
1563: if (is_array($msg)) {
1564: if (count($msg) > 0) {
1565: $html .= '<ul>';
1566: foreach ($msg as $m) {
1567: if (is_array($msg) && isset($m['message'])) {
1568: $html .= '<li>'.$m['message'].'</li>';
1569: } else {
1570: $html .= '<li>'.$m.'</li>';
1571: }
1572: }
1573: $html .= '</ul>';
1574: } else {
1575: $html = '';
1576: }
1577: } else {
1578: $html .= $msg;
1579: }
1580:
1581: $html .= '</div></div>';
1582:
1583: if (is_array($msg) && count($msg) == 0) {
1584: $html = '';
1585: }
1586:
1587: if ($return == 'html' || $return === true) {
1588: return $html;
1589: } else {
1590: echo $html;
1591: }
1592:
1593: return '';
1594: }
1595: }
1596:
1597: /**
1598: * Find the size of the given file.
1599: *
1600: * @param string $file The file name (file must exist)
1601: * @param int $digits Number of precisions
1602: * @param array $sizes Array of size units, e.g., array("TB","GB","MB","KB","B"). Default is array("MB","KB","B")
1603: *
1604: * @return string|bool The size unit (B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB) or `FALSE` for non-existence file
1605: */
1606: function _filesize($file, $digits = 2, $sizes = array("MB","KB","B"))
1607: {
1608: if (is_file($file)) {
1609: $filePath = $file;
1610: if (!realpath($filePath)) {
1611: $filePath = $_SERVER["DOCUMENT_ROOT"].$filePath;
1612: }
1613: $fileSize = filesize($filePath);
1614: $total = count($sizes);
1615: while ($total-- && $fileSize > 1024) {
1616: $fileSize /= 1024;
1617: }
1618:
1619: return round($fileSize, $digits)." ".$sizes[$total];
1620: }
1621:
1622: return false;
1623: }
1624:
1625: if (!function_exists('_randomCode')) {
1626: /**
1627: * Generate a random string from the given array of letters.
1628: * @param int $length The length of required random string
1629: * @param array $letters Array of letters from which randomized string is derived from.
1630: * Default is a to z and 0 to 9.
1631: * @param string $prefix Prefix to the generated string
1632: * @return string The random string of required length
1633: */
1634: function _randomCode($length = 5, $letters = array(), $prefix = '')
1635: {
1636: # Letters & Numbers for default
1637: if (sizeof($letters) == 0) {
1638: $letters = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));
1639: }
1640:
1641: shuffle($letters); # Shuffle letters
1642: $randArr = array_splice($letters, 0, $length);
1643:
1644: return $prefix . implode('', $randArr);
1645: }
1646: }
1647:
1648: if (!function_exists('_slug')) {
1649: /**
1650: * Generate a slug of human-readable keywords
1651: *
1652: * @param string $string Text to slug
1653: * @param string $table Table name to check in. If it is empty, no check in the table
1654: * @param array $condition Condition to append table check-in, e.g, `array('fieldName !=' => value)`
1655: *
1656: * @return string The generated slug
1657: */
1658: function _slug($string, $table = '', array $condition = array())
1659: {
1660: $specChars = array(
1661: '`','~','!','@','#','$','%','\^','&',
1662: '*','(',')','=','+','{','}','[',']',
1663: ':',';',"'",'"','<','>','\\','|','?','/',','
1664: );
1665: $table = db_table($table);
1666: $slug = strtolower(trim($string));
1667: $slug = trim($slug, '-');
1668: # clear special characters
1669: $slug = preg_replace('/(&amp;|&quot;|&#039;|&lt;|&gt;)/i', '', $slug);
1670: $slug = str_replace($specChars, '-', $slug);
1671: $slug = str_replace(array(' ', '.'), '-', $slug);
1672: $slug = trim($slug, '-');
1673:
1674: $condition = array_merge(
1675: array('slug' => $slug),
1676: $condition
1677: );
1678:
1679: while (true && $table) {
1680: $count = db_count($table)->where($condition)->fetch();
1681: if ($count == 0) {
1682: break;
1683: }
1684:
1685: $segments = explode('-', $slug);
1686: if (sizeof($segments) > 1 && is_numeric($segments[sizeof($segments)-1])) {
1687: $index = array_pop($segments);
1688: $index++;
1689: } else {
1690: $index = 1;
1691: }
1692:
1693: $segments[] = $index;
1694: $slug = implode('-', $segments);
1695: }
1696:
1697: $slug = preg_replace('/[\-]+/', '-', $slug);
1698:
1699: return trim($slug, '-');
1700: }
1701: }
1702:
1703: /**
1704: * Return the SQL date (Y-m-d) from the given date and format
1705: *
1706: * @param string $date Date to convert
1707: * @param string $givenFormat Format for the given date
1708: * @param string $separator Separator in the date. Default is dash "-"
1709: *
1710: * @return string|null the SQL date string if the given date is valid, otherwise null
1711: */
1712: function _sqlDate($date, $givenFormat = 'dmy', $separator = '-')
1713: {
1714: if (empty($date)) {
1715: return null;
1716: }
1717:
1718: $dt = explode($separator, $date);
1719: $format = str_split($givenFormat);
1720: $ft = array_flip($format);
1721:
1722: $y = $dt[$ft['y']];
1723: $m = $dt[$ft['m']];
1724: $d = $dt[$ft['d']];
1725:
1726: return checkdate($m, $d, $y) ? $y . '-' . $m .'-'. $d : null;
1727: }
1728:
1729: /**
1730: * Encrypts the given text using security salt if mcrypt extension is enabled, otherwise using md5()
1731: *
1732: * @param string $text Text to be encrypted
1733: * @return string The encrypted text
1734: */
1735: function _encrypt($text)
1736: {
1737: $secret = _cfg('securitySecret');
1738: if (!$secret || !function_exists('openssl_encrypt')) {
1739: return md5($text);
1740: }
1741:
1742: $method = _cipher();
1743: $ivlen = openssl_cipher_iv_length($method);
1744: $iv = openssl_random_pseudo_bytes($ivlen);
1745:
1746: $textRaw = openssl_encrypt($text, $method, $secret, OPENSSL_RAW_DATA, $iv);
1747: $hmac = hash_hmac('sha256', $textRaw, $secret, true);
1748:
1749: return base64_encode($iv . $hmac . $textRaw );
1750: }
1751:
1752: /**
1753: * Decrypts the given text using security salt if mcrypt extension is enabled,
1754: * otherwise return the original encrypted string
1755: *
1756: * @param string $encryptedText Text to be decrypted
1757: * @return string The decrypted text
1758: */
1759: function _decrypt($encryptedText)
1760: {
1761: $secret = _cfg('securitySecret');
1762: if (!$secret || !function_exists('openssl_decrypt')) {
1763: return $encryptedText;
1764: }
1765:
1766: $method = _cipher();
1767: $sha2len = 32;
1768: $ivlen = openssl_cipher_iv_length($method);
1769: $text = base64_decode($encryptedText);
1770: $iv = substr($text, 0, $ivlen);
1771:
1772: $rawText = substr($text, $ivlen + $sha2len);
1773: $plainText = openssl_decrypt($rawText, $method, $secret, OPENSSL_RAW_DATA, $iv);
1774:
1775: $hmac = substr($text, $ivlen, $sha2len);
1776: $mac = hash_hmac('sha256', $rawText, $secret, true);
1777: if (hash_equals($hmac, $mac)) {
1778: return $plainText;
1779: }
1780:
1781: return $text;
1782: }
1783:
1784: /**
1785: * Get current cipher method
1786: * @return string
1787: */
1788: function _cipher()
1789: {
1790: $method = _cfg('cipher');
1791: if (!in_array($method, openssl_get_cipher_methods())) {
1792: $method = 'AES-256-CBC';
1793: }
1794:
1795: return $method;
1796: }
1797:
1798: /**
1799: * Simple quick helper function for <meta> tag attribute values
1800: *
1801: * @param string $key The <meta> tag name
1802: * @param string $value If the value is empty, this is a Getter function; otherwise Setter function
1803: * @return void|mixed
1804: */
1805: function _meta($key, $value = '')
1806: {
1807: global $_meta;
1808: $value = trim($value);
1809: if (empty($value)) {
1810: return (isset($_meta[$key])) ? $_meta[$key] : '';
1811: } else {
1812: if (in_array($key, array('description', 'og:description', 'twitter:description', 'gp:description'))) {
1813: $value = trim(substr($value, 0, 200));
1814: }
1815: $_meta[$key] = $value;
1816: }
1817: }
1818:
1819: /**
1820: * Print SEO meta tags
1821: * @return void
1822: */
1823: function _metaSeoTags()
1824: {
1825: if (_meta('description')) {
1826: _cfg('metaDescription', _meta('description'));
1827: }
1828:
1829: if (_meta('keywords')) {
1830: _cfg('metaKeywords', _meta('keywords'));
1831: }
1832:
1833: $tags = array();
1834: $tags['description'] = _cfg('metaDescription');
1835: $tags['keywords'] = _cfg('metaKeywords');
1836:
1837: $tags['og'] = array();
1838: $tags['og']['title'] = _meta('og:title') ? _meta('og:title') : _cfg('siteName');
1839: $tags['og']['url'] = _meta('og:url') ? _meta('og:url') : _url();
1840: $tags['og']['type'] = _meta('og:type') ? _meta('og:type') : 'website';
1841: $tags['og']['image'] = _meta('og:image') ? _meta('og:image') : _img('logo-social.jpg');
1842: $tags['og']['description'] = _meta('og:description') ? _meta('og:description') : _cfg('metaDescription');
1843: $tags['og']['site_name'] = _meta('og:site_name') ? _meta('og:site_name') : _cfg('siteName');
1844:
1845: $tags['twitter'] = array();
1846: $tags['twitter']['card'] = _meta('twitter:card') ? _meta('twitter:card') : 'summary';
1847: $tags['twitter']['site'] = _meta('twitter:site') ? '@'._meta('twitter:site') : '@'._cfg('siteDomain');
1848: $tags['twitter']['title'] = _meta('twitter:title') ? _meta('twitter:title') : _cfg('siteName');
1849: $tags['twitter']['description'] = _meta('twitter:description') ? _meta('twitter:description') : _cfg('metaDescription');
1850: $tags['twitter']['image'] = _meta('twitter:image') ? _meta('twitter:image') : _img('logo-social.jpg');
1851:
1852: if (function_exists('__metaSeoTags')) {
1853: echo __metaSeoTags($tags);
1854: } else {
1855: echo "\n";
1856: foreach ($tags as $name => $tag) {
1857: if ($name == 'og') {
1858: foreach ($tag as $key => $content) {
1859: echo '<meta property="og:' . $key . '" content="' . $content . '" />'."\n";
1860: }
1861: } elseif ($name == 'twitter') {
1862: foreach ($tag as $key => $content) {
1863: echo '<meta name="twitter:' . $key . '" content="' . $content . '" />'."\n";
1864: }
1865: } else {
1866: echo '<meta name="' . $name . '" content="' . $tag . '" />'."\n";
1867: }
1868: }
1869: }
1870: }
1871:
1872: /**
1873: * Simple mail helper function
1874: * The formatting of the email addresses must comply with RFC 2822. Some examples are:
1875: *
1876: * - user@example.com
1877: * - user@example.com, anotheruser@example.com
1878: * - User <user@example.com>
1879: * - User <user@example.com>, Another User <anotheruser@example.com>*
1880: *
1881: * @param string $from The sender of the mail
1882: * @param string $to The receiver or receivers of the mail
1883: * @param string $subject Subject of the email to be sent.
1884: * @param string $message Message to be sent
1885: * @param string $cc The CC receiver or receivers of the mail
1886: * @param string $bcc The Bcc receiver or receivers of the mail
1887: *
1888: * @return boolean Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise
1889: */
1890: function _mail($from, $to, $subject = '', $message = '', $cc = '', $bcc = '')
1891: {
1892: $charset = mb_detect_encoding($message);
1893: $message = nl2br(stripslashes($message));
1894:
1895: $EEOL = PHP_EOL; //"\n";
1896: $headers = 'From: ' . $from . $EEOL;
1897: $headers .= 'MIME-Version: 1.0' . $EEOL;
1898: $headers .= 'Content-type: text/html; charset=' . $charset . $EEOL;
1899: $headers .= 'Reply-To: ' . $from . $EEOL;
1900: $headers .= 'Return-Path:'.$from . $EEOL;
1901: if ($cc) {
1902: $headers .= 'Cc: ' . $cc . $EEOL;
1903: }
1904: if ($bcc) {
1905: $headers .= 'Bcc: ' . $bcc . $EEOL;
1906: }
1907: $headers .= 'X-Mailer: PHP';
1908:
1909: return mail($to, $subject, $message, $headers);
1910: }
1911: /**
1912: * Get translation strings from the POST array
1913: * and prepare to insert or update into the table according to the specified fields
1914: *
1915: * @param array $post The POST array
1916: * @param array $fields The array of field name and input name mapping, e.g., array('fieldName' => 'inputName')
1917: * @param string $lang The language code to fetch (if it is not provided, all languages will be fetched)
1918: *
1919: * @return array The data array
1920: */
1921: function _postTranslationStrings($post, $fields, $lang = null)
1922: {
1923: global $lc_languages;
1924:
1925: $data = array();
1926: foreach ($fields as $key => $name) {
1927: if ($lang) {
1928: $lcode = _queryLang($lang);
1929: if (isset($post[$name.'_'.$lcode])) {
1930: $data[$key.'_'.$lcode] = $post[$name.'_'.$lcode];
1931: }
1932: } else {
1933: if (isset($post[$name])) {
1934: $data[$key.'_'._defaultLang()] = $post[$name];
1935: }
1936: foreach ($lc_languages as $lcode => $lname) {
1937: $lcode = _queryLang($lcode);
1938: if (isset($post[$name.'_'.$lcode])) {
1939: $data[$key.'_'.$lcode] = $post[$name.'_'.$lcode];
1940: }
1941: }
1942: }
1943: }
1944:
1945: return $data;
1946: }
1947:
1948: /**
1949: * Get translation strings from the query result
1950: * and return the array of `$i18n[fieldName][lang] = $value`
1951: *
1952: * @param object|array $data The query result
1953: * @param array|string $fields The array of field names to get data, e.g.,
1954: * 'fieldName' or `array('fieldName1', 'fieldName2')`
1955: * @param string $lang The language code to fetch (if it is not provided, all languages will be fetched)
1956: *
1957: * @return array|object The array or object of translation strings
1958: */
1959: function _getTranslationStrings($data, $fields, $lang = null)
1960: {
1961: global $lc_languages;
1962:
1963: $isObject = is_object($data);
1964: $data = (array) $data;
1965:
1966: if (is_string($fields)) {
1967: $fields = array($fields);
1968: }
1969:
1970: foreach ($fields as $name) {
1971: if ($lang) {
1972: $lcode = _queryLang($lang);
1973: if (isset($data[$name.'_'.$lcode]) && $data[$name.'_'.$lcode]) {
1974: $data[$name.'_i18n'] = $data[$name.'_'.$lcode];
1975: } else {
1976: $data[$name.'_i18n'] = $data[$name];
1977: }
1978: } else {
1979: foreach ($lc_languages as $lcode => $lname) {
1980: $lcode = _queryLang($lcode);
1981: if (isset($data[$name.'_'.$lcode])) {
1982: $data[$name.'_i18n'][$lcode] = $data[$name.'_'.$lcode];
1983: }
1984: }
1985: }
1986: }
1987:
1988: if ($isObject) {
1989: $data = (object) $data;
1990: }
1991:
1992: return $data;
1993: }
1994:
1995: /**
1996: * Detect the current page visited by a search bot or crawler
1997: * @return boolean `TRUE` if it is a bot's visit; otherwise `FALSE`
1998: * @see http://www.useragentstring.com/pages/useragentstring.php?typ=Crawler
1999: */
2000: function _isBot()
2001: {
2002: if (!isset($_SERVER['HTTP_USER_AGENT'])) {
2003: return false;
2004: }
2005:
2006: $userAgent = $_SERVER['HTTP_USER_AGENT'];
2007: if (empty($userAgent)) {
2008: return false;
2009: }
2010:
2011: $bots = array(
2012: 'Googlebot',
2013: 'Slurp',
2014: 'msnbot',
2015: 'bingbot',
2016: 'yahoo',
2017: 'search.msn.com',
2018: 'Baidu',
2019: 'baiduspider',
2020: 'Yandex',
2021: 'nutch',
2022: 'FAST',
2023: 'Sosospider',
2024: 'Exabot',
2025: 'sogou',
2026: 'bot',
2027: 'crawler',
2028: 'spider',
2029: 'Feedfetcher-Google',
2030: 'ASPSeek',
2031: 'simpy',
2032: 'ips-agent',
2033: 'Libwww-perl',
2034: 'ask jeeves',
2035: 'fastcrawler',
2036: 'infoseek',
2037: 'lycos',
2038: 'mediapartners-google',
2039: 'CRAZYWEBCRAWLER',
2040: 'adsbot-google',
2041: 'curious george',
2042: 'ia_archiver',
2043: 'MJ12bot',
2044: 'Uptimebot',
2045: 'Dataprovider.com',
2046: 'Go-http-client',
2047: 'Barkrowler',
2048: 'panscient.com',
2049: 'Symfony BrowserKit',
2050: 'Apache-HttpClient',
2051: 'serpstatbot',
2052: 'BLEXBot',
2053: 'DotBot',
2054: 'AhrefsBot',
2055: );
2056: foreach ($bots as $bot) {
2057: if (false !== strpos(strtolower($userAgent), strtolower($bot))) {
2058: return true;
2059: }
2060: }
2061:
2062: return false;
2063: }
2064:
2065: /**
2066: * Write output
2067: * @since PHPLucidFrame v 1.14.0
2068: * @param string $text The text to output
2069: * @param [mixed $args [, mixed ...]] Arguments to the text
2070: * @return void
2071: */
2072: function _write($text = '')
2073: {
2074: $args = func_get_args();
2075: $text = array_shift($args);
2076: if ($text) {
2077: echo vsprintf($text, $args);
2078: }
2079: }
2080:
2081: /**
2082: * Write output with line feed (\n)
2083: * @since PHPLucidFrame v 1.11.0
2084: * @param string $text The text to output
2085: * @param [mixed $args [, mixed ...]] Arguments to the text
2086: * @return void
2087: */
2088: function _writeln($text = '')
2089: {
2090: $args = func_get_args();
2091: $text = array_shift($args);
2092: if ($text) {
2093: echo vsprintf($text, $args);
2094: }
2095:
2096: echo "\n";
2097: }
2098:
2099: /**
2100: * Write spacer for indentation purpose
2101: * @since PHPLucidFrame v 1.11.0
2102: * @param int $width No. of spaces
2103: * @return void|string
2104: */
2105: function _indent($width = 2)
2106: {
2107: return str_repeat(' ', $width);
2108: }
2109:
2110: /**
2111: * Simple helper to create an instance of LucidFrame\Console\Command
2112: * @since PHPLucidFrame v 1.11.0
2113: * @param string $command The command name
2114: * @return object LucidFrame\Console\Command
2115: */
2116: function _consoleCommand($command)
2117: {
2118: return new Command($command);
2119: }
2120:
2121: /**
2122: * Simple helper to create an instance of LucidFrame\Console\ConsoleTable
2123: * @since PHPLucidFrame v 1.12.0
2124: * @return object LucidFrame\Console\ConsoleTable
2125: */
2126: function _consoleTable()
2127: {
2128: return new ConsoleTable();
2129: }
2130:
2131: /**
2132: * Simple helper to get all registered commands
2133: * @since PHPLucidFrame v 1.12.0
2134: * @return array The array of command LucidFrame\Console\Command
2135: */
2136: function _consoleCommands()
2137: {
2138: return Console::getCommands();
2139: }
2140:
2141: /**
2142: * Simple helper to create Pager object
2143: * @since PHPLucidFrame v 1.11.0
2144: * @param string $pageQueryStr The customized page query string name, default is page
2145: * @return object LucidFrame\Core\Pager
2146: */
2147: function _pager($pageQueryStr = '')
2148: {
2149: return new Pager($pageQueryStr);
2150: }
2151:
2152: /**
2153: * Simple helper to create File object
2154: * @since PHPLucidFrame v 1.11.0
2155: * @param string $fileName (optinal) Path to the file
2156: * @return object LucidFrame\File\File
2157: */
2158: function _fileHelper($fileName = '')
2159: {
2160: return new File($fileName);
2161: }
2162:
2163: /**
2164: * Simple helper to create AsynFileUploader object
2165: * @since PHPLucidFrame v 1.11.0
2166: * @param string/array anonymous The input file name or The array of property/value pairs
2167: * @return object LucidFrame\File\AsynFileUploader
2168: */
2169: function _asynFileUploader()
2170: {
2171: if (func_num_args()) {
2172: return new AsynFileUploader(func_get_arg(0));
2173: } else {
2174: return new AsynFileUploader();
2175: }
2176: }
2177:
2178: /**
2179: * Simple helper to register a middleware
2180: * @since PHPLucidFrame v 2.0.0
2181: * @param Closure $closure Anonymous function
2182: * @param string $event before (default) or after
2183: * @return object LucidFrame\Core\Middleware
2184: */
2185: function _middleware(\Closure $closure, $event = 'before')
2186: {
2187: $middleware = new Middleware();
2188:
2189: return $middleware->register($closure, $event);
2190: }
2191:
2192: /**
2193: * Get view file
2194: * @return string The view file with absolute path
2195: */
2196: function _view()
2197: {
2198: if (_cfg('view')) {
2199: $viewName = 'view_'._cfg('view');
2200: } elseif (_g('view')) {
2201: $viewName = 'view_'._g('view');
2202: } else {
2203: $viewName = 'view';
2204: }
2205:
2206: return _i(_ds(_cr(), $viewName.'.php'));
2207: }
2208:
2209: /**
2210: * Return directories and file names glued by directory separator
2211: * @return string
2212: */
2213: function _ds()
2214: {
2215: return implode(_DS_, func_get_args());
2216: }
2217:
2218: /**
2219: * Check if the request is an AJAX request
2220: * @return boolean TRUE if the request is XmlHttpRequest, otherwise FALSE
2221: */
2222: function _isAjax()
2223: {
2224: if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
2225: strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
2226: return true;
2227: }
2228:
2229: return false;
2230: }
2231:
2232: /**
2233: * Check if HTTP request method is POST and has request data
2234: * @return bool
2235: */
2236: function _isHttpPost()
2237: {
2238: return _isRequestMethod('POST') && count($_POST);
2239: }
2240:
2241: /**
2242: * Header sent as text/json
2243: * @param array|object $data Array/Object of data to be encoded as JSON
2244: * @param int $status HTTP status code, default to 200
2245: * @return void
2246: */
2247: function _json($data = [], $status = 200)
2248: {
2249: if (_isRequestMethod('OPTIONS')) {
2250: _header(200);
2251: exit;
2252: }
2253:
2254: _header($status);
2255:
2256: header('Content-Type: application/json');
2257: if ($status != 204) {
2258: echo json_encode($data);
2259: }
2260:
2261: Middleware::runAfter();
2262: exit;
2263: }
2264:
2265: /**
2266: * Response error as JSON
2267: * @param string|array $message The error message or array of error message
2268: * @param string $field The field name
2269: * @param int $status HTTP status code
2270: * @return void
2271: */
2272: function _jsonError($message, $field = '', $status = 400)
2273: {
2274: $errors = [];
2275: if (is_array($message)) {
2276: $errors = $message;
2277: } else {
2278: $errors[] = [
2279: 'field' => $field,
2280: 'message' => $message,
2281: ];
2282:
2283: }
2284:
2285: _json(['error' => $errors], $status);
2286: }
2287:
2288: /**
2289: * Fetch all HTTP request headers
2290: * @return array An associative array of all the HTTP headers in the current request, or FALSE on failure.
2291: */
2292: function _requestHeaders()
2293: {
2294: if (function_exists('getallheaders')) {
2295: return getallheaders();
2296: }
2297:
2298: if (function_exists('apache_request_headers')) {
2299: return apache_request_headers();
2300: }
2301:
2302: $headers = array();
2303: foreach ($_SERVER as $name => $value) {
2304: $name = strtolower($name);
2305: if (substr($name, 0, 5) == 'http_') {
2306: $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($name, 5))))] = $value;
2307: } elseif ($name == 'content_type') {
2308: $headers['Content-Type'] = $value;
2309: } elseif ($name == 'content_length') {
2310: $headers['Content-Length'] = $value;
2311: }
2312: }
2313:
2314: return $headers;
2315: }
2316:
2317: /**
2318: * Fetch a HTTP request header by name
2319: * @param string $name The HTTP header name
2320: * @return string The HTTP header value from the request
2321: */
2322: function _requestHeader($name)
2323: {
2324: $headers = _requestHeaders();
2325: if (!is_array($headers)) {
2326: return null;
2327: }
2328:
2329: $headers = array_change_key_case($headers);
2330: $name = strtolower($name);
2331:
2332: if (isset($headers[$name])) {
2333: return $headers[$name];
2334: }
2335:
2336: return null;
2337: }
2338:
2339: /**
2340: * Get request method
2341: * @return string|null
2342: */
2343: function _requestMethod()
2344: {
2345: if (isset($_SERVER['REQUEST_METHOD'])) {
2346: return strtoupper($_SERVER['REQUEST_METHOD']);
2347: }
2348:
2349: return null;
2350: }
2351:
2352: /**
2353: * Check if the request method is the given one
2354: * @param string $method The request method
2355: * @return bool
2356: */
2357: function _isRequestMethod($method)
2358: {
2359: return _requestMethod() == strtoupper($method);
2360: }
2361:
2362: /**
2363: * Convert form data into js variable
2364: * @param string $name The form name or scope name
2365: * @param array $data Array of data
2366: */
2367: function _addFormData($name, array $data)
2368: {
2369: echo '<script>LC.Form.formData["' . $name . '"] = ' . json_encode($data) . ';</script>';
2370: }
2371:
2372: /**
2373: * Return a value or empty sign
2374: * Hook to implement `__nullFill()` at app/helpers/utility_helper.php
2375: * @param mixed $value The value to check and show
2376: * @return string
2377: */
2378: function _nullFill($value)
2379: {
2380: if (function_exists('__nullFill')) {
2381: return __nullFill($value);
2382: }
2383:
2384: return $value ?: '<span class="null-fill">-</span>';
2385: }
2386:
2387: /**
2388: * Get default entity object from the schema
2389: * @param string $table The mapped table name without prefix
2390: * @param string|null $dbNamespace The current db namespace
2391: * @return object The empty stdClass object with field names as properties
2392: */
2393: function _entity($table, $dbNamespace = null)
2394: {
2395: if (!$dbNamespace) {
2396: $dbNamespace = _cfg('defaultDbSource');
2397: }
2398:
2399: $schema = _schema($dbNamespace, true);
2400:
2401: $entity = array();
2402: if ($schema && isset($schema[$table])) {
2403: $options = array_merge(SchemaManager::$relationships, array('options'));
2404: foreach ($schema[$table] as $field => $def) {
2405: if (in_array($field, $options)) {
2406: continue;
2407: }
2408:
2409: if (isset($def['autoinc'])) {
2410: $value = 0;
2411: } else {
2412: $value = isset($def['null']) ? null : '';
2413: if (isset($def['default'])) {
2414: $value = $def['default'];
2415: }
2416: }
2417:
2418: if ($field == 'created' || $field == 'updated') {
2419: $value = date('Y-m-i H:i:s');
2420: }
2421:
2422: if ($def['type'] == 'array' || $def['type'] == 'json') {
2423: $value = array();
2424: }
2425:
2426: $entity[$field] = $value;
2427: }
2428: }
2429:
2430: return (object) $entity;
2431: }
2432:
2433: /**
2434: * Add CSS file to be included in head section
2435: * @param string $file An absolute file path or file name only.
2436: * The file name only will be prepended the folder name css/ and it will be looked in every sub-sites "css" folder
2437: */
2438: function _addHeadStyle($file)
2439: {
2440: $view = _app('view');
2441: $view->addHeadStyle($file);
2442: }
2443:
2444: /**
2445: * Add JS file to be included in head section
2446: * @param string $file An absolute file path or file name only.
2447: * The file name only will be prepended the folder name js/ and it will be looked in every sub-sites "js" folder
2448: */
2449: function _addHeadScript($file)
2450: {
2451: $view = _app('view');
2452: $view->addHeadScript($file);
2453: }
2454:
2455: /**
2456: * Convert English number to Myanmar number
2457: * @param string $num
2458: * @return string
2459: */
2460: function _en2myNum($num)
2461: {
2462: $digits = array(
2463: '/0/' => '၀',
2464: '/1/' => '၁',
2465: '/2/' => '၂',
2466: '/3/' => '၃',
2467: '/4/' => '၄',
2468: '/5/' => '၅',
2469: '/6/' => '၆',
2470: '/7/' => '၇',
2471: '/8/' => '၈',
2472: '/9/' => '၉',
2473: );
2474:
2475: return preg_replace(array_keys($digits), array_values($digits), $num);
2476: }
2477:
2478: /**
2479: * Check if array is associative or sequential
2480: * @param array $arr The array to be checked
2481: * @return bool
2482: */
2483: function _arrayAssoc(array $arr)
2484: {
2485: if (empty($arr)) {
2486: return false;
2487: }
2488:
2489: return array_keys($arr) !== range(0, count($arr) - 1);
2490: }
2491:
2492: /**
2493: * Check if HTTP header has the given content type
2494: * @param string $type HTTP header content type
2495: * @return bool
2496: */
2497: function _isContentType($type)
2498: {
2499: return isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] == $type;
2500: }
2501: