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