Removed double <div> from Picasa2 album render
[tip.git] / TIP.php
blob84a983fb2203125ba82b76150d02a261a582dfe0
1 <?php
2 /* vim: set expandtab shiftwidth=4 softtabstop=4 tabstop=4 foldmethod=marker: */
4 /**
5 * Main definition file
7 * The TiP framework requires PHP v.5.2.0 or later.
9 * LICENSE: This source file is subject to the New BSD license that is
10 * available through the world-wide-web at the following URI:
11 * http://www.opensource.org/licenses/bsd-license.php
12 * If you did not receive a copy of the New BSD License and are unable to
13 * obtain it through the web, please send a note to license@php.net so we
14 * can mail you a copy immediately.
16 * @author Nicola Fontana <ntd@entidi.it>
17 * @copyright Copyright &copy; 2006-2008 Nicola Fontana
18 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
19 * @package TIP
20 * @since 0.0.1
23 /**
24 * This avoid E_STRICT errors generation. It will be removed when TIP will be
25 * fully PHP-5 compliant.
27 * Now I have too many PHP-4 dependencies that cannot be updated (PEAR overall,
28 * but also Text_Wiki, HTML_QuickForm and HTML_Menu).
30 error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
32 /**
33 * The default encoding for TIP based sites is utf8.
35 mb_internal_encoding('UTF-8');
37 /**
38 * Defs.php must precede anything
40 require_once 'Defs.php';
41 require_once 'Renderer.php';
43 set_include_path(TIP::buildLogicPath('pear'));
45 require_once 'PEAR.php';
46 require_once 'HTTP.php';
47 require_once TIP::buildLogicPath('Type.php');
49 /**
50 * A collection of global functions
52 * A static class root of all the TIP hierarchy. It provides some global useful
53 * functions.
56 * @package TIP
58 class TIP
60 //{{{ Internal methods
62 static private function _getTyped($id, $type, &$collection)
64 $value = @$collection[$id];
65 if (is_null($value) || ! settype($value, $type)) {
66 return null;
69 if (! is_string($value) && ! is_array($value)) {
70 return $value;
73 return get_magic_quotes_gpc() ? TIP::deepStripSlashes($value) : $value;
76 static private function _formatTimestamp($timestamp, $format)
78 switch ($format) {
80 case '':
81 return $timestamp;
83 case 'date':
84 // Custom locale manipulations
85 switch (TIP::getLocaleId()) {
87 case 'it_IT':
88 $same_year = date('Y', $timestamp) == date('Y');
89 $same_day = date('z', $timestamp) == date('z');
90 if ($same_year && $same_day) {
91 return 'oggi';
93 return strftime($same_year ? '%d %B' : '%d %B %Y', $timestamp);
96 return strftime('%x', $timestamp);
98 case 'datetime':
99 // Custom locale manipulations
100 switch (TIP::getLocaleId()) {
102 case 'it_IT':
103 $date = TIP::_formatTimestamp($timestamp, 'date');
104 return $date . ' alle ' . strftime('%H:%M', $timestamp);
107 return strftime('%c', $timestamp);
109 case 'date_sql':
110 case 'date_iso8601':
111 return strftime('%Y-%m-%d', $timestamp);
113 case 'datetime_sql':
114 return strftime('%Y-%m-%d %H:%M:%S', $timestamp);
116 case 'datetime_iso8601':
117 return date(DATE_ISO8601, $timestamp);
119 case 'datetime_rfc3339':
120 return date(DATE_RFC3339, $timestamp);
123 return strftime($format, $timestamp);
126 //}}}
127 //{{{ Static methods
130 * Get the operating system descriptor
132 * Checks the PHP_OS constant to get on which operating system the PHP is
133 * running. If the PHP_OS constant is not defined, the function fallbacks
134 * to 'unix'. The idea was picked from phpMyAdmin.
136 * @return 'unix'|'windows'|'os2' The guessed operating system descriptor
138 static public function getOS()
140 $os = 'unix';
142 if (defined ('PHP_OS')) {
143 if (stristr(PHP_OS, 'win')) {
144 $os = 'windows';
145 } elseif (stristr (PHP_OS, 'OS/2')) {
146 $os = 'os2';
150 return $os;
154 * Convenience function to set a default array value
156 * @param array &$array An array
157 * @param string $key The item key on $array
158 * @param mixed $value The value to use if $array[$key] is not set
160 static public function arrayDefault(&$array, $key, $value)
162 if (!is_array($array) || !array_key_exists($key, $array)) {
163 $array[$key] = $value;
168 * Get an option
170 * Gets a configuration option for a specified type. All the option values
171 * are defined in the config file.
173 * @param string $type Descriptor of the type
174 * @param string $option The option to retrieve
175 * @return mixed|null The requested option or null on errors
177 static public function getOption($type, $option, $required = false)
179 $value = @$GLOBALS['cfg'][$type][$option];
180 if ($required && !isset($value)) {
181 TIP::fatal("Required option not defined (\$cfg['$type']['$option'])");
183 return $value;
187 * Define a required option
189 * If $option is not defined in the $options array, try to guess the
190 * default value by inspecting the configuration options of the first
191 * 'application' module found in the global $cfg array.
193 * If yet not found, the $fallback value is used.
195 * @param array &$options Array of options
196 * @param string $option The option to set
197 * @param mixed $fallback The fallback value
199 static public function requiredOption(&$options, $option, $fallback = null)
201 if (isset($options[$option])) {
202 return;
203 } elseif (isset($GLOBALS[TIP_MAIN])) {
204 $options[$option] =& TIP_Application::getGlobal($option);
205 } else {
206 static $main_cfg = null;
208 if (is_null($main_cfg)) {
209 // Search for the first application module
210 global $cfg;
211 $main_cfg = false;
212 foreach (array_keys($cfg) as $id) {
213 if (end($cfg[$id]['type']) == 'application') {
214 $main_cfg = $cfg[$id];
215 break;
220 if ($main_cfg && isset($main_cfg[$option])) {
221 $options[$option] = $main_cfg[$option];
222 } else {
223 $options[$option] = $fallback;
229 * Set locale in a platform-independent way
231 * @param string $locale The locale name (such as 'en_US' or 'it_IT')
232 * @return boolean true on success or false if not possible
233 * @uses exception If the locale could not be set
234 * or the encoding will is not UTF-8
236 function setLocaleId($locale)
238 if (@strpos($locale, '_') === false) {
239 TIP::warning ("Not a valid locale id ($locale)");
240 return false;
243 list($language, $country) = explode('_', $locale);
245 $result = setlocale(LC_ALL, $locale . '.UTF-8', $language, $locale);
246 if(!$result) {
247 throw new exception("Unknown locale name ($locale)");
250 // See if we have successfully set it to UTF-8
251 if(!strpos($result, 'UTF-8')) {
252 throw new exception('Unable to force UTF-8 encoding on this system');
255 return true;
259 * Get the current locale, such as 'en_US' or 'it_IT'
261 * @param string $separator The optional glue to use between language
262 * and territory parts
263 * @return string The current locale
265 static public function getLocaleId($separator = '_')
267 static $locale = null;
268 if (is_null($locale)) {
269 $shared_modules = TIP_Application::getGlobal('shared_modules');
270 $locale = TIP::getOption($shared_modules['locale'], 'locale');
273 // Fallback to en_US, so ensure the locale is set anyway
274 isset($locale) || $locale = 'en_US';
276 return str_replace('_', $separator, $locale);
280 * Get a localized text
282 * Gets the localized text for the specified id and prefix.
283 * The parameters are passed throught: this is merely a shortcut.
285 * See the TIP_Locale::get() method for technical details on how the text
286 * is localized.
288 * @param string $id The identifier
289 * @param string $prefix The prefix
290 * @param array $context A context associative array
291 * @param bool $cached Whether to perform or not a cached read
292 * @return string|null The localized text or null if not found
294 static public function getLocale($id, $prefix, $context = null, $cached = true)
296 static $locale = false;
297 if ($locale === false) {
298 $locale =& TIP_Application::getSharedModule('locale');
300 if (!$locale instanceof TIP_Type) {
301 return null;
303 return $locale->get($id, $prefix, $context, $cached);
307 * Start the session
309 static public function startSession()
311 require_once 'HTTP/Session2.php';
313 $user_id = TIP::getUserId();
314 if ($user_id) {
315 // For a logged in user, use the special TIP container
316 HTTP_Session2::useCookies(false);
317 HTTP_Session2::setContainer('TIP');
318 HTTP_Session2::start('TIP_Session', $user_id);
319 } else {
320 // For anonymous users, cookie with an automatic session id is used
321 HTTP_Session2::useCookies(true);
322 HTTP_Session2::start('TIP_Session');
325 HTTP_Session2::setExpire(time() + 3600*4);
326 if (HTTP_Session2::isExpired()) {
327 HTTP_Session2::destroy();
328 TIP::notifyInfo('session');
333 * Extended trim function
335 * The same as trim(), but converts '&nbsp;' and '&#160;' to spaces before
336 * trimming the string.
338 * @param string $str The string to trim
339 * @return The trimmed string
341 static public function extendedTrim($str)
343 return trim(str_replace(array('&#160', '&nbsp;'), ' ', $str));
347 * Deep addslashes()
349 * Wrappes addslashes() in a deeper form, allowing to add slashes also to
350 * embedded arrays.
352 * @param array|string $value Array or string to add slashes
353 * @return array|string The slashized copy of $value
355 static public function deepAddSlashes($value)
357 return is_array($value) ? array_map(array('TIP', 'deepAddSlashes'), $value) : addslashes($value);
361 * Deep stripslashes()
363 * Wrappes stripslashes() in a deeper form, allowing to strip slashes also
364 * to embedded arrays.
366 * @param array|string $value Array or string to strip slashes
367 * @return array|string The unslashized copy of $value
369 static public function deepStripSlashes($value)
371 return is_array($value) ? array_map(array('TIP', 'deepStripSlashes'), $value) : stripslashes($value);
375 * Deep implode()
377 * Wrappes implode() in a deeper form, allowing to implode also embedded
378 * arrays. Be careful the order of the arguments is not the same of the
379 * original implode() function. This because the array_map() recursive
380 * calls pass the array as the first argument.
382 * @param array $pieces The array to implode
383 * @param string $glue The glue to use while imploding
384 * @return string The imploded copy of $pieces
386 static public function deepImplode($pieces, $glue = null)
388 static $the_glue = null;
389 if (isset($glue)) {
390 $the_glue = $glue;
392 return is_array($pieces) ? implode($the_glue, array_map(array('TIP', 'deepImplode'), $pieces)) : $pieces;
396 * Double explode a string
398 * Given an item separator and a pair separator, performs the explode()
399 * operation twice and return the result as an associative array.
401 * The $buffer must have the following format:
402 * <code>key1{$pair_separator}value1{$item_separator}key2{$pair_separator}value2{$item_separator}...</code>
403 * If, for instance, $item_separator is ',' and $pair_separator is '=',
404 * this function will properly parse the following string:
405 * <code>key1=value1,key2=value2,key_n=value_n</code>
407 * The spaces are no stripped, so be aware to keep $buffer compact.
409 * @param string $item_separator The item separator character
410 * @param string $pair_separator The key-value separator character
411 * @param string $buffer The buffer to parse
412 * @return array|null The resulting associative array or null on errors
414 static public function doubleExplode($item_separator, $pair_separator, $buffer)
416 $items = explode($item_separator, $buffer);
417 $result = null;
418 foreach ($items as $item) {
419 @list($k, $v) = explode($pair_separator, $item, 2);
420 $result[$k] = $v;
422 return $result;
426 * Pick one or more elements from an array
428 * In the simplest case, this is equivalent to $source[$keys] but if
429 * $keys is an array, the result is an implode() of $source values
430 * having the keys specified in the $keys array. The $glue is used
431 * to join these values.
433 * This function also adds some checking on $source so return null
434 * if $source is not an array or $keys is not found.
436 * @param string|array $keys A key or an array of keys
437 * @param array &$source The source array
438 * @param string $glue The optional glue
439 * @return string|null The requested value or null if not found
441 static public function pickElement($keys, &$source, $glue = ' ')
443 if (!is_array($source)) {
444 return null;
447 if (is_string($keys)) {
448 return array_key_exists($keys, $source) ? $source[$keys] : null;
451 foreach ($keys as $key) {
452 array_key_exists($key, $source) && $values[] = $source[$key];
455 return isset($values) ? implode($glue, $values) : null;
459 * Gets a $_GET in a typesafe manner
461 * Gets a value from the superglobal $_GET array, forcing the result to
462 * $type. Also, if the current PHP installation has the "magic quote"
463 * feature turned on, the result is unslashized throught deepStripSlashes()
464 * to provide a consistent method on different PHP installations.
466 * $type can be any value accepted by settype(), that is:
468 * - 'bool' to force a boolean value
469 * - 'int' to force an integer number
470 * - 'float' to force a floating point number
471 * - 'string' to force a string
472 * - 'array' to force an array
473 * - 'object' to force an object
475 * @param string $id The get identifier
476 * @param string $type The expected type
477 * @return mixed|null The content of the requested get or null on errors
478 * @see getPost(),getCookie()
480 static public function getGet($id, $type)
482 return TIP::_getTyped($id, $type, $_GET);
486 * Get a $_POST in a typesafe manner
488 * Performs the same job as getGet(), but using the superglobal $_POST
489 * array.
491 * @param string $id The post identifier
492 * @param string $type The expected type
493 * @return mixed|null The content of the requested post or null on errors
494 * @see getGet(),getCookie()
496 static public function getPost($id, $type)
498 return TIP::_getTyped($id, $type, $_POST);
502 * Get a $_GET or $_POST in a typesafe manner
504 * Calls getGet() to retrieve the specified item and fallback to
505 * getPost() on no item found in $_GET.
507 * @param string $id The get/post identifier
508 * @param string $type The expected type
509 * @return mixed|null The requested item or null on errors
510 * @see getGet(),getPost()
512 static public function getGetOrPost($id, $type)
514 $result = TIP::_getTyped($id, $type, $_GET);
515 is_null($result) && $result = TIP::_getTyped($id, $type, $_POST);
516 return $result;
520 * Get a $_COOKIE in a typesafe manner
522 * Performs the same job as getGet(), but using the superglobal $_COOKIE
523 * array.
525 * @param string $id The cookie identifier
526 * @param string $type The expected type
527 * @return mixed|null The content of the requested cookie or null on errors
528 * @see getGet(),getPost()
530 static public function getCookie($id, $type)
532 return TIP::_getTyped($id, $type, $_COOKIE);
536 * Get the timestamp from a special date
538 * Parses $date, specified in $format format, and return the timestamp.
539 * The currently supported formats are:
540 * - 'sql' for SQL date or datetime (YYYY-MM-DD hh:mm:ss)
542 * @param mixed $date The input date
543 * @param string $format A supported date format
544 * @return int|null $date converted in timestamp or null on errors
546 static public function getTimestamp($date, $format)
548 switch ($format) {
550 case 'sql':
551 @list($year, $month, $day, $hour, $min, $sec) = sscanf($date, '%d-%d-%d %d:%d:%d');
552 return mktime($hour, $min, $sec, $month, $day, $year);
555 TIP::warning("Input time format not recognized ($format)");
556 return null;
560 * Date/time formatter
562 * Converts a date, specified in $input_format format, in the $format
563 * format and returns the result. If $input is not defined, the current
564 * time is used as input.
566 * The $format parameter can be one of the following values:
567 * - 'date' for a string with a date description (current locale)
568 * - 'date_sql' for date in common SQL format ('%Y-%m-%d')
569 * - 'date_iso8601' same as 'date_sql'
570 * - 'datetime' for a string with date and time description (current locale)
571 * - 'datetime_sql' for a string with a time description as '%Y-%m-%d %H:%M:%S'
572 * - 'datetime_iso8601' for a string with time description in ISO 8601 format
573 * - 'datetime_rfc3339' for a string as described in RFC3339 (atom format)
575 * Any other value will be passed directly to strftime().
577 * The $input_format parameter can be one of the following values:
578 * - 'timestamp' for UNIX timestamps
579 * - 'sql' for common SQL date/datetime
581 * @param string $format The format of the resulting date
582 * @param mixed $input The source date to format
583 * @param string $input_format The format of the source date
584 * @return mixed|null The formatted date or null on errors
586 static public function formatDate($format, $input = null, $input_format = 'timestamp')
588 if (is_null($input)) {
589 $timestamp = time();
590 } elseif ($input_format == 'timestamp') {
591 $timestamp = $input;
592 } else {
593 $timestamp = TIP::getTimestamp($input, $input_format);
595 return empty($timestamp) ? null : TIP::_formatTimestamp($timestamp, $format);
599 * Log a generic message
601 * Calls the TIP_Logger::log() function, if present, to log a custom
602 * message.
604 * The parameters are passed throught: this is merely a shortcut.
606 * @param string $severity The text of the log
607 * @param string $message A custom message
609 static public function log($severity, $message)
611 static $logger = false;
612 if ($logger === false && isset($GLOBALS[TIP_MAIN])) {
613 $logger =& TIP_Application::getSharedModule('logger');
616 is_object($logger) && $logger->log($severity, $message);
620 * Application warnings
622 * Logs the specified warning message (for developement purpose only)
623 * using the TIP_Logger instance, if present.
625 * The difference between warnings and errors is that errors generate a
626 * notifyError() call while warnings don't.
628 * @param string $message A custom message
630 static public function warning($message)
632 TIP::log('WARNING', $message);
636 * Application errors
638 * Logs the specified warning message (for developement purpose only)
639 * using the TIP_Logger instance, if present.
641 * The difference between warnings and errors is that errors generate a
642 * notifyError() call while warnings don't.
644 * @param string $message A custom message
646 static public function error($message)
648 TIP::log('ERROR', $message);
649 TIP::notifyError();
653 * Application fatal errors
655 * Log an error message and quits the application. This is done by
656 * redirecting the user agent to a special page.
658 * @param string $message A custom message
660 static public function fatal($message)
662 debug_print_backtrace();
663 flush();
664 TIP::log('FATAL', $message);
665 $fatal_uri = HTTP::absoluteURI(TIP_Application::getGlobal('fatal_uri'));
666 if ($fatal_uri == $_SERVER['REQUEST_URI']) {
667 // This is a recursive redirection
668 HTTP::redirect('/fatal.html');
669 } else {
670 // This is the first redirection
671 HTTP::redirect($fatal_uri);
673 exit;
677 * Error notification to the user
678 * @param string $id The notification id
679 * @return bool true on success or false on errors
681 static public function notifyError($id = 'fallback')
683 return TIP_Application::notify(TIP_SEVERITY_ERROR, $id);
687 * Warning notification to the user
688 * @param string $id The notification id
689 * @return bool true on success or false on errors
691 static public function notifyWarning($id = 'fallback')
693 return TIP_Application::notify(TIP_SEVERITY_WARNING, $id);
697 * Notification to the user
698 * @param string $id The notification id
699 * @return bool true on success or false on errors
701 static public function notifyInfo($id = 'fallback')
703 return TIP_Application::notify(TIP_SEVERITY_INFO, $id);
707 * Recursively remove a directory
708 * @param string $dir The directory to delete
709 * @param boolean $self_remove Whether to remove $dir itsself
711 static public function removeDir($dir, $self_remove = true)
713 $handle = @opendir($dir);
714 if (!$handle) {
715 return;
718 while (($file = readdir($handle)) !== false) {
719 if ($file != '.' && $file != '..') {
720 $file = $dir . DIRECTORY_SEPARATOR . $file;
721 @unlink($file) || TIP::removeDir($file);
725 closedir($handle);
726 $self_remove && @rmdir($dir);
730 * Build a path
732 * Constructs a path from the argument list and prepending the application
733 * base path.
735 * @param string|array $varargs A list of partial paths
736 * @return string The constructed path
738 static public function buildPath()
740 static $base_path = null;
741 if (is_null($base_path)) {
742 // All the paths are relative to the running script
743 $script = $_SERVER['SCRIPT_FILENAME'];
744 $base_path = rtrim(realpath(dirname($script)), DIRECTORY_SEPARATOR);
746 return TIP::deepImplode(array($base_path, func_get_args()), DIRECTORY_SEPARATOR);
750 * Build a logic path
752 * Shortcut for building a path prepending the application 'logic_root'.
754 * @param string|array $varargs A list of partial paths
755 * @return string The constructed path
757 static public function buildLogicPath()
759 static $logic_path = null;
760 if (is_null($logic_path)) {
761 $file = dirname(__FILE__);
762 $logic_path = rtrim(realpath($file), DIRECTORY_SEPARATOR);
764 return TIP::deepImplode(array($logic_path, func_get_args()), DIRECTORY_SEPARATOR);
768 * Build a template path
770 * Shortcut for building a path prepending the application 'template_root'.
772 * @param string|array $varargs A list of partial paths
773 * @return string The constructed path
775 static public function buildTemplatePath()
777 static $template_path = null;
778 if (is_null($template_path)) {
779 $engine =& TIP_Application::getGlobal('engine');
780 $template_path = TIP::buildPath($engine->getProperty('template_root'));
782 return TIP::deepImplode(array($template_path, func_get_args()), DIRECTORY_SEPARATOR);
786 * Build a template fallback path
788 * Shortcut for building a path prepending the application 'fallback_root'.
790 * @param string|array $varargs A list of partial paths
791 * @return string The constructed path
793 static public function buildFallbackPath()
795 static $fallback_path = null;
796 if (is_null($fallback_path)) {
797 $engine =& TIP_Application::getGlobal('engine');
798 $fallback_path = TIP::buildPath($engine->getProperty('fallback_root'));
800 return TIP::deepImplode(array($fallback_path, func_get_args()), DIRECTORY_SEPARATOR);
804 * Build a data path
806 * Shortcut for building a path prepending the application 'data_root'.
808 * @param string|array $varargs A list of partial paths
809 * @return string The constructed path
811 static public function buildDataPath()
813 static $path = null;
814 if (is_null($path)) {
815 $path = TIP::buildPath(TIP_Application::getGlobal('data_root'));
817 return TIP::deepImplode(array($path, func_get_args()), DIRECTORY_SEPARATOR);
821 * Build a cached path
823 * Shortcut for building a path prepending the application 'cache_root'.
825 * @param string|array $varargs A list of partial paths
826 * @return string The constructed path
828 static public function buildCachePath()
830 static $cache_path = null;
831 if (is_null($cache_path)) {
832 $cache_path = TIP::buildPath(TIP_Application::getGlobal('cache_root'));
834 return TIP::deepImplode(array($cache_path, func_get_args()), DIRECTORY_SEPARATOR);
838 * Get the absolute root of the URIs in this server
839 * @return string The URI root
841 static public function getRoot()
843 static $uri = null;
844 if (is_null($uri)) {
845 $uri = 'http://' . $_SERVER['SERVER_NAME'];
847 return $uri;
851 * Get the (relative) URI to the home page
852 * @return string The home URI
854 static public function getHome()
856 static $uri = null;
857 if (is_null($uri)) {
858 $namespace = TIP_Application::getGlobal('namespace');
859 if (is_null($namespace)) {
860 $uri = basename($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_FILENAME']);
861 } else {
862 $uri = empty($namespace) ? '' : $namespace . '/';
864 $uri = TIP::buildUri($uri);
866 return $uri;
870 * Build a relative URI
871 * @param string|array $varargs A list of partial URIs
872 * @return string The constructed URI
874 static public function buildUri()
876 static $uri = null;
877 if (is_null($uri)) {
878 // $uri is the path from the server root to this site root
879 $uri = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_FILENAME'];
880 $uri = dirname($uri);
881 substr($uri, -1) == '/' && $uri = substr($uri, 0, -1);
883 return TIP::deepImplode(array($uri, func_get_args()), '/');
887 * Build a data (relative) URI
888 * @param string|array $varargs A list of partial URIs
889 * @return string The constructed URI
891 static public function buildDataUri()
893 static $uri = null;
894 if (is_null($uri)) {
895 $uri = TIP::buildUri(TIP_Application::getGlobal('data_root'));
897 return TIP::deepImplode(array($uri, func_get_args()), '/');
901 * Build a template (relative) URI
902 * @param string|array $varargs A list of partial URIs
903 * @return string The constructed URI
905 static public function buildTemplateUri()
907 static $uri = null;
908 if (is_null($uri)) {
909 $engine =& TIP_Application::getGlobal('engine');
910 $uri = TIP::buildUri($engine->getProperty('template_root'));
912 return TIP::deepImplode(array($uri, func_get_args()), '/');
916 * Build a template fallback (relative) URI
917 * @param string|array $varargs A list of partial URIs
918 * @return string The constructed URI
920 static public function buildFallbackUri()
922 static $uri = null;
923 if (is_null($uri)) {
924 $engine =& TIP_Application::getGlobal('engine');
925 $uri = TIP::buildUri($engine->getProperty('fallback_root'));
927 return TIP::deepImplode(array($uri, func_get_args()), '/');
931 * Build an action (relative) URI
932 * @param string $module The module name
933 * @param string $action The action to perform
934 * @param string $id The subject of the action
935 * @param array $args Optional additional query arguments
936 * @return string The constructed URI
938 static public function buildActionUri($module, $action, $id = null, $args = null)
940 $uri = TIP::getHome();
942 if (empty($module) || empty($action)) {
943 empty($args) || $uri .= '?' . http_build_query($args, '', '&');
944 return $uri;
947 $namespace = TIP_Application::getGlobal('namespace');
949 if (is_null($namespace)) {
950 $args['module'] = $module;
951 $args['action'] = $action;
952 is_null($id) || $args['id'] = $id;
953 $uri .= '?' . http_build_query($args, '', '&');
954 return $uri;
957 // Strip the namespace from the module name, if present
958 if (strpos($module, $namespace . '_') === 0) {
959 $module = substr($module, strlen($namespace)+1);
962 $uri .= $module . '/' . $action;
963 is_null($id) || $uri .= '/' . $id;
964 empty($args) || $uri .= '?' . http_build_query($args, '', '&');
965 return $uri;
969 * Build an action (relative) URI
970 * @param string $tag A string in the format
971 * 'action[,id[,arg1=value1,...]]'
972 * @param string $default_module The module to use if not specified as arg
973 * @return string The constructed URI
975 static public function buildActionUriFromTag($tag, $default_module)
977 @list($action, $id, $list) = explode(',', $tag, 3);
978 empty($id) && $id = null;
980 if (is_string($list)) {
981 $list = explode(',', $list);
982 foreach ($list as $item) {
983 list($arg, $value) = explode('=', $item, 2);
984 $args[$arg] = $value;
986 } else {
987 $args = null;
990 if (isset($args['module'])) {
991 $module = $args['module'];
992 unset($args['module']);
993 } else {
994 $module = $default_module;
997 return TIP::buildActionUri($module, $action, $id, $args);
1001 * Build an action URI by modify the current action
1003 * In this case, anything different from null will be applied to the
1004 * current action. The $args array will be merged to the current one.
1006 * @param string $module The module name
1007 * @param string $action The action to perform
1008 * @param string $id The subject of the action
1009 * @param array $args Optional additional query arguments
1010 * @return string The constructed URI
1012 static public function modifyActionUri($module, $action, $id = null, $args = null)
1014 $gets = array();
1015 foreach ($_GET as $get => $value) {
1016 switch ($get) {
1017 case 'module':
1018 is_null($module) && $module = $value;
1019 break;
1020 case 'action':
1021 is_null($action) && $action = $value;
1022 break;
1023 case 'id':
1024 is_null($id) && $id = $value;
1025 break;
1026 default:
1027 $gets[$get] = $value;
1031 isset($args) && $gets = array_merge($gets, $args);
1032 return TIP::buildActionUri($module, $action, $id, $args);
1036 * Get the referer URI
1038 * The returned string is not the raw referer, but a logic referer. This
1039 * means page swapping on the same action or refreshing it does not change
1040 * the old referer.
1042 * @return string The referer URI
1044 static public function getRefererUri()
1046 static $referer_uri = null;
1047 if (is_null($referer_uri)) {
1048 $referer =& TIP_Application::getGlobal('_referer');
1049 $referer_uri = $referer['uri'];
1051 return $referer_uri;
1055 * Get the request URI
1057 * @return string The request URI
1059 static public function getRequestUri()
1061 static $request_uri = null;
1062 if (is_null($request_uri)) {
1063 $request =& TIP_Application::getGlobal('_request');
1064 $request_uri = $request['uri'];
1066 return $request_uri;
1070 * Convert to HTML a value
1072 * Converts the $value content in HTML safe manner, according to its type.
1074 * @param mixed $value The value to convert
1075 * @return string The converted value
1077 static public function toHtml($value)
1079 if (is_bool($value)) {
1080 return $value ? 'true' : 'false';
1081 } elseif (is_numeric($value)) {
1082 return (string) $value;
1083 } elseif (is_string($value)) {
1084 return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
1085 } elseif (is_array($value)) {
1086 // Canonicalize the name
1087 return TIP::toHtml(implode(',', $value));
1090 return '';
1094 * Stringify a value to its raw representation
1096 * Converts the given $value to its raw representation. This is
1097 * different from a simple (string) cast: booleans, for instance,
1098 * are converted to 'true' or 'false', not to '1' or ''.
1100 * Useful on expanding values for eval()ued code.
1102 * @param mixed $value The value to convert
1103 * @return string The converted value
1105 static public function toRaw($value)
1107 if (is_bool($value)) {
1108 return $value ? 'true' : 'false';
1109 } elseif (is_numeric($value)) {
1110 return (string) $value;
1111 } elseif (is_string($value)) {
1112 return $value;
1113 } elseif (is_array($value)) {
1114 // Canonicalize the name
1115 return TIP::toRaw(implode(',', $value));
1118 return '';
1122 * Function wrapper of the 'echo' construct
1124 * @param mixed $buffer The buffer to echo
1126 public static function echo_wrapper($buffer)
1128 echo $buffer;
1133 * Strip the TIP prefix
1135 * Removes the TIP prefix, defined in the TIP_PREFIX constant, from a
1136 * string.
1138 * @param string $id A TIP prefixed identifier
1139 * @return string The identifier without the TIP prefix
1141 static public function stripTipPrefix($id)
1143 return substr($id, strlen(TIP_PREFIX));
1147 * Gets the current user id
1149 * Returns the id of the logged in user.
1151 * @param bool $refresh Forces the update of the internal cache
1152 * @return mixed|false|null The current user id,
1153 * null for anonymous session or
1154 * false if the user module does not exist
1156 static public function getUserId($refresh = false)
1158 static $initialized = false;
1159 static $user_id;
1161 if (!$initialized || $refresh) {
1162 $user =& TIP_Application::getSharedModule('user');
1163 $user_id = is_object($user) ? @$user->keys['CID'] : false;
1164 $initialized = true;
1167 return $user_id;
1171 * Get the privilege for the specified module
1173 * Returns the privilege for a module and the specified user. If $user
1174 * is omitted, the current user id is used. Check TIP_Privilege to see how the
1175 * privileges are used.
1177 * @param string $module The requesting module identifier
1178 * @param mixed $user A user id
1179 * @return TIP_PRIVILEGE... The requested privilege
1181 static public function getPrivilege($module, $user = null)
1183 static $privilege = false;
1184 if ($privilege === false) {
1185 $privilege =& TIP_Application::getSharedModule('privilege');
1188 if ($privilege) {
1189 return $privilege->getPrivilege($module, $user);
1192 return TIP::getDefaultPrivilege($module, $user);
1196 * Get the default fallback privilege for the specified module
1198 * Returns the default privilege for a module and a specified user.
1200 * @param string $module The requesting module identifier
1201 * @param mixed $user A user id
1202 * @return TIP_PRIVILEGE... The requested privilege
1204 static public function getDefaultPrivilege($module, $user)
1206 $privilege_type = $user ? 'default_privilege' : 'anonymous_privilege';
1207 $result = @$GLOBALS['cfg'][(string) $module][$privilege_type];
1208 if (is_null($result)) {
1209 $result = TIP_Application::getGlobal($privilege_type);
1212 return $result;
1215 //}}}