1: <?php
2: /**
3: * Basic CakePHP functionality.
4: *
5: * Core functions for including other source files, loading models and so forth.
6: *
7: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8: * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
9: *
10: * Licensed under The MIT License
11: * For full copyright and license information, please see the LICENSE.txt
12: * Redistributions of files must retain the above copyright notice.
13: *
14: * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
15: * @link http://cakephp.org CakePHP(tm) Project
16: * @package Cake
17: * @since CakePHP(tm) v 0.2.9
18: * @license http://www.opensource.org/licenses/mit-license.php MIT License
19: */
20:
21: /**
22: * Basic defines for timing functions.
23: */
24: define('SECOND', 1);
25: define('MINUTE', 60);
26: define('HOUR', 3600);
27: define('DAY', 86400);
28: define('WEEK', 604800);
29: define('MONTH', 2592000);
30: define('YEAR', 31536000);
31:
32: if (!function_exists('config')) {
33:
34: /**
35: * Loads configuration files. Receives a set of configuration files
36: * to load.
37: * Example:
38: *
39: * `config('config1', 'config2');`
40: *
41: * @return bool Success
42: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#config
43: */
44: function config() {
45: $args = func_get_args();
46: $count = count($args);
47: $included = 0;
48: foreach ($args as $arg) {
49: if (file_exists(APP . 'Config' . DS . $arg . '.php')) {
50: include_once APP . 'Config' . DS . $arg . '.php';
51: $included++;
52: }
53: }
54: return $included === $count;
55: }
56:
57: }
58:
59: if (!function_exists('debug')) {
60:
61: /**
62: * Prints out debug information about given variable.
63: *
64: * Only runs if debug level is greater than zero.
65: *
66: * @param mixed $var Variable to show debug information for.
67: * @param bool $showHtml If set to true, the method prints the debug data in a browser-friendly way.
68: * @param bool $showFrom If set to true, the method prints from where the function was called.
69: * @return void
70: * @link http://book.cakephp.org/2.0/en/development/debugging.html#basic-debugging
71: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#debug
72: */
73: function debug($var, $showHtml = null, $showFrom = true) {
74: if (!Configure::read('debug')) {
75: return;
76: }
77: App::uses('Debugger', 'Utility');
78:
79: $file = '';
80: $line = '';
81: $lineInfo = '';
82: if ($showFrom) {
83: $trace = Debugger::trace(array('start' => 1, 'depth' => 2, 'format' => 'array'));
84: $file = str_replace(array(CAKE_CORE_INCLUDE_PATH, ROOT), '', $trace[0]['file']);
85: $line = $trace[0]['line'];
86: }
87: $html = <<<HTML
88: <div class="cake-debug-output">
89: %s
90: <pre class="cake-debug">
91: %s
92: </pre>
93: </div>
94: HTML;
95: $text = <<<TEXT
96: %s
97: ########## DEBUG ##########
98: %s
99: ###########################
100:
101: TEXT;
102: $template = $html;
103: if (php_sapi_name() === 'cli' || $showHtml === false) {
104: $template = $text;
105: if ($showFrom) {
106: $lineInfo = sprintf('%s (line %s)', $file, $line);
107: }
108: }
109: if ($showHtml === null && $template !== $text) {
110: $showHtml = true;
111: }
112: $var = Debugger::exportVar($var, 25);
113: if ($showHtml) {
114: $template = $html;
115: $var = h($var);
116: if ($showFrom) {
117: $lineInfo = sprintf('<span><strong>%s</strong> (line <strong>%s</strong>)</span>', $file, $line);
118: }
119: }
120: printf($template, $lineInfo, $var);
121: }
122:
123: }
124:
125: if (!function_exists('stackTrace')) {
126:
127: /**
128: * Outputs a stack trace based on the supplied options.
129: *
130: * ### Options
131: *
132: * - `depth` - The number of stack frames to return. Defaults to 999
133: * - `args` - Should arguments for functions be shown? If true, the arguments for each method call
134: * will be displayed.
135: * - `start` - The stack frame to start generating a trace from. Defaults to 1
136: *
137: * @param array $options Format for outputting stack trace
138: * @return mixed Formatted stack trace
139: * @see Debugger::trace()
140: */
141: function stackTrace(array $options = array()) {
142: if (!Configure::read('debug')) {
143: return;
144: }
145: App::uses('Debugger', 'Utility');
146:
147: $options += array('start' => 0);
148: $options['start']++;
149: echo Debugger::trace($options);
150: }
151:
152: }
153:
154: if (!function_exists('sortByKey')) {
155:
156: /**
157: * Sorts given $array by key $sortBy.
158: *
159: * @param array &$array Array to sort
160: * @param string $sortBy Sort by this key
161: * @param string $order Sort order asc/desc (ascending or descending).
162: * @param int $type Type of sorting to perform
163: * @return array|null Sorted array, or null if not an array.
164: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#sortByKey
165: */
166: function sortByKey(&$array, $sortBy, $order = 'asc', $type = SORT_NUMERIC) {
167: if (!is_array($array)) {
168: return null;
169: }
170:
171: foreach ($array as $key => $val) {
172: $sa[$key] = $val[$sortBy];
173: }
174:
175: if ($order === 'asc') {
176: asort($sa, $type);
177: } else {
178: arsort($sa, $type);
179: }
180:
181: foreach ($sa as $key => $val) {
182: $out[] = $array[$key];
183: }
184: return $out;
185: }
186:
187: }
188:
189: if (!function_exists('h')) {
190:
191: /**
192: * Convenience method for htmlspecialchars.
193: *
194: * @param string|array|object $text Text to wrap through htmlspecialchars. Also works with arrays, and objects.
195: * Arrays will be mapped and have all their elements escaped. Objects will be string cast if they
196: * implement a `__toString` method. Otherwise the class name will be used.
197: * @param bool $double Encode existing html entities
198: * @param string $charset Character set to use when escaping. Defaults to config value in 'App.encoding' or 'UTF-8'
199: * @return string Wrapped text
200: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#h
201: */
202: function h($text, $double = true, $charset = null) {
203: if (is_string($text)) {
204: //optimize for strings
205: } elseif (is_array($text)) {
206: $texts = array();
207: foreach ($text as $k => $t) {
208: $texts[$k] = h($t, $double, $charset);
209: }
210: return $texts;
211: } elseif (is_object($text)) {
212: if (method_exists($text, '__toString')) {
213: $text = (string)$text;
214: } else {
215: $text = '(object)' . get_class($text);
216: }
217: } elseif (is_bool($text)) {
218: return $text;
219: }
220:
221: static $defaultCharset = false;
222: if ($defaultCharset === false) {
223: $defaultCharset = Configure::read('App.encoding');
224: if ($defaultCharset === null) {
225: $defaultCharset = 'UTF-8';
226: }
227: }
228: if (is_string($double)) {
229: $charset = $double;
230: }
231: return htmlspecialchars($text, ENT_QUOTES, ($charset) ? $charset : $defaultCharset, $double);
232: }
233:
234: }
235:
236: if (!function_exists('pluginSplit')) {
237:
238: /**
239: * Splits a dot syntax plugin name into its plugin and class name.
240: * If $name does not have a dot, then index 0 will be null.
241: *
242: * Commonly used like `list($plugin, $name) = pluginSplit($name);`
243: *
244: * @param string $name The name you want to plugin split.
245: * @param bool $dotAppend Set to true if you want the plugin to have a '.' appended to it.
246: * @param string $plugin Optional default plugin to use if no plugin is found. Defaults to null.
247: * @return array Array with 2 indexes. 0 => plugin name, 1 => class name
248: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pluginSplit
249: */
250: function pluginSplit($name, $dotAppend = false, $plugin = null) {
251: if (strpos($name, '.') !== false) {
252: $parts = explode('.', $name, 2);
253: if ($dotAppend) {
254: $parts[0] .= '.';
255: }
256: return $parts;
257: }
258: return array($plugin, $name);
259: }
260:
261: }
262:
263: if (!function_exists('pr')) {
264:
265: /**
266: * print_r() convenience function
267: *
268: * In terminals this will act the same as using print_r() directly, when not run on cli
269: * print_r() will wrap <PRE> tags around the output of given array. Similar to debug().
270: *
271: * @param mixed $var Variable to print out
272: * @return void
273: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pr
274: * @see debug()
275: */
276: function pr($var) {
277: if (Configure::read('debug') > 0) {
278: $template = php_sapi_name() !== 'cli' ? '<pre>%s</pre>' : "\n%s\n";
279: printf($template, print_r($var, true));
280: }
281: }
282:
283: }
284:
285: if (!function_exists('am')) {
286:
287: /**
288: * Merge a group of arrays
289: *
290: * Accepts variable arguments. Each argument will be converted into an array and then merged.
291: *
292: * @return array All array parameters merged into one
293: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#am
294: */
295: function am() {
296: $r = array();
297: $args = func_get_args();
298: foreach ($args as $a) {
299: if (!is_array($a)) {
300: $a = array($a);
301: }
302: $r = array_merge($r, $a);
303: }
304: return $r;
305: }
306:
307: }
308:
309: if (!function_exists('env')) {
310:
311: /**
312: * Gets an environment variable from available sources, and provides emulation
313: * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
314: * IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
315: * environment information.
316: *
317: * @param string $key Environment variable name.
318: * @return string|bool|null Environment variable setting.
319: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#env
320: */
321: function env($key) {
322: if ($key === 'HTTPS') {
323: if (isset($_SERVER['HTTPS'])) {
324: return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
325: }
326: return (strpos(env('SCRIPT_URI'), 'https://') === 0);
327: }
328:
329: if ($key === 'SCRIPT_NAME') {
330: if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
331: $key = 'SCRIPT_URL';
332: }
333: }
334:
335: $val = null;
336: if (isset($_SERVER[$key])) {
337: $val = $_SERVER[$key];
338: } elseif (isset($_ENV[$key])) {
339: $val = $_ENV[$key];
340: } elseif (getenv($key) !== false) {
341: $val = getenv($key);
342: }
343:
344: if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) {
345: $addr = env('HTTP_PC_REMOTE_ADDR');
346: if ($addr !== null) {
347: $val = $addr;
348: }
349: }
350:
351: if ($val !== null) {
352: return $val;
353: }
354:
355: switch ($key) {
356: case 'DOCUMENT_ROOT':
357: $name = env('SCRIPT_NAME');
358: $filename = env('SCRIPT_FILENAME');
359: $offset = 0;
360: if (!strpos($name, '.php')) {
361: $offset = 4;
362: }
363: return substr($filename, 0, -(strlen($name) + $offset));
364: case 'PHP_SELF':
365: return str_replace(env('DOCUMENT_ROOT'), '', env('SCRIPT_FILENAME'));
366: case 'CGI_MODE':
367: return (PHP_SAPI === 'cgi');
368: case 'HTTP_BASE':
369: $host = env('HTTP_HOST');
370: $parts = explode('.', $host);
371: $count = count($parts);
372:
373: if ($count === 1) {
374: return '.' . $host;
375: } elseif ($count === 2) {
376: return '.' . $host;
377: } elseif ($count === 3) {
378: $gTLD = array(
379: 'aero',
380: 'asia',
381: 'biz',
382: 'cat',
383: 'com',
384: 'coop',
385: 'edu',
386: 'gov',
387: 'info',
388: 'int',
389: 'jobs',
390: 'mil',
391: 'mobi',
392: 'museum',
393: 'name',
394: 'net',
395: 'org',
396: 'pro',
397: 'tel',
398: 'travel',
399: 'xxx'
400: );
401: if (in_array($parts[1], $gTLD)) {
402: return '.' . $host;
403: }
404: }
405: array_shift($parts);
406: return '.' . implode('.', $parts);
407: }
408: return null;
409: }
410:
411: }
412:
413: if (!function_exists('cache')) {
414:
415: /**
416: * Reads/writes temporary data to cache files or session.
417: *
418: * @param string $path File path within /tmp to save the file.
419: * @param mixed $data The data to save to the temporary file.
420: * @param mixed $expires A valid strtotime string when the data expires.
421: * @param string $target The target of the cached data; either 'cache' or 'public'.
422: * @return mixed The contents of the temporary file.
423: * @deprecated 3.0.0 Will be removed in 3.0. Please use Cache::write() instead.
424: */
425: function cache($path, $data = null, $expires = '+1 day', $target = 'cache') {
426: if (Configure::read('Cache.disable')) {
427: return null;
428: }
429: $now = time();
430:
431: if (!is_numeric($expires)) {
432: $expires = strtotime($expires, $now);
433: }
434:
435: switch (strtolower($target)) {
436: case 'cache':
437: $filename = CACHE . $path;
438: break;
439: case 'public':
440: $filename = WWW_ROOT . $path;
441: break;
442: case 'tmp':
443: $filename = TMP . $path;
444: break;
445: }
446: $timediff = $expires - $now;
447: $filetime = false;
448:
449: if (file_exists($filename)) {
450: //@codingStandardsIgnoreStart
451: $filetime = @filemtime($filename);
452: //@codingStandardsIgnoreEnd
453: }
454:
455: if ($data === null) {
456: if (file_exists($filename) && $filetime !== false) {
457: if ($filetime + $timediff < $now) {
458: //@codingStandardsIgnoreStart
459: @unlink($filename);
460: //@codingStandardsIgnoreEnd
461: } else {
462: //@codingStandardsIgnoreStart
463: $data = @file_get_contents($filename);
464: //@codingStandardsIgnoreEnd
465: }
466: }
467: } elseif (is_writable(dirname($filename))) {
468: //@codingStandardsIgnoreStart
469: @file_put_contents($filename, $data, LOCK_EX);
470: //@codingStandardsIgnoreEnd
471: }
472: return $data;
473: }
474:
475: }
476:
477: if (!function_exists('clearCache')) {
478:
479: /**
480: * Used to delete files in the cache directories, or clear contents of cache directories
481: *
482: * @param string|array $params As String name to be searched for deletion, if name is a directory all files in
483: * directory will be deleted. If array, names to be searched for deletion. If clearCache() without params,
484: * all files in app/tmp/cache/views will be deleted
485: * @param string $type Directory in tmp/cache defaults to view directory
486: * @param string $ext The file extension you are deleting
487: * @return true if files found and deleted false otherwise
488: */
489: function clearCache($params = null, $type = 'views', $ext = '.php') {
490: if (is_string($params) || $params === null) {
491: $params = preg_replace('/\/\//', '/', $params);
492: $cache = CACHE . $type . DS . $params;
493:
494: if (is_file($cache . $ext)) {
495: //@codingStandardsIgnoreStart
496: @unlink($cache . $ext);
497: //@codingStandardsIgnoreEnd
498: return true;
499: } elseif (is_dir($cache)) {
500: $files = glob($cache . '*');
501:
502: if ($files === false) {
503: return false;
504: }
505:
506: foreach ($files as $file) {
507: if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
508: //@codingStandardsIgnoreStart
509: @unlink($file);
510: //@codingStandardsIgnoreEnd
511: }
512: }
513: return true;
514: }
515: $cache = array(
516: CACHE . $type . DS . '*' . $params . $ext,
517: CACHE . $type . DS . '*' . $params . '_*' . $ext
518: );
519: $files = array();
520: while ($search = array_shift($cache)) {
521: $results = glob($search);
522: if ($results !== false) {
523: $files = array_merge($files, $results);
524: }
525: }
526: if (empty($files)) {
527: return false;
528: }
529: foreach ($files as $file) {
530: if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
531: //@codingStandardsIgnoreStart
532: @unlink($file);
533: //@codingStandardsIgnoreEnd
534: }
535: }
536: return true;
537:
538: } elseif (is_array($params)) {
539: foreach ($params as $file) {
540: clearCache($file, $type, $ext);
541: }
542: return true;
543: }
544: return false;
545: }
546:
547: }
548:
549: if (!function_exists('stripslashes_deep')) {
550:
551: /**
552: * Recursively strips slashes from all values in an array
553: *
554: * @param array $values Array of values to strip slashes
555: * @return mixed What is returned from calling stripslashes
556: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#stripslashes_deep
557: */
558: function stripslashes_deep($values) {
559: if (is_array($values)) {
560: foreach ($values as $key => $value) {
561: $values[$key] = stripslashes_deep($value);
562: }
563: } else {
564: $values = stripslashes($values);
565: }
566: return $values;
567: }
568:
569: }
570:
571: if (!function_exists('__')) {
572:
573: /**
574: * Returns a translated string if one is found; Otherwise, the submitted message.
575: *
576: * @param string $singular Text to translate
577: * @param mixed $args Array with arguments or multiple arguments in function
578: * @return mixed translated string
579: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__
580: */
581: function __($singular, $args = null) {
582: if (!$singular) {
583: return;
584: }
585:
586: App::uses('I18n', 'I18n');
587: $translated = I18n::translate($singular);
588: $arguments = func_get_args();
589: return I18n::insertArgs($translated, array_slice($arguments, 1));
590: }
591:
592: }
593:
594: if (!function_exists('__n')) {
595:
596: /**
597: * Returns correct plural form of message identified by $singular and $plural for count $count.
598: * Some languages have more than one form for plural messages dependent on the count.
599: *
600: * @param string $singular Singular text to translate
601: * @param string $plural Plural text
602: * @param int $count Count
603: * @param mixed $args Array with arguments or multiple arguments in function
604: * @return mixed plural form of translated string
605: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__n
606: */
607: function __n($singular, $plural, $count, $args = null) {
608: if (!$singular) {
609: return;
610: }
611:
612: App::uses('I18n', 'I18n');
613: $translated = I18n::translate($singular, $plural, null, I18n::LC_MESSAGES, $count);
614: $arguments = func_get_args();
615: return I18n::insertArgs($translated, array_slice($arguments, 3));
616: }
617:
618: }
619:
620: if (!function_exists('__d')) {
621:
622: /**
623: * Allows you to override the current domain for a single message lookup.
624: *
625: * @param string $domain Domain
626: * @param string $msg String to translate
627: * @param mixed $args Array with arguments or multiple arguments in function
628: * @return string translated string
629: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__d
630: */
631: function __d($domain, $msg, $args = null) {
632: if (!$msg) {
633: return;
634: }
635: App::uses('I18n', 'I18n');
636: $translated = I18n::translate($msg, null, $domain);
637: $arguments = func_get_args();
638: return I18n::insertArgs($translated, array_slice($arguments, 2));
639: }
640:
641: }
642:
643: if (!function_exists('__dn')) {
644:
645: /**
646: * Allows you to override the current domain for a single plural message lookup.
647: * Returns correct plural form of message identified by $singular and $plural for count $count
648: * from domain $domain.
649: *
650: * @param string $domain Domain
651: * @param string $singular Singular string to translate
652: * @param string $plural Plural
653: * @param int $count Count
654: * @param mixed $args Array with arguments or multiple arguments in function
655: * @return string plural form of translated string
656: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dn
657: */
658: function __dn($domain, $singular, $plural, $count, $args = null) {
659: if (!$singular) {
660: return;
661: }
662: App::uses('I18n', 'I18n');
663: $translated = I18n::translate($singular, $plural, $domain, I18n::LC_MESSAGES, $count);
664: $arguments = func_get_args();
665: return I18n::insertArgs($translated, array_slice($arguments, 4));
666: }
667:
668: }
669:
670: if (!function_exists('__dc')) {
671:
672: /**
673: * Allows you to override the current domain for a single message lookup.
674: * It also allows you to specify a category.
675: *
676: * The category argument allows a specific category of the locale settings to be used for fetching a message.
677: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
678: *
679: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
680: *
681: * - LC_ALL I18n::LC_ALL
682: * - LC_COLLATE I18n::LC_COLLATE
683: * - LC_CTYPE I18n::LC_CTYPE
684: * - LC_MONETARY I18n::LC_MONETARY
685: * - LC_NUMERIC I18n::LC_NUMERIC
686: * - LC_TIME I18n::LC_TIME
687: * - LC_MESSAGES I18n::LC_MESSAGES
688: *
689: * @param string $domain Domain
690: * @param string $msg Message to translate
691: * @param int $category Category
692: * @param mixed $args Array with arguments or multiple arguments in function
693: * @return string translated string
694: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dc
695: */
696: function __dc($domain, $msg, $category, $args = null) {
697: if (!$msg) {
698: return;
699: }
700: App::uses('I18n', 'I18n');
701: $translated = I18n::translate($msg, null, $domain, $category);
702: $arguments = func_get_args();
703: return I18n::insertArgs($translated, array_slice($arguments, 3));
704: }
705:
706: }
707:
708: if (!function_exists('__dcn')) {
709:
710: /**
711: * Allows you to override the current domain for a single plural message lookup.
712: * It also allows you to specify a category.
713: * Returns correct plural form of message identified by $singular and $plural for count $count
714: * from domain $domain.
715: *
716: * The category argument allows a specific category of the locale settings to be used for fetching a message.
717: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
718: *
719: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
720: *
721: * - LC_ALL I18n::LC_ALL
722: * - LC_COLLATE I18n::LC_COLLATE
723: * - LC_CTYPE I18n::LC_CTYPE
724: * - LC_MONETARY I18n::LC_MONETARY
725: * - LC_NUMERIC I18n::LC_NUMERIC
726: * - LC_TIME I18n::LC_TIME
727: * - LC_MESSAGES I18n::LC_MESSAGES
728: *
729: * @param string $domain Domain
730: * @param string $singular Singular string to translate
731: * @param string $plural Plural
732: * @param int $count Count
733: * @param int $category Category
734: * @param mixed $args Array with arguments or multiple arguments in function
735: * @return string plural form of translated string
736: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dcn
737: */
738: function __dcn($domain, $singular, $plural, $count, $category, $args = null) {
739: if (!$singular) {
740: return;
741: }
742: App::uses('I18n', 'I18n');
743: $translated = I18n::translate($singular, $plural, $domain, $category, $count);
744: $arguments = func_get_args();
745: return I18n::insertArgs($translated, array_slice($arguments, 5));
746: }
747:
748: }
749:
750: if (!function_exists('__c')) {
751:
752: /**
753: * The category argument allows a specific category of the locale settings to be used for fetching a message.
754: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
755: *
756: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
757: *
758: * - LC_ALL I18n::LC_ALL
759: * - LC_COLLATE I18n::LC_COLLATE
760: * - LC_CTYPE I18n::LC_CTYPE
761: * - LC_MONETARY I18n::LC_MONETARY
762: * - LC_NUMERIC I18n::LC_NUMERIC
763: * - LC_TIME I18n::LC_TIME
764: * - LC_MESSAGES I18n::LC_MESSAGES
765: *
766: * @param string $msg String to translate
767: * @param int $category Category
768: * @param mixed $args Array with arguments or multiple arguments in function
769: * @return string translated string
770: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__c
771: */
772: function __c($msg, $category, $args = null) {
773: if (!$msg) {
774: return;
775: }
776: App::uses('I18n', 'I18n');
777: $translated = I18n::translate($msg, null, null, $category);
778: $arguments = func_get_args();
779: return I18n::insertArgs($translated, array_slice($arguments, 2));
780: }
781:
782: }
783:
784: if (!function_exists('__x')) {
785:
786: /**
787: * Returns a translated string if one is found; Otherwise, the submitted message.
788: *
789: * @param string $context Context of the text
790: * @param string $singular Text to translate
791: * @param mixed $args Array with arguments or multiple arguments in function
792: * @return mixed translated string
793: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__
794: */
795: function __x($context, $singular, $args = null) {
796: if (!$singular) {
797: return;
798: }
799:
800: App::uses('I18n', 'I18n');
801: $translated = I18n::translate($singular, null, null, null, null, null, $context);
802: $arguments = func_get_args();
803: return I18n::insertArgs($translated, array_slice($arguments, 2));
804: }
805:
806: }
807:
808: if (!function_exists('__xn')) {
809:
810: /**
811: * Returns correct plural form of message identified by $singular and $plural for count $count.
812: * Some languages have more than one form for plural messages dependent on the count.
813: *
814: * @param string $context Context of the text
815: * @param string $singular Singular text to translate
816: * @param string $plural Plural text
817: * @param int $count Count
818: * @param mixed $args Array with arguments or multiple arguments in function
819: * @return mixed plural form of translated string
820: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__n
821: */
822: function __xn($context, $singular, $plural, $count, $args = null) {
823: if (!$singular) {
824: return;
825: }
826:
827: App::uses('I18n', 'I18n');
828: $translated = I18n::translate($singular, $plural, null, I18n::LC_MESSAGES, $count, null, $context);
829: $arguments = func_get_args();
830: return I18n::insertArgs($translated, array_slice($arguments, 4));
831: }
832:
833: }
834:
835: if (!function_exists('__dx')) {
836:
837: /**
838: * Allows you to override the current domain for a single message lookup.
839: *
840: * @param string $domain Domain
841: * @param string $context Context of the text
842: * @param string $msg String to translate
843: * @param mixed $args Array with arguments or multiple arguments in function
844: * @return string translated string
845: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__d
846: */
847: function __dx($domain, $context, $msg, $args = null) {
848: if (!$msg) {
849: return;
850: }
851: App::uses('I18n', 'I18n');
852: $translated = I18n::translate($msg, null, $domain, null, null, null, $context);
853: $arguments = func_get_args();
854: return I18n::insertArgs($translated, array_slice($arguments, 3));
855: }
856:
857: }
858:
859: if (!function_exists('__dxn')) {
860:
861: /**
862: * Allows you to override the current domain for a single plural message lookup.
863: * Returns correct plural form of message identified by $singular and $plural for count $count
864: * from domain $domain.
865: *
866: * @param string $domain Domain
867: * @param string $context Context of the text
868: * @param string $singular Singular string to translate
869: * @param string $plural Plural
870: * @param int $count Count
871: * @param mixed $args Array with arguments or multiple arguments in function
872: * @return string plural form of translated string
873: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dn
874: */
875: function __dxn($domain, $context, $singular, $plural, $count, $args = null) {
876: if (!$singular) {
877: return;
878: }
879: App::uses('I18n', 'I18n');
880: $translated = I18n::translate($singular, $plural, $domain, I18n::LC_MESSAGES, $count, null, $context);
881: $arguments = func_get_args();
882: return I18n::insertArgs($translated, array_slice($arguments, 5));
883: }
884:
885: }
886:
887: if (!function_exists('__dxc')) {
888:
889: /**
890: * Allows you to override the current domain for a single message lookup.
891: * It also allows you to specify a category.
892: *
893: * The category argument allows a specific category of the locale settings to be used for fetching a message.
894: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
895: *
896: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
897: *
898: * - LC_ALL I18n::LC_ALL
899: * - LC_COLLATE I18n::LC_COLLATE
900: * - LC_CTYPE I18n::LC_CTYPE
901: * - LC_MONETARY I18n::LC_MONETARY
902: * - LC_NUMERIC I18n::LC_NUMERIC
903: * - LC_TIME I18n::LC_TIME
904: * - LC_MESSAGES I18n::LC_MESSAGES
905: *
906: * @param string $domain Domain
907: * @param string $context Context of the text
908: * @param string $msg Message to translate
909: * @param int $category Category
910: * @param mixed $args Array with arguments or multiple arguments in function
911: * @return string translated string
912: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dc
913: */
914: function __dxc($domain, $context, $msg, $category, $args = null) {
915: if (!$msg) {
916: return;
917: }
918: App::uses('I18n', 'I18n');
919: $translated = I18n::translate($msg, null, $domain, $category, null, null, $context);
920: $arguments = func_get_args();
921: return I18n::insertArgs($translated, array_slice($arguments, 4));
922: }
923:
924: }
925:
926: if (!function_exists('__dxcn')) {
927:
928: /**
929: * Allows you to override the current domain for a single plural message lookup.
930: * It also allows you to specify a category.
931: * Returns correct plural form of message identified by $singular and $plural for count $count
932: * from domain $domain.
933: *
934: * The category argument allows a specific category of the locale settings to be used for fetching a message.
935: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
936: *
937: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
938: *
939: * - LC_ALL I18n::LC_ALL
940: * - LC_COLLATE I18n::LC_COLLATE
941: * - LC_CTYPE I18n::LC_CTYPE
942: * - LC_MONETARY I18n::LC_MONETARY
943: * - LC_NUMERIC I18n::LC_NUMERIC
944: * - LC_TIME I18n::LC_TIME
945: * - LC_MESSAGES I18n::LC_MESSAGES
946: *
947: * @param string $domain Domain
948: * @param string $context Context of the text
949: * @param string $singular Singular string to translate
950: * @param string $plural Plural
951: * @param int $count Count
952: * @param int $category Category
953: * @param mixed $args Array with arguments or multiple arguments in function
954: * @return string plural form of translated string
955: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dcn
956: */
957: function __dxcn($domain, $context, $singular, $plural, $count, $category, $args = null) {
958: if (!$singular) {
959: return;
960: }
961: App::uses('I18n', 'I18n');
962: $translated = I18n::translate($singular, $plural, $domain, $category, $count, null, $context);
963: $arguments = func_get_args();
964: return I18n::insertArgs($translated, array_slice($arguments, 6));
965: }
966:
967: }
968:
969: if (!function_exists('__xc')) {
970:
971: /**
972: * The category argument allows a specific category of the locale settings to be used for fetching a message.
973: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
974: *
975: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
976: *
977: * - LC_ALL I18n::LC_ALL
978: * - LC_COLLATE I18n::LC_COLLATE
979: * - LC_CTYPE I18n::LC_CTYPE
980: * - LC_MONETARY I18n::LC_MONETARY
981: * - LC_NUMERIC I18n::LC_NUMERIC
982: * - LC_TIME I18n::LC_TIME
983: * - LC_MESSAGES I18n::LC_MESSAGES
984: *
985: * @param string $context Context of the text
986: * @param string $msg String to translate
987: * @param int $category Category
988: * @param mixed $args Array with arguments or multiple arguments in function
989: * @return string translated string
990: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__c
991: */
992: function __xc($context, $msg, $category, $args = null) {
993: if (!$msg) {
994: return;
995: }
996: App::uses('I18n', 'I18n');
997: $translated = I18n::translate($msg, null, null, $category, null, null, $context);
998: $arguments = func_get_args();
999: return I18n::insertArgs($translated, array_slice($arguments, 3));
1000: }
1001:
1002: }
1003:
1004: if (!function_exists('LogError')) {
1005:
1006: /**
1007: * Shortcut to Log::write.
1008: *
1009: * @param string $message Message to write to log
1010: * @return void
1011: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#LogError
1012: */
1013: function LogError($message) {
1014: App::uses('CakeLog', 'Log');
1015: $bad = array("\n", "\r", "\t");
1016: $good = ' ';
1017: CakeLog::write('error', str_replace($bad, $good, $message));
1018: }
1019:
1020: }
1021:
1022: if (!function_exists('fileExistsInPath')) {
1023:
1024: /**
1025: * Searches include path for files.
1026: *
1027: * @param string $file File to look for
1028: * @return string Full path to file if exists, otherwise false
1029: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#fileExistsInPath
1030: */
1031: function fileExistsInPath($file) {
1032: $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
1033: foreach ($paths as $path) {
1034: $fullPath = $path . DS . $file;
1035:
1036: if (file_exists($fullPath)) {
1037: return $fullPath;
1038: } elseif (file_exists($file)) {
1039: return $file;
1040: }
1041: }
1042: return false;
1043: }
1044:
1045: }
1046:
1047: if (!function_exists('convertSlash')) {
1048:
1049: /**
1050: * Convert forward slashes to underscores and removes first and last underscores in a string
1051: *
1052: * @param string $string String to convert
1053: * @return string with underscore remove from start and end of string
1054: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#convertSlash
1055: */
1056: function convertSlash($string) {
1057: $string = trim($string, '/');
1058: $string = preg_replace('/\/\//', '/', $string);
1059: $string = str_replace('/', '_', $string);
1060: return $string;
1061: }
1062:
1063: }
1064:
1065: if (!function_exists('json_last_error_msg')) {
1066:
1067: /**
1068: * Provides the fallback implementation of json_last_error_msg() available in PHP 5.5 and above.
1069: *
1070: * @return string Error message.
1071: */
1072: function json_last_error_msg() {
1073: static $errors = array(
1074: JSON_ERROR_NONE => '',
1075: JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
1076: JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
1077: JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
1078: JSON_ERROR_SYNTAX => 'Syntax error',
1079: JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
1080: );
1081: $error = json_last_error();
1082: return array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})";
1083: }
1084:
1085: }
1086: