cake/basics.php

1 <?php
2 /**
3 * Basic Cake functionality.
4 *
5 * Core functions for including other source files, loading models and so forth.
6 *
7 * PHP versions 4 and 5
8 *
9 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
10 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
11 *
12 * Licensed under The MIT License
13 * Redistributions of files must retain the above copyright notice.
14 *
15 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
16 * @link http://cakephp.org CakePHP(tm) Project
17 * @package cake
18 * @subpackage cake.cake
19 * @since CakePHP(tm) v 0.2.9
20 * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
21 */
22  
23 /**
24 * Basic defines for timing functions.
25 */
26 define('SECOND', 1);
27 define('MINUTE', 60);
28 define('HOUR', 3600);
29 define('DAY', 86400);
30 define('WEEK', 604800);
31 define('MONTH', 2592000);
32 define('YEAR', 31536000);
33  
34 /**
35 * Patch for PHP < 5.0
36 */
37 if (!function_exists('clone')) {
38 if (version_compare(PHP_VERSION, '5.0') < 0) {
39 eval ('
40 function clone($object)
41 {
42 return $object;
43 }');
44 }
45 }
46  
47 /**
48 * Loads configuration files. Receives a set of configuration files
49 * to load.
50 * Example:
51 *
52 * `config('config1', 'config2');`
53 *
54 * @return boolean Success
55 * @link http://book.cakephp.org/view/1125/config
56 */
57 function config() {
58 $args = func_get_args();
59 foreach ($args as $arg) {
60 if ($arg === 'database' && file_exists(CONFIGS . 'database.php')) {
61 include_once(CONFIGS . $arg . '.php');
62 } elseif (file_exists(CONFIGS . $arg . '.php')) {
63 include_once(CONFIGS . $arg . '.php');
64  
65 if (count($args) == 1) {
66 return true;
67 }
68 } else {
69 if (count($args) == 1) {
70 return false;
71 }
72 }
73 }
74 return true;
75 }
76  
77 /**
78 * Loads component/components from LIBS. Takes optional number of parameters.
79 *
80 * Example:
81 *
82 * `uses('flay', 'time');`
83 *
84 * @param string $name Filename without the .php part
85 * @deprecated Will be removed in 2.0
86 * @link http://book.cakephp.org/view/1140/uses
87 */
88 function uses() {
89 $args = func_get_args();
90 foreach ($args as $file) {
91 require_once(LIBS . strtolower($file) . '.php');
92 }
93 }
94  
95 /**
96 * Prints out debug information about given variable.
97 *
98 * Only runs if debug level is greater than zero.
99 *
100 * @param boolean $var Variable to show debug information for.
101 * @param boolean $showHtml If set to true, the method prints the debug data in a screen-friendly way.
102 * @param boolean $showFrom If set to true, the method prints from where the function was called.
103 * @link http://book.cakephp.org/view/1190/Basic-Debugging
104 * @link http://book.cakephp.org/view/1128/debug
105 */
106 function debug($var = false, $showHtml = false, $showFrom = true) {
107 if (Configure::read() > 0) {
108 if ($showFrom) {
109 $calledFrom = debug_backtrace();
110 echo '<strong>' . substr(str_replace(ROOT, '', $calledFrom[0]['file']), 1) . '</strong>';
111 echo ' (line <strong>' . $calledFrom[0]['line'] . '</strong>)';
112 }
113 echo "\n<pre class=\"cake-debug\">\n";
114  
115 $var = print_r($var, true);
116 if ($showHtml) {
117 $var = str_replace('<', '&lt;', str_replace('>', '&gt;', $var));
118 }
119 echo $var . "\n</pre>\n";
120 }
121 }
122 if (!function_exists('getMicrotime')) {
123  
124 /**
125 * Returns microtime for execution time checking
126 *
127 * @return float Microtime
128 */
129 function getMicrotime() {
130 list($usec, $sec) = explode(' ', microtime());
131 return ((float)$usec + (float)$sec);
132 }
133 }
134 if (!function_exists('sortByKey')) {
135  
136 /**
137 * Sorts given $array by key $sortby.
138 *
139 * @param array $array Array to sort
140 * @param string $sortby Sort by this key
141 * @param string $order Sort order asc/desc (ascending or descending).
142 * @param integer $type Type of sorting to perform
143 * @return mixed Sorted array
144 */
145 function sortByKey(&$array, $sortby, $order = 'asc', $type = SORT_NUMERIC) {
146 if (!is_array($array)) {
147 return null;
148 }
149  
150 foreach ($array as $key => $val) {
151 $sa[$key] = $val[$sortby];
152 }
153  
154 if ($order == 'asc') {
155 asort($sa, $type);
156 } else {
157 arsort($sa, $type);
158 }
159  
160 foreach ($sa as $key => $val) {
161 $out[] = $array[$key];
162 }
163 return $out;
164 }
165 }
166 if (!function_exists('array_combine')) {
167  
168 /**
169 * Combines given identical arrays by using the first array's values as keys,
170 * and the second one's values as values. (Implemented for backwards compatibility with PHP4)
171 *
172 * @param array $a1 Array to use for keys
173 * @param array $a2 Array to use for values
174 * @return mixed Outputs either combined array or false.
175 * @deprecated Will be removed in 2.0
176 */
177 function array_combine($a1, $a2) {
178 $a1 = array_values($a1);
179 $a2 = array_values($a2);
180 $c1 = count($a1);
181 $c2 = count($a2);
182  
183 if ($c1 != $c2) {
184 return false;
185 }
186 if ($c1 <= 0) {
187 return false;
188 }
189 $output = array();
190  
191 for ($i = 0; $i < $c1; $i++) {
192 $output[$a1[$i]] = $a2[$i];
193 }
194 return $output;
195 }
196 }
197  
198 /**
199 * Convenience method for htmlspecialchars.
200 *
201 * @param string $text Text to wrap through htmlspecialchars
202 * @param string $charset Character set to use when escaping. Defaults to config value in 'App.encoding' or 'UTF-8'
203 * @return string Wrapped text
204 * @link http://book.cakephp.org/view/1132/h
205 */
206 function h($text, $charset = null) {
207 if (is_array($text)) {
208 return array_map('h', $text);
209 }
210  
211 static $defaultCharset = false;
212 if ($defaultCharset === false) {
213 $defaultCharset = Configure::read('App.encoding');
214 if ($defaultCharset === null) {
215 $defaultCharset = 'UTF-8';
216 }
217 }
218 if ($charset) {
219 return htmlspecialchars($text, ENT_QUOTES, $charset);
220 } else {
221 return htmlspecialchars($text, ENT_QUOTES, $defaultCharset);
222 }
223 }
224  
225 /**
226 * Splits a dot syntax plugin name into its plugin and classname.
227 * If $name does not have a dot, then index 0 will be null.
228 *
229 * Commonly used like `list($plugin, $name) = pluginSplit($name);`
230 *
231 * @param string $name The name you want to plugin split.
232 * @param boolean $dotAppend Set to true if you want the plugin to have a '.' appended to it.
233 * @param string $plugin Optional default plugin to use if no plugin is found. Defaults to null.
234 * @return array Array with 2 indexes. 0 => plugin name, 1 => classname
235 */
236 function pluginSplit($name, $dotAppend = false, $plugin = null) {
237 if (strpos($name, '.') !== false) {
238 $parts = explode('.', $name, 2);
239 if ($dotAppend) {
240 $parts[0] .= '.';
241 }
242 return $parts;
243 }
244 return array($plugin, $name);
245 }
246  
247 /**
248 * Returns an array of all the given parameters.
249 *
250 * Example:
251 *
252 * `a('a', 'b')`
253 *
254 * Would return:
255 *
256 * `array('a', 'b')`
257 *
258 * @return array Array of given parameters
259 * @link http://book.cakephp.org/view/1122/a
260 * @deprecated Will be removed in 2.0
261 */
262 function a() {
263 $args = func_get_args();
264 return $args;
265 }
266  
267 /**
268 * Constructs associative array from pairs of arguments.
269 *
270 * Example:
271 *
272 * `aa('a','b')`
273 *
274 * Would return:
275 *
276 * `array('a'=>'b')`
277 *
278 * @return array Associative array
279 * @link http://book.cakephp.org/view/1123/aa
280 * @deprecated Will be removed in 2.0
281 */
282 function aa() {
283 $args = func_get_args();
284 $argc = count($args);
285 for ($i = 0; $i < $argc; $i++) {
286 if ($i + 1 < $argc) {
287 $a[$args[$i]] = $args[$i + 1];
288 } else {
289 $a[$args[$i]] = null;
290 }
291 $i++;
292 }
293 return $a;
294 }
295  
296 /**
297 * Convenience method for echo().
298 *
299 * @param string $text String to echo
300 * @link http://book.cakephp.org/view/1129/e
301 * @deprecated Will be removed in 2.0
302 */
303 function e($text) {
304 echo $text;
305 }
306  
307 /**
308 * Convenience method for strtolower().
309 *
310 * @param string $str String to lowercase
311 * @return string Lowercased string
312 * @link http://book.cakephp.org/view/1134/low
313 * @deprecated Will be removed in 2.0
314 */
315 function low($str) {
316 return strtolower($str);
317 }
318  
319 /**
320 * Convenience method for strtoupper().
321 *
322 * @param string $str String to uppercase
323 * @return string Uppercased string
324 * @link http://book.cakephp.org/view/1139/up
325 * @deprecated Will be removed in 2.0
326 */
327 function up($str) {
328 return strtoupper($str);
329 }
330  
331 /**
332 * Convenience method for str_replace().
333 *
334 * @param string $search String to be replaced
335 * @param string $replace String to insert
336 * @param string $subject String to search
337 * @return string Replaced string
338 * @link http://book.cakephp.org/view/1137/r
339 * @deprecated Will be removed in 2.0
340 */
341 function r($search, $replace, $subject) {
342 return str_replace($search, $replace, $subject);
343 }
344  
345 /**
346 * Print_r convenience function, which prints out <PRE> tags around
347 * the output of given array. Similar to debug().
348 *
349 * @see debug()
350 * @param array $var Variable to print out
351 * @link http://book.cakephp.org/view/1136/pr
352 */
353 function pr($var) {
354 if (Configure::read() > 0) {
355 echo '<pre>';
356 print_r($var);
357 echo '</pre>';
358 }
359 }
360  
361 /**
362 * Display parameters.
363 *
364 * @param mixed $p Parameter as string or array
365 * @return string
366 * @deprecated Will be removed in 2.0
367 */
368 function params($p) {
369 if (!is_array($p) || count($p) == 0) {
370 return null;
371 }
372 if (is_array($p[0]) && count($p) == 1) {
373 return $p[0];
374 }
375 return $p;
376 }
377  
378 /**
379 * Merge a group of arrays
380 *
381 * @param array First array
382 * @param array Second array
383 * @param array Third array
384 * @param array Etc...
385 * @return array All array parameters merged into one
386 * @link http://book.cakephp.org/view/1124/am
387 */
388 function am() {
389 $r = array();
390 $args = func_get_args();
391 foreach ($args as $a) {
392 if (!is_array($a)) {
393 $a = array($a);
394 }
395 $r = array_merge($r, $a);
396 }
397 return $r;
398 }
399  
400 /**
401 * Gets an environment variable from available sources, and provides emulation
402 * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
403 * IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
404 * environment information.
405 *
406 * @param string $key Environment variable name.
407 * @return string Environment variable setting.
408 * @link http://book.cakephp.org/view/1130/env
409 */
410 function env($key) {
411 if ($key == 'HTTPS') {
412 if (isset($_SERVER['HTTPS'])) {
413 return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
414 }
415 return (strpos(env('SCRIPT_URI'), 'https://') === 0);
416 }
417  
418 if ($key == 'SCRIPT_NAME') {
419 if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
420 $key = 'SCRIPT_URL';
421 }
422 }
423  
424 $val = null;
425 if (isset($_SERVER[$key])) {
426 $val = $_SERVER[$key];
427 } elseif (isset($_ENV[$key])) {
428 $val = $_ENV[$key];
429 } elseif (getenv($key) !== false) {
430 $val = getenv($key);
431 }
432  
433 if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) {
434 $addr = env('HTTP_PC_REMOTE_ADDR');
435 if ($addr !== null) {
436 $val = $addr;
437 }
438 }
439  
440 if ($val !== null) {
441 return $val;
442 }
443  
444 switch ($key) {
445 case 'SCRIPT_FILENAME':
446 if (defined('SERVER_IIS') && SERVER_IIS === true) {
447 return str_replace('\\\\', '\\', env('PATH_TRANSLATED'));
448 }
449 break;
450 case 'DOCUMENT_ROOT':
451 $name = env('SCRIPT_NAME');
452 $filename = env('SCRIPT_FILENAME');
453 $offset = 0;
454 if (!strpos($name, '.php')) {
455 $offset = 4;
456 }
457 return substr($filename, 0, strlen($filename) - (strlen($name) + $offset));
458 break;
459 case 'PHP_SELF':
460 return str_replace(env('DOCUMENT_ROOT'), '', env('SCRIPT_FILENAME'));
461 break;
462 case 'CGI_MODE':
463 return (PHP_SAPI === 'cgi');
464 break;
465 case 'HTTP_BASE':
466 $host = env('HTTP_HOST');
467 if (substr_count($host, '.') !== 1) {
468 return preg_replace('/^([^.])*/i', null, env('HTTP_HOST'));
469 }
470 return '.' . $host;
471 break;
472 }
473 return null;
474 }
475 if (!function_exists('file_put_contents')) {
476  
477 /**
478 * Writes data into file.
479 *
480 * If file exists, it will be overwritten. If data is an array, it will be implode()ed with an empty string.
481 *
482 * @param string $fileName File name.
483 * @param mixed $data String or array.
484 * @return boolean Success
485 * @deprecated Will be removed in 2.0
486 */
487 function file_put_contents($fileName, $data) {
488 if (is_array($data)) {
489 $data = implode('', $data);
490 }
491 $res = @fopen($fileName, 'w+b');
492  
493 if ($res) {
494 $write = @fwrite($res, $data);
495 if ($write === false) {
496 return false;
497 } else {
498 @fclose($res);
499 return $write;
500 }
501 }
502 return false;
503 }
504 }
505  
506 /**
507 * Reads/writes temporary data to cache files or session.
508 *
509 * @param string $path File path within /tmp to save the file.
510 * @param mixed $data The data to save to the temporary file.
511 * @param mixed $expires A valid strtotime string when the data expires.
512 * @param string $target The target of the cached data; either 'cache' or 'public'.
513 * @return mixed The contents of the temporary file.
514 * @deprecated Please use Cache::write() instead
515 */
516 function cache($path, $data = null, $expires = '+1 day', $target = 'cache') {
517 if (Configure::read('Cache.disable')) {
518 return null;
519 }
520 $now = time();
521  
522 if (!is_numeric($expires)) {
523 $expires = strtotime($expires, $now);
524 }
525  
526 switch (strtolower($target)) {
527 case 'cache':
528 $filename = CACHE . $path;
529 break;
530 case 'public':
531 $filename = WWW_ROOT . $path;
532 break;
533 case 'tmp':
534 $filename = TMP . $path;
535 break;
536 }
537 $timediff = $expires - $now;
538 $filetime = false;
539  
540 if (file_exists($filename)) {
541 $filetime = @filemtime($filename);
542 }
543  
544 if ($data === null) {
545 if (file_exists($filename) && $filetime !== false) {
546 if ($filetime + $timediff < $now) {
547 @unlink($filename);
548 } else {
549 $data = @file_get_contents($filename);
550 }
551 }
552 } elseif (is_writable(dirname($filename))) {
553 @file_put_contents($filename, $data);
554 }
555 return $data;
556 }
557  
558 /**
559 * Used to delete files in the cache directories, or clear contents of cache directories
560 *
561 * @param mixed $params As String name to be searched for deletion, if name is a directory all files in
562 * directory will be deleted. If array, names to be searched for deletion. If clearCache() without params,
563 * all files in app/tmp/cache/views will be deleted
564 * @param string $type Directory in tmp/cache defaults to view directory
565 * @param string $ext The file extension you are deleting
566 * @return true if files found and deleted false otherwise
567 */
568 function clearCache($params = null, $type = 'views', $ext = '.php') {
569 if (is_string($params) || $params === null) {
570 $params = preg_replace('/\/\//', '/', $params);
571 $cache = CACHE . $type . DS . $params;
572  
573 if (is_file($cache . $ext)) {
574 @unlink($cache . $ext);
575 return true;
576 } elseif (is_dir($cache)) {
577 $files = glob($cache . '*');
578  
579 if ($files === false) {
580 return false;
581 }
582  
583 foreach ($files as $file) {
584 if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
585 @unlink($file);
586 }
587 }
588 return true;
589 } else {
590 $cache = array(
591 CACHE . $type . DS . '*' . $params . $ext,
592 CACHE . $type . DS . '*' . $params . '_*' . $ext
593 );
594 $files = array();
595 while ($search = array_shift($cache)) {
596 $results = glob($search);
597 if ($results !== false) {
598 $files = array_merge($files, $results);
599 }
600 }
601 if (empty($files)) {
602 return false;
603 }
604 foreach ($files as $file) {
605 if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) {
606 @unlink($file);
607 }
608 }
609 return true;
610 }
611 } elseif (is_array($params)) {
612 foreach ($params as $file) {
613 clearCache($file, $type, $ext);
614 }
615 return true;
616 }
617 return false;
618 }
619  
620 /**
621 * Recursively strips slashes from all values in an array
622 *
623 * @param array $values Array of values to strip slashes
624 * @return mixed What is returned from calling stripslashes
625 * @link http://book.cakephp.org/view/1138/stripslashes_deep
626 */
627 function stripslashes_deep($values) {
628 if (is_array($values)) {
629 foreach ($values as $key => $value) {
630 $values[$key] = stripslashes_deep($value);
631 }
632 } else {
633 $values = stripslashes($values);
634 }
635 return $values;
636 }
637  
638 /**
639 * Returns a translated string if one is found; Otherwise, the submitted message.
640 *
641 * @param string $singular Text to translate
642 * @param boolean $return Set to true to return translated string, or false to echo
643 * @return mixed translated string if $return is false string will be echoed
644 * @link http://book.cakephp.org/view/1121/__
645 */
646 function __($singular, $return = false) {
647 if (!$singular) {
648 return;
649 }
650 if (!class_exists('I18n')) {
651 App::import('Core', 'i18n');
652 }
653  
654 if ($return === false) {
655 echo I18n::translate($singular);
656 } else {
657 return I18n::translate($singular);
658 }
659 }
660  
661 /**
662 * Returns correct plural form of message identified by $singular and $plural for count $count.
663 * Some languages have more than one form for plural messages dependent on the count.
664 *
665 * @param string $singular Singular text to translate
666 * @param string $plural Plural text
667 * @param integer $count Count
668 * @param boolean $return true to return, false to echo
669 * @return mixed plural form of translated string if $return is false string will be echoed
670 */
671 function __n($singular, $plural, $count, $return = false) {
672 if (!$singular) {
673 return;
674 }
675 if (!class_exists('I18n')) {
676 App::import('Core', 'i18n');
677 }
678  
679 if ($return === false) {
680 echo I18n::translate($singular, $plural, null, 6, $count);
681 } else {
682 return I18n::translate($singular, $plural, null, 6, $count);
683 }
684 }
685  
686 /**
687 * Allows you to override the current domain for a single message lookup.
688 *
689 * @param string $domain Domain
690 * @param string $msg String to translate
691 * @param string $return true to return, false to echo
692 * @return translated string if $return is false string will be echoed
693 */
694 function __d($domain, $msg, $return = false) {
695 if (!$msg) {
696 return;
697 }
698 if (!class_exists('I18n')) {
699 App::import('Core', 'i18n');
700 }
701  
702 if ($return === false) {
703 echo I18n::translate($msg, null, $domain);
704 } else {
705 return I18n::translate($msg, null, $domain);
706 }
707 }
708  
709 /**
710 * Allows you to override the current domain for a single plural message lookup.
711 * Returns correct plural form of message identified by $singular and $plural for count $count
712 * from domain $domain.
713 *
714 * @param string $domain Domain
715 * @param string $singular Singular string to translate
716 * @param string $plural Plural
717 * @param integer $count Count
718 * @param boolean $return true to return, false to echo
719 * @return plural form of translated string if $return is false string will be echoed
720 */
721 function __dn($domain, $singular, $plural, $count, $return = false) {
722 if (!$singular) {
723 return;
724 }
725 if (!class_exists('I18n')) {
726 App::import('Core', 'i18n');
727 }
728  
729 if ($return === false) {
730 echo I18n::translate($singular, $plural, $domain, 6, $count);
731 } else {
732 return I18n::translate($singular, $plural, $domain, 6, $count);
733 }
734 }
735  
736 /**
737 * Allows you to override the current domain for a single message lookup.
738 * It also allows you to specify a category.
739 *
740 * The category argument allows a specific category of the locale settings to be used for fetching a message.
741 * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
742 *
743 * Note that the category must be specified with a numeric value, instead of the constant name. The values are:
744 *
745 * - LC_ALL 0
746 * - LC_COLLATE 1
747 * - LC_CTYPE 2
748 * - LC_MONETARY 3
749 * - LC_NUMERIC 4
750 * - LC_TIME 5
751 * - LC_MESSAGES 6
752 *
753 * @param string $domain Domain
754 * @param string $msg Message to translate
755 * @param integer $category Category
756 * @param boolean $return true to return, false to echo
757 * @return translated string if $return is false string will be echoed
758 */
759 function __dc($domain, $msg, $category, $return = false) {
760 if (!$msg) {
761 return;
762 }
763 if (!class_exists('I18n')) {
764 App::import('Core', 'i18n');
765 }
766  
767 if ($return === false) {
768 echo I18n::translate($msg, null, $domain, $category);
769 } else {
770 return I18n::translate($msg, null, $domain, $category);
771 }
772 }
773  
774 /**
775 * Allows you to override the current domain for a single plural message lookup.
776 * It also allows you to specify a category.
777 * Returns correct plural form of message identified by $singular and $plural for count $count
778 * from domain $domain.
779 *
780 * The category argument allows a specific category of the locale settings to be used for fetching a message.
781 * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
782 *
783 * Note that the category must be specified with a numeric value, instead of the constant name. The values are:
784 *
785 * - LC_ALL 0
786 * - LC_COLLATE 1
787 * - LC_CTYPE 2
788 * - LC_MONETARY 3
789 * - LC_NUMERIC 4
790 * - LC_TIME 5
791 * - LC_MESSAGES 6
792 *
793 * @param string $domain Domain
794 * @param string $singular Singular string to translate
795 * @param string $plural Plural
796 * @param integer $count Count
797 * @param integer $category Category
798 * @param boolean $return true to return, false to echo
799 * @return plural form of translated string if $return is false string will be echoed
800 */
801 function __dcn($domain, $singular, $plural, $count, $category, $return = false) {
802 if (!$singular) {
803 return;
804 }
805 if (!class_exists('I18n')) {
806 App::import('Core', 'i18n');
807 }
808  
809 if ($return === false) {
810 echo I18n::translate($singular, $plural, $domain, $category, $count);
811 } else {
812 return I18n::translate($singular, $plural, $domain, $category, $count);
813 }
814 }
815  
816 /**
817 * The category argument allows a specific category of the locale settings to be used for fetching a message.
818 * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
819 *
820 * Note that the category must be specified with a numeric value, instead of the constant name. The values are:
821 *
822 * - LC_ALL 0
823 * - LC_COLLATE 1
824 * - LC_CTYPE 2
825 * - LC_MONETARY 3
826 * - LC_NUMERIC 4
827 * - LC_TIME 5
828 * - LC_MESSAGES 6
829 *
830 * @param string $msg String to translate
831 * @param integer $category Category
832 * @param string $return true to return, false to echo
833 * @return translated string if $return is false string will be echoed
834 */
835 function __c($msg, $category, $return = false) {
836 if (!$msg) {
837 return;
838 }
839 if (!class_exists('I18n')) {
840 App::import('Core', 'i18n');
841 }
842  
843 if ($return === false) {
844 echo I18n::translate($msg, null, null, $category);
845 } else {
846 return I18n::translate($msg, null, null, $category);
847 }
848 }
849  
850 /**
851 * Computes the difference of arrays using keys for comparison.
852 *
853 * @param array First array
854 * @param array Second array
855 * @return array Array with different keys
856 * @deprecated Will be removed in 2.0
857 */
858 if (!function_exists('array_diff_key')) {
859 function array_diff_key() {
860 $valuesDiff = array();
861  
862 $argc = func_num_args();
863 if ($argc < 2) {
864 return false;
865 }
866  
867 $args = func_get_args();
868 foreach ($args as $param) {
869 if (!is_array($param)) {
870 return false;
871 }
872 }
873  
874 foreach ($args[0] as $valueKey => $valueData) {
875 for ($i = 1; $i < $argc; $i++) {
876 if (array_key_exists($valueKey, $args[$i])) {
877 continue 2;
878 }
879 }
880 $valuesDiff[$valueKey] = $valueData;
881 }
882 return $valuesDiff;
883 }
884 }
885  
886 /**
887 * Computes the intersection of arrays using keys for comparison
888 *
889 * @param array First array
890 * @param array Second array
891 * @return array Array with interesected keys
892 * @deprecated Will be removed in 2.0
893 */
894 if (!function_exists('array_intersect_key')) {
895 function array_intersect_key($arr1, $arr2) {
896 $res = array();
897 foreach ($arr1 as $key => $value) {
898 if (array_key_exists($key, $arr2)) {
899 $res[$key] = $arr1[$key];
900 }
901 }
902 return $res;
903 }
904 }
905  
906 /**
907 * Shortcut to Log::write.
908 *
909 * @param string $message Message to write to log
910 */
911 function LogError($message) {
912 if (!class_exists('CakeLog')) {
913 App::import('Core', 'CakeLog');
914 }
915 $bad = array("\n", "\r", "\t");
916 $good = ' ';
917 CakeLog::write('error', str_replace($bad, $good, $message));
918 }
919  
920 /**
921 * Searches include path for files.
922 *
923 * @param string $file File to look for
924 * @return Full path to file if exists, otherwise false
925 * @link http://book.cakephp.org/view/1131/fileExistsInPath
926 */
927 function fileExistsInPath($file) {
928 $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
929 foreach ($paths as $path) {
930 $fullPath = $path . DS . $file;
931  
932 if (file_exists($fullPath)) {
933 return $fullPath;
934 } elseif (file_exists($file)) {
935 return $file;
936 }
937 }
938 return false;
939 }
940  
941 /**
942 * Convert forward slashes to underscores and removes first and last underscores in a string
943 *
944 * @param string String to convert
945 * @return string with underscore remove from start and end of string
946 * @link http://book.cakephp.org/view/1126/convertSlash
947 */
948 function convertSlash($string) {
949 $string = trim($string, '/');
950 $string = preg_replace('/\/\//', '/', $string);
951 $string = str_replace('/', '_', $string);
952 return $string;
953 }
954  
955 /**
956 * Implements http_build_query for PHP4.
957 *
958 * @param string $data Data to set in query string
959 * @param string $prefix If numeric indices, prepend this to index for elements in base array.
960 * @param string $argSep String used to separate arguments
961 * @param string $baseKey Base key
962 * @return string URL encoded query string
963 * @see http://php.net/http_build_query
964 * @deprecated Will be removed in 2.0
965 */
966 if (!function_exists('http_build_query')) {
967 function http_build_query($data, $prefix = null, $argSep = null, $baseKey = null) {
968 if (empty($argSep)) {
969 $argSep = ini_get('arg_separator.output');
970 }
971 if (is_object($data)) {
972 $data = get_object_vars($data);
973 }
974 $out = array();
975  
976 foreach ((array)$data as $key => $v) {
977 if (is_numeric($key) && !empty($prefix)) {
978 $key = $prefix . $key;
979 }
980 $key = urlencode($key);
981  
982 if (!empty($baseKey)) {
983 $key = $baseKey . '[' . $key . ']';
984 }
985  
986 if (is_array($v) || is_object($v)) {
987 $out[] = http_build_query($v, $prefix, $argSep, $key);
988 } else {
989 $out[] = $key . '=' . urlencode($v);
990 }
991 }
992 return implode($argSep, $out);
993 }
994 }
995  
996 /**
997 * Wraps ternary operations. If $condition is a non-empty value, $val1 is returned, otherwise $val2.
998 * Don't use for isset() conditions, or wrap your variable with @ operator:
999 * Example:
1000 *
1001 * `ife(isset($variable), @$variable, 'default');`
1002 *
1003 * @param mixed $condition Conditional expression
1004 * @param mixed $val1 Value to return in case condition matches
1005 * @param mixed $val2 Value to return if condition doesn't match
1006 * @return mixed $val1 or $val2, depending on whether $condition evaluates to a non-empty expression.
1007 * @link http://book.cakephp.org/view/1133/ife
1008 * @deprecated Will be removed in 2.0
1009 */
1010 function ife($condition, $val1 = null, $val2 = null) {
1011 if (!empty($condition)) {
1012 return $val1;
1013 }
1014 return $val2;
1015 }
1016  
1017