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') > 0) {
75: App::uses('Debugger', 'Utility');
76: $file = '';
77: $line = '';
78: $lineInfo = '';
79: if ($showFrom) {
80: $trace = Debugger::trace(array('start' => 1, 'depth' => 2, 'format' => 'array'));
81: $file = str_replace(array(CAKE_CORE_INCLUDE_PATH, ROOT), '', $trace[0]['file']);
82: $line = $trace[0]['line'];
83: }
84: $html = <<<HTML
85: <div class="cake-debug-output">
86: %s
87: <pre class="cake-debug">
88: %s
89: </pre>
90: </div>
91: HTML;
92: $text = <<<TEXT
93: %s
94: ########## DEBUG ##########
95: %s
96: ###########################
97:
98: TEXT;
99: $template = $html;
100: if (php_sapi_name() === 'cli' || $showHtml === false) {
101: $template = $text;
102: if ($showFrom) {
103: $lineInfo = sprintf('%s (line %s)', $file, $line);
104: }
105: }
106: if ($showHtml === null && $template !== $text) {
107: $showHtml = true;
108: }
109: $var = Debugger::exportVar($var, 25);
110: if ($showHtml) {
111: $template = $html;
112: $var = h($var);
113: if ($showFrom) {
114: $lineInfo = sprintf('<span><strong>%s</strong> (line <strong>%s</strong>)</span>', $file, $line);
115: }
116: }
117: printf($template, $lineInfo, $var);
118: }
119: }
120:
121: }
122:
123: if (!function_exists('sortByKey')) {
124:
125: /**
126: * Sorts given $array by key $sortBy.
127: *
128: * @param array &$array Array to sort
129: * @param string $sortBy Sort by this key
130: * @param string $order Sort order asc/desc (ascending or descending).
131: * @param int $type Type of sorting to perform
132: * @return array|null Sorted array, or null if not an array.
133: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#sortByKey
134: */
135: function sortByKey(&$array, $sortBy, $order = 'asc', $type = SORT_NUMERIC) {
136: if (!is_array($array)) {
137: return null;
138: }
139:
140: foreach ($array as $key => $val) {
141: $sa[$key] = $val[$sortBy];
142: }
143:
144: if ($order === 'asc') {
145: asort($sa, $type);
146: } else {
147: arsort($sa, $type);
148: }
149:
150: foreach ($sa as $key => $val) {
151: $out[] = $array[$key];
152: }
153: return $out;
154: }
155:
156: }
157:
158: if (!function_exists('h')) {
159:
160: /**
161: * Convenience method for htmlspecialchars.
162: *
163: * @param string|array|object $text Text to wrap through htmlspecialchars. Also works with arrays, and objects.
164: * Arrays will be mapped and have all their elements escaped. Objects will be string cast if they
165: * implement a `__toString` method. Otherwise the class name will be used.
166: * @param bool $double Encode existing html entities
167: * @param string $charset Character set to use when escaping. Defaults to config value in 'App.encoding' or 'UTF-8'
168: * @return string Wrapped text
169: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#h
170: */
171: function h($text, $double = true, $charset = null) {
172: if (is_string($text)) {
173: //optimize for strings
174: } elseif (is_array($text)) {
175: $texts = array();
176: foreach ($text as $k => $t) {
177: $texts[$k] = h($t, $double, $charset);
178: }
179: return $texts;
180: } elseif (is_object($text)) {
181: if (method_exists($text, '__toString')) {
182: $text = (string)$text;
183: } else {
184: $text = '(object)' . get_class($text);
185: }
186: } elseif (is_bool($text)) {
187: return $text;
188: }
189:
190: static $defaultCharset = false;
191: if ($defaultCharset === false) {
192: $defaultCharset = Configure::read('App.encoding');
193: if ($defaultCharset === null) {
194: $defaultCharset = 'UTF-8';
195: }
196: }
197: if (is_string($double)) {
198: $charset = $double;
199: }
200: return htmlspecialchars($text, ENT_QUOTES, ($charset) ? $charset : $defaultCharset, $double);
201: }
202:
203: }
204:
205: if (!function_exists('pluginSplit')) {
206:
207: /**
208: * Splits a dot syntax plugin name into its plugin and class name.
209: * If $name does not have a dot, then index 0 will be null.
210: *
211: * Commonly used like `list($plugin, $name) = pluginSplit($name);`
212: *
213: * @param string $name The name you want to plugin split.
214: * @param bool $dotAppend Set to true if you want the plugin to have a '.' appended to it.
215: * @param string $plugin Optional default plugin to use if no plugin is found. Defaults to null.
216: * @return array Array with 2 indexes. 0 => plugin name, 1 => class name
217: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pluginSplit
218: */
219: function pluginSplit($name, $dotAppend = false, $plugin = null) {
220: if (strpos($name, '.') !== false) {
221: $parts = explode('.', $name, 2);
222: if ($dotAppend) {
223: $parts[0] .= '.';
224: }
225: return $parts;
226: }
227: return array($plugin, $name);
228: }
229:
230: }
231:
232: if (!function_exists('pr')) {
233:
234: /**
235: * print_r() convenience function
236: *
237: * In terminals this will act the same as using print_r() directly, when not run on cli
238: * print_r() will wrap <PRE> tags around the output of given array. Similar to debug().
239: *
240: * @param mixed $var Variable to print out
241: * @return void
242: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pr
243: * @see debug()
244: */
245: function pr($var) {
246: if (Configure::read('debug') > 0) {
247: $template = php_sapi_name() !== 'cli' ? '<pre>%s</pre>' : "\n%s\n";
248: printf($template, print_r($var, true));
249: }
250: }
251:
252: }
253:
254: if (!function_exists('am')) {
255:
256: /**
257: * Merge a group of arrays
258: *
259: * Accepts variable arguments. Each argument will be converted into an array and then merged.
260: *
261: * @return array All array parameters merged into one
262: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#am
263: */
264: function am() {
265: $r = array();
266: $args = func_get_args();
267: foreach ($args as $a) {
268: if (!is_array($a)) {
269: $a = array($a);
270: }
271: $r = array_merge($r, $a);
272: }
273: return $r;
274: }
275:
276: }
277:
278: if (!function_exists('env')) {
279:
280: /**
281: * Gets an environment variable from available sources, and provides emulation
282: * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
283: * IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
284: * environment information.
285: *
286: * @param string $key Environment variable name.
287: * @return string|bool|null Environment variable setting.
288: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#env
289: */
290: function env($key) {
291: if ($key === 'HTTPS') {
292: if (isset($_SERVER['HTTPS'])) {
293: return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
294: }
295: return (strpos(env('SCRIPT_URI'), 'https://') === 0);
296: }
297:
298: if ($key === 'SCRIPT_NAME') {
299: if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
300: $key = 'SCRIPT_URL';
301: }
302: }
303:
304: $val = null;
305: if (isset($_SERVER[$key])) {
306: $val = $_SERVER[$key];
307: } elseif (isset($_ENV[$key])) {
308: $val = $_ENV[$key];
309: } elseif (getenv($key) !== false) {
310: $val = getenv($key);
311: }
312:
313: if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) {
314: $addr = env('HTTP_PC_REMOTE_ADDR');
315: if ($addr !== null) {
316: $val = $addr;
317: }
318: }
319:
320: if ($val !== null) {
321: return $val;
322: }
323:
324: switch ($key) {
325: case 'DOCUMENT_ROOT':
326: $name = env('SCRIPT_NAME');
327: $filename = env('SCRIPT_FILENAME');
328: $offset = 0;
329: if (!strpos($name, '.php')) {
330: $offset = 4;
331: }
332: return substr($filename, 0, -(strlen($name) + $offset));
333: case 'PHP_SELF':
334: return str_replace(env('DOCUMENT_ROOT'), '', env('SCRIPT_FILENAME'));
335: case 'CGI_MODE':
336: return (PHP_SAPI === 'cgi');
337: case 'HTTP_BASE':
338: $host = env('HTTP_HOST');
339: $parts = explode('.', $host);
340: $count = count($parts);
341:
342: if ($count === 1) {
343: return '.' . $host;
344: } elseif ($count === 2) {
345: return '.' . $host;
346: } elseif ($count === 3) {
347: $gTLD = array(
348: 'aero',
349: 'asia',
350: 'biz',
351: 'cat',
352: 'com',
353: 'coop',
354: 'edu',
355: 'gov',
356: 'info',
357: 'int',
358: 'jobs',
359: 'mil',
360: 'mobi',
361: 'museum',
362: 'name',
363: 'net',
364: 'org',
365: 'pro',
366: 'tel',
367: 'travel',
368: 'xxx'
369: );
370: if (in_array($parts[1], $gTLD)) {
371: return '.' . $host;
372: }
373: }
374: array_shift($parts);
375: return '.' . implode('.', $parts);
376: }
377: return null;
378: }
379:
380: }
381:
382: if (!function_exists('cache')) {
383:
384: /**
385: * Reads/writes temporary data to cache files or session.
386: *
387: * @param string $path File path within /tmp to save the file.
388: * @param mixed $data The data to save to the temporary file.
389: * @param mixed $expires A valid strtotime string when the data expires.
390: * @param string $target The target of the cached data; either 'cache' or 'public'.
391: * @return mixed The contents of the temporary file.
392: * @deprecated 3.0.0 Will be removed in 3.0. Please use Cache::write() instead.
393: */
394: function cache($path, $data = null, $expires = '+1 day', $target = 'cache') {
395: if (Configure::read('Cache.disable')) {
396: return null;
397: }
398: $now = time();
399:
400: if (!is_numeric($expires)) {
401: $expires = strtotime($expires, $now);
402: }
403:
404: switch (strtolower($target)) {
405: case 'cache':
406: $filename = CACHE . $path;
407: break;
408: case 'public':
409: $filename = WWW_ROOT . $path;
410: break;
411: case 'tmp':
412: $filename = TMP . $path;
413: break;
414: }
415: $timediff = $expires - $now;
416: $filetime = false;
417:
418: if (file_exists($filename)) {
419: //@codingStandardsIgnoreStart
420: $filetime = @filemtime($filename);
421: //@codingStandardsIgnoreEnd
422: }
423:
424: if ($data === null) {
425: if (file_exists($filename) && $filetime !== false) {
426: if ($filetime + $timediff < $now) {
427: //@codingStandardsIgnoreStart
428: @unlink($filename);
429: //@codingStandardsIgnoreEnd
430: } else {
431: //@codingStandardsIgnoreStart
432: $data = @file_get_contents($filename);
433: //@codingStandardsIgnoreEnd
434: }
435: }
436: } elseif (is_writable(dirname($filename))) {
437: //@codingStandardsIgnoreStart
438: @file_put_contents($filename, $data, LOCK_EX);
439: //@codingStandardsIgnoreEnd
440: }
441: return $data;
442: }
443:
444: }
445:
446: if (!function_exists('clearCache')) {
447:
448: /**
449: * Used to delete files in the cache directories, or clear contents of cache directories
450: *
451: * @param string|array $params As String name to be searched for deletion, if name is a directory all files in
452: * directory will be deleted. If array, names to be searched for deletion. If clearCache() without params,
453: * all files in app/tmp/cache/views will be deleted
454: * @param string $type Directory in tmp/cache defaults to view directory
455: * @param string $ext The file extension you are deleting
456: * @return true if files found and deleted false otherwise
457: */
458: function clearCache($params = null, $type = 'views', $ext = '.php') {
459: if (is_string($params) || $params === null) {
460: $params = preg_replace('/\/\//', '/', $params);
461: $cache = CACHE . $type . DS . $params;
462:
463: if (is_file($cache . $ext)) {
464: //@codingStandardsIgnoreStart
465: @unlink($cache . $ext);
466: //@codingStandardsIgnoreEnd
467: return true;
468: } elseif (is_dir($cache)) {
469: $files = glob($cache . '*');
470:
471: if ($files === false) {
472: return false;
473: }
474:
475: foreach ($files as $file) {
476: if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
477: //@codingStandardsIgnoreStart
478: @unlink($file);
479: //@codingStandardsIgnoreEnd
480: }
481: }
482: return true;
483: }
484: $cache = array(
485: CACHE . $type . DS . '*' . $params . $ext,
486: CACHE . $type . DS . '*' . $params . '_*' . $ext
487: );
488: $files = array();
489: while ($search = array_shift($cache)) {
490: $results = glob($search);
491: if ($results !== false) {
492: $files = array_merge($files, $results);
493: }
494: }
495: if (empty($files)) {
496: return false;
497: }
498: foreach ($files as $file) {
499: if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
500: //@codingStandardsIgnoreStart
501: @unlink($file);
502: //@codingStandardsIgnoreEnd
503: }
504: }
505: return true;
506:
507: } elseif (is_array($params)) {
508: foreach ($params as $file) {
509: clearCache($file, $type, $ext);
510: }
511: return true;
512: }
513: return false;
514: }
515:
516: }
517:
518: if (!function_exists('stripslashes_deep')) {
519:
520: /**
521: * Recursively strips slashes from all values in an array
522: *
523: * @param array $values Array of values to strip slashes
524: * @return mixed What is returned from calling stripslashes
525: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#stripslashes_deep
526: */
527: function stripslashes_deep($values) {
528: if (is_array($values)) {
529: foreach ($values as $key => $value) {
530: $values[$key] = stripslashes_deep($value);
531: }
532: } else {
533: $values = stripslashes($values);
534: }
535: return $values;
536: }
537:
538: }
539:
540: if (!function_exists('__')) {
541:
542: /**
543: * Returns a translated string if one is found; Otherwise, the submitted message.
544: *
545: * @param string $singular Text to translate
546: * @param mixed $args Array with arguments or multiple arguments in function
547: * @return mixed translated string
548: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__
549: */
550: function __($singular, $args = null) {
551: if (!$singular) {
552: return;
553: }
554:
555: App::uses('I18n', 'I18n');
556: $translated = I18n::translate($singular);
557: if ($args === null && func_num_args() < 3) {
558: return $translated;
559: } elseif (!is_array($args)) {
560: $args = array_slice(func_get_args(), 1);
561: }
562:
563: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
564: return vsprintf($translated, $args);
565: }
566:
567: }
568:
569: if (!function_exists('__n')) {
570:
571: /**
572: * Returns correct plural form of message identified by $singular and $plural for count $count.
573: * Some languages have more than one form for plural messages dependent on the count.
574: *
575: * @param string $singular Singular text to translate
576: * @param string $plural Plural text
577: * @param int $count Count
578: * @param mixed $args Array with arguments or multiple arguments in function
579: * @return mixed plural form of translated string
580: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__n
581: */
582: function __n($singular, $plural, $count, $args = null) {
583: if (!$singular) {
584: return;
585: }
586:
587: App::uses('I18n', 'I18n');
588: $translated = I18n::translate($singular, $plural, null, I18n::LC_MESSAGES, $count);
589: if ($args === null && func_num_args() < 5) {
590: return $translated;
591: } elseif (!is_array($args)) {
592: $args = array_slice(func_get_args(), 3);
593: }
594:
595: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
596: return vsprintf($translated, $args);
597: }
598:
599: }
600:
601: if (!function_exists('__d')) {
602:
603: /**
604: * Allows you to override the current domain for a single message lookup.
605: *
606: * @param string $domain Domain
607: * @param string $msg String to translate
608: * @param mixed $args Array with arguments or multiple arguments in function
609: * @return translated string
610: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__d
611: */
612: function __d($domain, $msg, $args = null) {
613: if (!$msg) {
614: return;
615: }
616: App::uses('I18n', 'I18n');
617: $translated = I18n::translate($msg, null, $domain);
618: if ($args === null && func_num_args() < 4) {
619: return $translated;
620: } elseif (!is_array($args)) {
621: $args = array_slice(func_get_args(), 2);
622: }
623:
624: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
625: return vsprintf($translated, $args);
626: }
627:
628: }
629:
630: if (!function_exists('__dn')) {
631:
632: /**
633: * Allows you to override the current domain for a single plural message lookup.
634: * Returns correct plural form of message identified by $singular and $plural for count $count
635: * from domain $domain.
636: *
637: * @param string $domain Domain
638: * @param string $singular Singular string to translate
639: * @param string $plural Plural
640: * @param int $count Count
641: * @param mixed $args Array with arguments or multiple arguments in function
642: * @return plural form of translated string
643: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dn
644: */
645: function __dn($domain, $singular, $plural, $count, $args = null) {
646: if (!$singular) {
647: return;
648: }
649: App::uses('I18n', 'I18n');
650: $translated = I18n::translate($singular, $plural, $domain, I18n::LC_MESSAGES, $count);
651: if ($args === null && func_num_args() < 6) {
652: return $translated;
653: } elseif (!is_array($args)) {
654: $args = array_slice(func_get_args(), 4);
655: }
656:
657: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
658: return vsprintf($translated, $args);
659: }
660:
661: }
662:
663: if (!function_exists('__dc')) {
664:
665: /**
666: * Allows you to override the current domain for a single message lookup.
667: * It also allows you to specify a category.
668: *
669: * The category argument allows a specific category of the locale settings to be used for fetching a message.
670: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
671: *
672: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
673: *
674: * - LC_ALL I18n::LC_ALL
675: * - LC_COLLATE I18n::LC_COLLATE
676: * - LC_CTYPE I18n::LC_CTYPE
677: * - LC_MONETARY I18n::LC_MONETARY
678: * - LC_NUMERIC I18n::LC_NUMERIC
679: * - LC_TIME I18n::LC_TIME
680: * - LC_MESSAGES I18n::LC_MESSAGES
681: *
682: * @param string $domain Domain
683: * @param string $msg Message to translate
684: * @param int $category Category
685: * @param mixed $args Array with arguments or multiple arguments in function
686: * @return translated string
687: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dc
688: */
689: function __dc($domain, $msg, $category, $args = null) {
690: if (!$msg) {
691: return;
692: }
693: App::uses('I18n', 'I18n');
694: $translated = I18n::translate($msg, null, $domain, $category);
695: if ($args === null && func_num_args() < 5) {
696: return $translated;
697: } elseif (!is_array($args)) {
698: $args = array_slice(func_get_args(), 3);
699: }
700:
701: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
702: return vsprintf($translated, $args);
703: }
704:
705: }
706:
707: if (!function_exists('__dcn')) {
708:
709: /**
710: * Allows you to override the current domain for a single plural message lookup.
711: * It also allows you to specify a category.
712: * Returns correct plural form of message identified by $singular and $plural for count $count
713: * from domain $domain.
714: *
715: * The category argument allows a specific category of the locale settings to be used for fetching a message.
716: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
717: *
718: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
719: *
720: * - LC_ALL I18n::LC_ALL
721: * - LC_COLLATE I18n::LC_COLLATE
722: * - LC_CTYPE I18n::LC_CTYPE
723: * - LC_MONETARY I18n::LC_MONETARY
724: * - LC_NUMERIC I18n::LC_NUMERIC
725: * - LC_TIME I18n::LC_TIME
726: * - LC_MESSAGES I18n::LC_MESSAGES
727: *
728: * @param string $domain Domain
729: * @param string $singular Singular string to translate
730: * @param string $plural Plural
731: * @param int $count Count
732: * @param int $category Category
733: * @param mixed $args Array with arguments or multiple arguments in function
734: * @return plural form of translated string
735: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dcn
736: */
737: function __dcn($domain, $singular, $plural, $count, $category, $args = null) {
738: if (!$singular) {
739: return;
740: }
741: App::uses('I18n', 'I18n');
742: $translated = I18n::translate($singular, $plural, $domain, $category, $count);
743: if ($args === null && func_num_args() < 7) {
744: return $translated;
745: } elseif (!is_array($args)) {
746: $args = array_slice(func_get_args(), 5);
747: }
748:
749: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
750: return vsprintf($translated, $args);
751: }
752:
753: }
754:
755: if (!function_exists('__c')) {
756:
757: /**
758: * The category argument allows a specific category of the locale settings to be used for fetching a message.
759: * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
760: *
761: * Note that the category must be specified with a class constant of I18n, instead of the constant name. The values are:
762: *
763: * - LC_ALL I18n::LC_ALL
764: * - LC_COLLATE I18n::LC_COLLATE
765: * - LC_CTYPE I18n::LC_CTYPE
766: * - LC_MONETARY I18n::LC_MONETARY
767: * - LC_NUMERIC I18n::LC_NUMERIC
768: * - LC_TIME I18n::LC_TIME
769: * - LC_MESSAGES I18n::LC_MESSAGES
770: *
771: * @param string $msg String to translate
772: * @param int $category Category
773: * @param mixed $args Array with arguments or multiple arguments in function
774: * @return translated string
775: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__c
776: */
777: function __c($msg, $category, $args = null) {
778: if (!$msg) {
779: return;
780: }
781: App::uses('I18n', 'I18n');
782: $translated = I18n::translate($msg, null, null, $category);
783: if ($args === null && func_num_args() < 4) {
784: return $translated;
785: } elseif (!is_array($args)) {
786: $args = array_slice(func_get_args(), 2);
787: }
788:
789: $translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
790: return vsprintf($translated, $args);
791: }
792:
793: }
794:
795: if (!function_exists('LogError')) {
796:
797: /**
798: * Shortcut to Log::write.
799: *
800: * @param string $message Message to write to log
801: * @return void
802: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#LogError
803: */
804: function LogError($message) {
805: App::uses('CakeLog', 'Log');
806: $bad = array("\n", "\r", "\t");
807: $good = ' ';
808: CakeLog::write('error', str_replace($bad, $good, $message));
809: }
810:
811: }
812:
813: if (!function_exists('fileExistsInPath')) {
814:
815: /**
816: * Searches include path for files.
817: *
818: * @param string $file File to look for
819: * @return Full path to file if exists, otherwise false
820: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#fileExistsInPath
821: */
822: function fileExistsInPath($file) {
823: $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
824: foreach ($paths as $path) {
825: $fullPath = $path . DS . $file;
826:
827: if (file_exists($fullPath)) {
828: return $fullPath;
829: } elseif (file_exists($file)) {
830: return $file;
831: }
832: }
833: return false;
834: }
835:
836: }
837:
838: if (!function_exists('convertSlash')) {
839:
840: /**
841: * Convert forward slashes to underscores and removes first and last underscores in a string
842: *
843: * @param string $string String to convert
844: * @return string with underscore remove from start and end of string
845: * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#convertSlash
846: */
847: function convertSlash($string) {
848: $string = trim($string, '/');
849: $string = preg_replace('/\/\//', '/', $string);
850: $string = str_replace('/', '_', $string);
851: return $string;
852: }
853:
854: }
855: