1
0
mirror of https://github.com/EGroupware/egroupware.git synced 2024-12-23 07:09:20 +01:00
egroupware_official/phpgwapi/inc/horde/Horde.php

1475 lines
53 KiB
PHP
Raw Normal View History

2005-06-19 21:00:58 +02:00
<?php
include_once 'Log.php';
include_once 'Horde/Util.php';
/**
* The Horde:: class provides the functionality shared by all Horde
* applications.
*
* $Horde: framework/Horde/Horde.php,v 1.500 2005/02/15 21:26:50 chuck Exp $
*
* Copyright 1999-2005 Chuck Hagenbuch <chuck@horde.org>
* Copyright 1999-2005 Jon Parise <jon@horde.org>
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@horde.org>
* @since Horde 1.3
* @package Horde_Framework
*/
class Horde {
/**
* Logs a message to the global Horde log backend.
*
* @access public
*
* @param mixed $message Either a string or a PEAR_Error object.
* @param string $file What file was the log function called from
* (e.g. __FILE__)?
* @param integer $line What line was the log function called from
* (e.g. __LINE__)?
* @param integer $priority The priority of the message. One of:
* <pre>
* PEAR_LOG_EMERG
* PEAR_LOG_ALERT
* PEAR_LOG_CRIT
* PEAR_LOG_ERR
* PEAR_LOG_WARNING
* PEAR_LOG_NOTICE
* PEAR_LOG_INFO
* PEAR_LOG_DEBUG
* </pre>
*/
function logMessage($message, $file, $line, $priority = PEAR_LOG_INFO)
{
global $conf;
if (!$conf['log']['enabled']) {
return;
}
if ($priority > $conf['log']['priority']) {
return;
}
$logger = &Horde::getLogger();
if (!is_a($logger, 'Log')) {
Horde::fatal(PEAR::raiseError('An error has occurred. Furthermore, Horde encountered an error attempting to log this error. Please check your Horde logging configuration in horde/config/conf.php.'), __FILE__, __LINE__, false);
}
if (is_a($message, 'PEAR_Error')) {
$userinfo = $message->getUserInfo();
$message = $message->getMessage();
if (!empty($userinfo)) {
if (is_array($userinfo)) {
$userinfo = implode(', ', $userinfo);
}
$message .= ': ' . $userinfo;
}
} elseif (is_callable(array($message, 'getMessage'))) {
$message = $message->getMessage();
}
$app = isset($GLOBALS['registry']) ? $GLOBALS['registry']->getApp() : 'horde';
$message = '[' . $app . '] ' . $message . ' [on line ' . $line . ' of "' . $file . '"]';
/* Make sure to log in the system's locale. */
$locale = setlocale(LC_TIME, 0);
setlocale(LC_TIME, 'C');
$logger->log($message, $priority);
/* Restore original locale. */
setlocale(LC_TIME, $locale);
return true;
}
function &getLogger()
{
global $conf;
if (empty($conf['log']['enabled'])) {
return false;
}
static $logcheck;
if (!isset($logcheck)) {
// Try to make sure that we can log messages somehow.
if (empty($conf['log']) ||
empty($conf['log']['type']) ||
empty($conf['log']['name']) ||
empty($conf['log']['ident']) ||
!isset($conf['log']['params'])) {
Horde::fatal(PEAR::raiseError('Horde is not correctly configured to log error messages. You must configure at least a text file log in horde/config/conf.php.'), __FILE__, __LINE__, false);
}
$logcheck = true;
}
return $logger = &Log::singleton($conf['log']['type'], $conf['log']['name'],
$conf['log']['ident'], $conf['log']['params']);
}
/**
* Destroys any existing session on login and make sure to use a new
* session ID, to avoid session fixation issues. Should be called before
* checking a login.
*
* @access public
*/
function getCleanSession()
{
// Make sure to force a completely new session ID and clear
// all session data.
if (version_compare(phpversion(), '4.3.3') !== -1) {
session_regenerate_id();
session_unset();
} else {
@session_destroy();
if (Util::extensionExists('posix')) {
$new_session_id = md5(microtime() . posix_getpid());
} else {
$new_session_id = md5(uniqid(mt_rand(), true));
}
session_id($new_session_id);
// Restart the session, including setting up the session
// handler.
Horde::setupSessionHandler();
@session_start();
}
}
/**
* Aborts with a fatal error, displaying debug information to the user.
*
* @access public
*
* @param mixed $error A PEAR_Error object with debug information or an
* error message.
* @param integer $file The file in which the error occured.
* @param integer $line The line on which the error occured.
* @param boolean $log Log this message via Horde::logMesage()?
*/
function fatal($error, $file, $line, $log = true)
{
@include_once 'Horde/Auth.php';
@include_once 'Horde/CLI.php';
$admin = class_exists('Auth') && Auth::isAdmin();
$cli = class_exists('Horde_CLI') && Horde_CLI::runningFromCLI();
$errortext = '<h1>' . _("A fatal error has occurred") . '</h1>';
if (is_a($error, 'PEAR_Error')) {
$info = array_merge(array('file' => 'conf.php', 'variable' => '$conf'),
array($error->getUserInfo()));
switch ($error->getCode()) {
case HORDE_ERROR_DRIVER_CONFIG_MISSING:
$message = sprintf(_("No configuration information specified for %s."), $info['name']) . '<br />' .
sprintf(_("The file %s should contain some %s settings."),
$GLOBALS['registry']->get('fileroot') . '/config/' . $info['file'],
sprintf("%s['%s']['params']", $info['variable'], $info['driver']));
break;
case HORDE_ERROR_DRIVER_CONFIG:
$message = sprintf(_("Required '%s' not specified in %s configuration."), $info['field'], $info['name']) . '<br />' .
sprintf(_("The file %s should contain a %s setting."),
$GLOBALS['registry']->get('fileroot') . '/config/' . $info['file'],
sprintf("%s['%s']['params']['%s']", $info['variable'], $info['driver'], $info['field']));
break;
default:
$message = $error->getMessage();
break;
}
$errortext .= '<h3>' . htmlspecialchars($message) . '</h3>';
} elseif (is_object($error) && method_exists($error, 'getMessage')) {
$errortext .= '<h3>' . htmlspecialchars($error->getMessage()) . '</h3>';
} elseif (is_string($error)) {
$errortext .= '<h3>' . $error . '</h3>';
}
if ($admin) {
$errortext .= '<p><code>' . sprintf(_("[line %s of %s]"), $line, $file) . '</code></p>';
if (is_object($error)) {
$errortext .= '<h3>' . _("Details (also in Horde's logfile):") . '</h3>';
$errortext .= '<p><pre>' . htmlspecialchars(Util::bufferOutput('var_dump', $error)) . '</pre></p>';
}
} elseif ($log) {
$errortext .= '<h3>' . _("Details have been logged for the administrator.") . '</h3>';
}
// Log the error via Horde::logMessage() if requested.
if ($log) {
Horde::logMessage($error, $file, $line, PEAR_LOG_EMERG);
}
if ($cli) {
echo strip_tags(str_replace(array('<br />', '<p>', '</p>', '<h1>', '</h1>', '<h3>', '</h3>'), "\n", $errortext));
} else {
echo <<< HTML
<html>
<head><title>Horde :: Fatal Error</title></head>
<body style="background-color: white; color: black;">$errortext</body>
</html>
HTML;
}
exit;
}
/**
* Adds the javascript code to the output (if output has already started)
* or to the list of script files to include via includeScriptFiles().
*
* @access public
*
* @param string $file The full javascript file name.
* @param string $app The application name. Defaults to the current
* application.
* @param boolean $direct Include the file directly without passing it
* through javascript.php?
*/
function addScriptFile($file, $app = null, $direct = false)
{
global $registry;
static $included = array();
if (empty($app)) {
$app = $registry->getApp();
}
// Don't include scripts multiple times.
if (!empty($included[$app][$file])) {
return;
}
$included[$app][$file] = true;
if (ob_get_length() || headers_sent()) {
if ($direct) {
$url = Horde::url($file{0} == '/' ? $registry->get('webroot', $app) . $file : $registry->get('jsuri', $app) . '/' . $file);
} else {
$url = Horde::url($registry->get('webroot', 'horde') . '/services/javascript.php');
$url = Util::addParameter($url, array('file' => $file,
'app' => $app));
}
echo '<script language="JavaScript" type="text/javascript" src="' . $url . '"></script>';
} else {
global $_horde_script_files;
$_horde_script_files[$app][] = array($file, $direct);
}
}
/**
* Includes javascript files that were needed before any headers were sent.
*
* @access public
*/
function includeScriptFiles()
{
global $_horde_script_files, $registry;
if (!empty($_horde_script_files)) {
$base_url = Horde::url($registry->get('webroot', 'horde') . '/services/javascript.php');
foreach ($_horde_script_files as $app => $files) {
foreach ($files as $file) {
if (!empty($file[1])) {
$url = $file[0]{0} == '/' ? $registry->get('webroot', $app) . $file[0] : $registry->get('jsuri', $app) . '/' . $file[0];
echo '<script language="JavaScript" type="text/javascript" src="' . Horde::url($url) . "\"></script>\n";
} else {
$url = Util::addParameter($base_url, array('file' => $file[0],
'app' => $app));
echo '<script language="JavaScript" type="text/javascript" src="' . $url . "\"></script>\n";
}
}
}
}
}
/**
* Includes javascript files that were needed before any headers were sent.
*
* @access public
*/
function inlineScriptFiles()
{
global $_horde_script_files, $registry;
if (!empty($_horde_script_files)) {
$jsWrapper = $registry->get('fileroot', 'horde') . '/services/javascript.php';
foreach ($_horde_script_files as $app => $files) {
foreach ($files as $file) {
if (!empty($file[1])) {
@readfile($file[0]{0} == '/' ? $registry->get('fileroot', $app) . $file[0] : $registry->get('jsfs', $app) . '/' . $file[0]);
} else {
$file = $file[0];
require $jsWrapper;
}
}
}
}
}
/**
* Checks if link should be shown and return the nescessary code.
*
* @access public
*
* @param string $type Type of link to display
* @param string $app The name of the current Horde application.
* @param boolean $override Override Horde settings?
* @param boolean $referrer Include the current page as the referrer (url=)?
*
* @return string The HTML to create the link.
*/
function getServiceLink($type, $app, $override = false, $referrer = true)
{
if (!Horde::showService($type) && !$override) {
return false;
}
switch ($type) {
case 'help':
if ($GLOBALS['browser']->hasFeature('javascript')) {
Horde::addScriptFile('open_help_win.js', 'horde');
return "javascript:open_help_win('$app');";
} else {
$url = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/help/', true);
return Util::addParameter($url, array('module' => $app,
'show' => 'topics'));
}
break;
case 'problem':
return Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/problem.php?return_url=' . urlencode(Horde::selfUrl(true)));
case 'logout':
return Auth::addLogoutParameters(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/login.php'), AUTH_REASON_LOGOUT);
case 'login':
return Auth::getLoginScreen('', $referrer ? Horde::selfUrl(true) : null);
case 'options':
global $conf;
if (($conf['prefs']['driver'] != '') && ($conf['prefs']['driver'] != 'none')) {
return Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/prefs.php?app=' . $app);
}
break;
}
return false;
}
/**
* @access public
*
* @param string $type The type of link.
*
* @return boolean True if the link is to be shown.
*/
function showService($type)
{
global $conf;
if (empty($conf['menu']['links'][$type])) {
return false;
}
switch ($conf['menu']['links'][$type]) {
case 'all':
return true;
case 'never':
return false;
case 'authenticated':
return (bool)Auth::getAuth();
default:
return false;
}
}
/**
* Returns the driver parameters for the specified backend.
*
* @param mixed $backend The backend system (e.g. 'prefs', 'categories',
* 'contacts') being used.
* The used configuration array will be
* $conf[$backend]. If an array gets passed, it will
* be $conf[$key1][$key2].
* @param string $type The type of driver.
*
* @return array The connection parameters.
*/
function getDriverConfig($backend, $type = 'sql')
{
global $conf;
$c = null;
if (is_array($backend)) {
require_once 'Horde/Array.php';
$c = Horde_Array::getElement($conf, $backend);
} elseif (isset($conf[$backend])) {
$c = $conf[$backend];
}
if (!is_null($c) && isset($c['params'])) {
if (isset($conf[$type])) {
return array_merge($conf[$type], $c['params']);
} else {
return $c['params'];
}
}
return isset($conf[$type]) ? $conf[$type] : array();
}
/**
* Returns the VFS driver parameters for the specified backend.
*
* @param string $name The VFS system name (e.g. 'images', 'documents')
* being used.
*
* @return array A hash with the VFS parameters; the VFS driver in 'type'
* and the connection parameters in 'params'.
*/
function getVFSConfig($name)
{
global $conf;
if (!isset($conf[$name]['type'])) {
return PEAR::raiseError(_("You must configure a VFS backend."));
}
if ($conf[$name]['type'] == 'horde') {
$vfs = $conf['vfs'];
} else {
$vfs = $conf[$name];
}
if ($vfs['type'] == 'sql') {
$vfs['params'] = Horde::getDriverConfig($name, 'sql');
}
return $vfs;
}
/**
* Checks if all necessary parameters for a driver configuration
* are set and throws a fatal error with a detailed explaination
* how to fix this, if something is missing.
*
* @param array $params The configuration array with all parameters.
* @param string $driver The key name (in the configuration array) of
* the driver.
* @param array $fields An array with mandatory parameter names for
* this driver.
* @param string $name The clear text name of the driver. If not
* specified, the application name will be used.
* @param string $file The configuration file that should contain
* these settings.
* @param string $variable The name of the configuration variable.
*/
function assertDriverConfig($params, $driver, $fields, $name = null,
$file = 'conf.php', $variable = '$conf')
{
global $registry;
// Don't generate a fatal error if we fail during or before
// Registry instantiation.
if (is_null($name)) {
$name = isset($registry) ? $registry->getApp() : '[unknown]';
}
$fileroot = isset($registry) ? $registry->get('fileroot') : '';
if (!is_array($params) || !count($params)) {
Horde::fatal(PEAR::raiseError(
sprintf(_("No configuration information specified for %s."), $name) . "\n\n" .
sprintf(_("The file %s should contain some %s settings."),
$fileroot . '/config/' . $file,
sprintf("%s['%s']['params']", $variable, $driver))),
__FILE__, __LINE__);
}
foreach ($fields as $field) {
if (!isset($params[$field])) {
Horde::fatal(PEAR::raiseError(
sprintf(_("Required '%s' not specified in %s configuration."), $field, $name) . "\n\n" .
sprintf(_("The file %s should contain a %s setting."),
$fileroot . '/config/' . $file,
sprintf("%s['%s']['params']['%s']", $variable, $driver, $field))),
__FILE__, __LINE__);
}
}
}
/**
* Returns a session-id-ified version of $uri.
* If a full URL is requested, all parameter separators get converted to
* "&", otherwise to "&amp;".
*
* @access public
*
* @param string $uri The URI to be modified.
* @param bool $full Generate a full (http://server/path/) URL.
* @param int $append_session 0 = only if needed, 1 = always, -1 = never.
*
* @return string The URL with the session id appended (if needed).
*/
function url($uri, $full = false, $append_session = 0, $force_ssl = false)
{
if ($force_ssl) {
$full = true;
}
if ($full) {
global $conf, $registry, $browser;
/* Store connection parameters in local variables. */
$server_name = $conf['server']['name'];
$server_port = $conf['server']['port'];
$protocol = 'http';
if ($conf['use_ssl'] == 1) {
$protocol = 'https';
} elseif ($conf['use_ssl'] == 2 &&
$browser->usingSSLConnection()) {
$protocol = 'https';
} elseif ($conf['use_ssl'] == 3) {
$server_port = '';
if ($force_ssl) {
$protocol = 'https';
}
}
/* If using non-standard ports, add the port to the URL. */
if (!empty($server_port) &&
((($protocol == 'http') && ($server_port != 80)) ||
(($protocol == 'https') && ($server_port != 443)))) {
$server_name .= ':' . $server_port;
}
/* Store the webroot in a local variable. */
$webroot = $registry->get('webroot');
$url = $protocol . '://' . $server_name;
if (substr($uri, 0, 1) != '/') {
if (substr($webroot, -1) == '/') {
$url .= $webroot . $uri;
} else {
$url .= $webroot . '/' . $uri;
}
} else {
$url .= $uri;
}
} else {
$url = $uri;
}
if (($append_session == 1) ||
(($append_session == 0) &&
!isset($_COOKIE[session_name()]))) {
$url = Util::addParameter($url, session_name(), session_id());
}
if ($full) {
/* We need to run the replace twice, because we only catch every
* second match. */
return preg_replace(array('/(=?.*?)&amp;(.*?=)/',
'/(=?.*?)&amp;(.*?=)/'),
'$1&$2', $url);
} elseif (preg_match('/=.*&amp;.*=/', $url)) {
return $url;
} else {
return htmlentities($url);
}
}
/**
* Returns a session-id-ified version of $uri, using the current
* application's webroot setting.
*
* @access public
*
* @param string $uri The URI to be modified.
* @param bool $full Generate a full (http://server/path/) URL.
* @param int $append_session 0 = only if needed, 1 = always, -1 = never.
*
* @return string The url with the session id appended.
*/
function applicationUrl($uri, $full = false, $append_session = 0)
{
global $registry;
/* Store the webroot in a local variable. */
$webroot = $registry->get('webroot');
if ($full) {
return Horde::url($uri, $full, $append_session);
} elseif (substr($webroot, -1) == '/') {
return Horde::url($webroot . $uri, $full, $append_session);
} else {
return Horde::url($webroot . '/' . $uri, $full, $append_session);
}
}
/**
* Returns an external link passed through the dereferer to strip session
* IDs from the referer.
*
* @param string $url The external URL to link to.
* @param boolean $tag If true, a complete <a> tag is returned, only the
* url otherwise.
*
* @return string The correct link to the dereferer script.
*/
function externalUrl($url, $tag = false)
{
$ext = Horde::url($GLOBALS['registry']->get('webroot', 'horde') .
'/services/go.php', true, -1);
/* We must make sure there are no &amp's in the URL. */
$url = preg_replace(array('/(=?.*?)&amp;(.*?=)/', '/(=?.*?)&amp;(.*?=)/'), '$1&$2', $url);
$ext = Util::addParameter($ext, 'url', $url);
if ($tag) {
$ext = Horde::link($ext, $url, '', '_blank');
}
return $ext;
}
/**
* Returns a URL to be used for downloading, that takes into account any
* special browser quirks (i.e. IE's broken filename handling).
*
* @access public
*
* @param string $filename The filename of the download data.
* @param array $params Any additional parameters needed.
* @param string $url The URL to alter. If none passed in, will use
* the file 'view.php' located in the current
* module's base directory.
*
* @return string The download URL.
*/
function downloadUrl($filename, $params = array(), $url = null)
{
global $browser;
$horde_url = false;
if (is_null($url)) {
global $registry;
$url = Util::addParameter(Horde::url($registry->get('webroot', 'horde') . '/services/download/'), 'module', $registry->getApp());
$horde_url = true;
}
/* Add parameters. */
if (!is_null($params)) {
foreach ($params as $key => $val) {
$url = Util::addParameter($url, $key, $val);
}
}
/* If we are using the default Horde download link, add the
* filename to the end of the URL. Although not necessary for
* many browsers, this should allow every browser to download
* correctly. */
if ($horde_url) {
$url = Util::addParameter($url, 'fn=/' . rawurlencode($filename));
} elseif ($browser->hasQuirk('break_disposition_filename')) {
/* Some browsers will only obtain the filename correctly
* if the extension is the last argument in the query
* string and rest of the filename appears in the
* PATH_INFO element. */
$filename = rawurlencode($filename);
/* Get the webserver ID. */
$server = Horde::webServerID();
/* Get the name and extension of the file. Apache 2 does
* NOT support PATH_INFO information being passed to the
* PHP module by default, so disable that
* functionality. */
if (($server != 'apache2')) {
if (($pos = strrpos($filename, '.'))) {
$name = '/' . preg_replace('/\./', '%2E', substr($filename, 0, $pos));
$ext = substr($filename, $pos);
} else {
$name = '/' . $filename;
$ext = '';
}
/* Enter the PATH_INFO information. */
if (($pos = strpos($url, '?'))) {
$url = substr($url, 0, $pos) . $name . substr($url, $pos);
} else {
$url .= $name;
}
}
/* Append the extension, if it exists. */
if (($server == 'apache2') || !empty($ext)) {
$url = Util::addParameter($url, 'fn_ext=/' . $filename);
}
}
return $url;
}
/**
* Returns an anchor tag with the relevant parameters
*
* @access public
*
* @param string $url The full URL to be linked to
* @param string $status The JavaScript mouse-over string
* @param string $class The CSS class of the link
* @param string $target The window target to point to.
* @param string $onclick JavaScript action for the 'onclick' event.
* @param string $title The link title (tooltip).
* @param string $accesskey The access key to use.
* @param array $attributes Any other name/value pairs to add to the <a>
* tag.
*
* @return string The full <a href> tag.
*/
function link($url, $status = '', $class = '', $target = '', $onclick = '',
$title = '', $accesskey = '', $attributes = array())
{
$ret = "<a href=\"$url\"";
if (!empty($onclick)) {
$ret .= " onclick=\"$onclick\"";
}
if (!empty($status)) {
$ret .= ' onmouseout="window.status=\'\';" onmouseover="window.status=\'' . @htmlspecialchars(strtr(addslashes($status), array("\r" => '', "\n" => '')), ENT_QUOTES, NLS::getCharset()) . '\'; return true;"';
}
if (!empty($class)) {
$ret .= " class=\"$class\"";
}
if (!empty($target)) {
$ret .= " target=\"$target\"";
}
if (!empty($title)) {
$ret .= ' title="' . @htmlspecialchars($title, ENT_QUOTES, NLS::getCharset()) . '"';
}
if (!empty($accesskey)) {
$ret .= ' accesskey="' . htmlspecialchars($accesskey) . '"';
}
foreach ($attributes as $name => $value) {
$ret .= ' ' . htmlspecialchars($name) . '="' . htmlspecialchars($value) . '"';
}
return "$ret>";
}
/**
* Returns an anchor sequence with the relevant parameters for a widget
* with accesskey and text.
*
* @access public
*
* @param string $url The full URL to be linked to
* @param string $status The JavaScript mouse-over string
* @param string $class The CSS class of the link
* @param string $target The window target to point to.
* @param string $onclick JavaScript action for the 'onclick' event.
* @param string $title The link title (tooltip).
* @param boolean $nocheck Don't check if the access key already has been
* used?
*
* @return string The full <a href>Title</a> sequence.
*/
function widget($url, $status = '', $class = 'widget', $target = '',
$onclick = '', $title = '', $nocheck = false)
{
$ak = Horde::getAccessKey($title, $nocheck);
$plaintitle = Horde::stripAccessKey($title);
return Horde::link($url, $status, $class, $target, $onclick, $plaintitle, $ak) . Horde::highlightAccessKey($title, $ak) . '</a>';
}
/**
* Returns a session-id-ified version of $PHP_SELF.
*
* @access public
*
* @param boolean $query_string Include any QUERY_STRING?
* @param boolean $nocache Include a nocache parameter in the URL?
* @param boolean $full Return a full URL?
*
* @return string The requested URI.
*/
function selfUrl($query_string = false, $nocache = true, $full = false,
$force_ssl = false)
{
$url = $_SERVER['PHP_SELF'];
if ($query_string && !empty($_SERVER['QUERY_STRING'])) {
$url .= '?' . $_SERVER['QUERY_STRING'];
}
$url = Horde::url($url, $full, 0, $force_ssl);
if ($nocache) {
return Util::nocacheUrl($url);
} else {
return $url;
}
}
/**
* Constructs a correctly-pathed link to an image.
*
* @access public
*
* @param string $src The image file.
* @param optional string $alt Text describing the image.
* @param optional mixed $attr Any additional attributes for the image tag.
* Can be a pre-built string or an array of key/value
* pairs that will be assembled and html-encoded.
* @param optional string $dir The root graphics directory.
*
* @return string The full image tag.
*/
function img($src, $alt = '', $attr = '', $dir = null)
{
/* If browser does not support images, simply return the ALT text. */
if (!$GLOBALS['browser']->hasFeature('images')) {
return @htmlspecialchars($alt, ENT_COMPAT, NLS::getCharset());
}
/* If no directory has been specified, get it from the registry. */
if ($dir === null) {
global $registry;
$dir = $registry->getImageDir();
}
/* If a directory has been provided, prepend it to the image source. */
if (!empty($dir)) {
$src = $dir . '/' . $src;
}
/* Build all of the tag attributes. */
$attributes = array('src' => $src,
'alt' => $alt,
'title' => $alt);
if (is_array($attr)) {
$attributes = array_merge($attributes, $attr);
}
$img = '<img';
foreach ($attributes as $attribute => $value) {
$img .= ' ' . $attribute . '="' . ($attribute == 'src' ? $value : @htmlspecialchars($value, ENT_COMPAT, NLS::getCharset())) . '"';
}
/* If the user supplied a pre-built string of attributes, add that. */
if (is_string($attr) && !empty($attr)) {
$img .= ' ' . $attr;
}
/* Return the closed image tag. */
return $img . ' />';
}
/**
* Determines the location of the system temporary directory. If a specific
* setting cannot be found, it defaults to /tmp.
*
* @access public
*
* @return string A directory name which can be used for temp files.
* Returns false if one could not be found.
*/
function getTempDir()
{
global $conf;
/* If one has been specifically set, then use that */
if (!empty($conf['tmpdir'])) {
$tmp = $conf['tmpdir'];
}
/* Next, try Util::getTempDir(). */
if (empty($tmp)) {
$tmp = Util::getTempDir();
}
/* If it is still empty, we have failed, so return false;
* otherwise return the directory determined. */
return empty($tmp) ? false : $tmp;
}
/**
* Creates a temporary filename for the lifetime of the script, and
* (optionally) registers it to be deleted at request shutdown.
*
* @access public
*
* @param string $prefix Prefix to make the temporary name more
* recognizable.
* @param boolean $delete Delete the file at the end of the request?
* @param string $dir Directory to create the temporary file in.
* @param boolean $secure If deleting file, should we securely delete the
* file?
*
* @return string Returns the full path-name to the temporary file or
* false if a temporary file could not be created.
*/
function getTempFile($prefix = 'Horde', $delete = true, $dir = '',
$secure = false)
{
if (empty($dir) || !is_dir($dir)) {
$dir = Horde::getTempDir();
}
return Util::getTempFile($prefix, $delete, $dir, $secure);
}
/**
* Starts output compression, if requested.
*
* @access public
*
* @since Horde 2.2
*/
function compressOutput()
{
static $started;
if (isset($started)) {
return;
}
/* Compress output if requested and possible. */
if ($GLOBALS['conf']['compress_pages'] &&
!$GLOBALS['browser']->hasQuirk('buggy_compression') &&
ini_get('zlib.output_compression') == '' &&
ini_get('output_handler') != 'ob_gzhandler') {
if (ob_get_level()) {
ob_end_clean();
}
ob_start('ob_gzhandler');
}
$started = true;
}
/**
* Determines if output compression can be used.
*
* @access public
*
* @return boolean True if output compression can be used, false if not.
*/
function allowOutputCompression()
{
require_once 'Horde/Browser.php';
$browser = &Browser::singleton();
/* Turn off compression for buggy browsers. */
if ($browser->hasQuirk('buggy_compression')) {
return false;
}
return (ini_get('zlib.output_compression') == '' &&
ini_get('output_handler') != 'ob_gzhandler');
}
/**
* Returns the Web server being used.
* PHP string list built from the PHP 'configure' script.
*
* @access public
*
* @return string A web server identification string.
* <pre>
* 'aolserver' = AOL Server
* 'apache1' = Apache 1.x
* 'apache2' = Apache 2.x
* 'caudium' = Caudium
* 'cgi' = Unknown server - PHP built as CGI program
* 'cli' = Command Line Interface build
* 'embed' = Embedded PHP
* 'isapi' = Zeus ISAPI
* 'milter' = Milter
* 'nsapi' = NSAPI
* 'phttpd' = PHTTPD
* 'pi3web' = Pi3Web
* 'roxen' = Roxen/Pike
* 'servlet' = Servlet
* 'thttpd' = thttpd
* 'tux' = Tux
* 'webjames' = Webjames
* </pre>
*/
function webServerID()
{
$server = php_sapi_name();
if ($server == 'apache') {
return 'apache1';
} elseif (($server == 'apache2filter') ||
($server == 'apache2handler')) {
return 'apache2';
} else {
return $server;
}
}
/**
* Returns the <link> tags for the CSS stylesheets.
*
* @access public
*
* @param string|array $app The Horde application(s).
* @param mixed $theme The theme to use; specify an empty value to
* retrieve the theme from user preferences, and
* false for no theme.
* @param boolean $inherit Inherit Horde-wide CSS?
*
* @return string <link> tags for CSS stylesheets.
*/
function stylesheetLink($apps = null, $theme = '', $inherit = true)
{
if ($theme !== false && empty($theme)) {
$theme = $GLOBALS['prefs']->getValue('theme');
}
$css = array();
$themes_fs = $GLOBALS['registry']->get('themesfs', 'horde');
if ($inherit) {
$themes_uri = Horde::url($GLOBALS['registry']->get('themesuri', 'horde'), false, -1);
$css[] = $themes_uri . '/screen.css';
if (!empty($theme) &&
file_exists($themes_fs . '/' . $theme . '/screen.css')) {
$css[] = $themes_uri . '/' . $theme . '/screen.css';
}
}
if (!empty($apps)) {
if (!is_array($apps)) {
$apps = array($apps);
}
foreach ($apps as $app) {
if ($inherit && $app == 'horde') {
continue;
}
$themes_fs = $GLOBALS['registry']->get('themesfs', $app);
if (file_exists($themes_fs . '/screen.css')) {
$themes_uri = Horde::url($GLOBALS['registry']->get('themesuri', $app), false, -1);
$css[] = $themes_uri . '/screen.css';
}
if (!empty($theme) &&
file_exists($themes_fs . '/' . $theme . '/screen.css')) {
$css[] = $themes_uri . '/' . $theme . '/screen.css';
}
}
}
$html = '';
foreach ($css as $css_link) {
$html .= '<link href="' . $css_link . '" rel="stylesheet" type="text/css" />' . "\n";
}
/* Load IE PNG transparency code if needed. */
if ($GLOBALS['browser']->hasQuirk('png_transparency') &&
$GLOBALS['prefs']->getValue('alpha_filter')) {
$url = Horde::url($GLOBALS['registry']->get('jsuri', 'horde') . '/alphaImageLoader.php', true, -1);
$html .= '<style type="text/css"> img { behavior: url("' . $url . '"); } </style>';
}
/* Load browser specific stylesheets if needed. */
if ($GLOBALS['browser']->isBrowser('msie')) {
$html .= '<link href="' . $GLOBALS['registry']->get('themesuri', 'horde') . '/ie.css" rel="stylesheet" type="text/css" />' . "\n";
if ($GLOBALS['browser']->getPlatform() == 'mac') {
$html .= '<link href="' . $GLOBALS['registry']->get('themesuri', 'horde') . '/ie5mac.css" rel="stylesheet" type="text/css" />' . "\n";
}
}
if ($GLOBALS['browser']->isBrowser('opera')) {
$html .= '<link href="' . $GLOBALS['registry']->get('themesuri', 'horde') . '/opera.css" rel="stylesheet" type="text/css" />' . "\n";
}
if (strpos(strtolower($GLOBALS['browser']->getAgentString()), 'safari') !== false) {
$html .= '<link href="' . $GLOBALS['registry']->get('themesuri', 'horde') . '/safari.css" rel="stylesheet" type="text/css" />' . "\n";
}
return $html;
}
/**
* Sets a custom session handler up, if there is one.
*
* @access public
*/
function setupSessionHandler()
{
global $conf;
ini_set('url_rewriter.tags', 0);
session_set_cookie_params($conf['session']['timeout'],
$conf['cookie']['path'], $conf['cookie']['domain'], $conf['use_ssl'] == 1 ? 1 : 0);
session_cache_limiter($conf['session']['cache_limiter']);
session_name(urlencode($conf['session']['name']));
$type = !empty($conf['sessionhandler']['type']) ? $conf['sessionhandler']['type'] : 'none';
if ($type == 'external') {
$calls = $conf['sessionhandler']['params'];
session_set_save_handler($calls['open'],
$calls['close'],
$calls['read'],
$calls['write'],
$calls['destroy'],
$calls['gc']);
} elseif ($type != 'none') {
global $_session_handler;
require_once 'Horde/SessionHandler.php';
$_session_handler = &SessionHandler::singleton($conf['sessionhandler']['type']);
if (!empty($_session_handler) &&
!is_a($_session_handler, 'PEAR_Error')) {
ini_set('session.save_handler', 'user');
session_set_save_handler(array(&$_session_handler, 'open'),
array(&$_session_handler, 'close'),
array(&$_session_handler, 'read'),
array(&$_session_handler, 'write'),
array(&$_session_handler, 'destroy'),
array(&$_session_handler, 'gc'));
} else {
Horde::fatal(PEAR::raiseError('Horde is unable to correctly start the custom session handler.'), __FILE__, __LINE__, false);
}
}
}
/**
* Returns an un-used access key from the label given.
*
* @access public
*
* @param string $label The label to choose an access key from.
* @param boolean $nocheck Don't check if the access key already has been
* used?
*
* @return string A single lower case character access key or empty
* string if none can be found
*/
function getAccessKey($label, $nocheck = false, $shutdown = false)
{
/* The access keys already used in this page */
static $_used = array();
/* The labels already used in this page */
static $_labels = array();
/* Shutdown call for translators? */
if ($shutdown) {
if (!count($_labels)) {
return;
}
$script = basename($_SERVER['PHP_SELF']);
$labels = array_keys($_labels);
sort($labels);
$used = array_keys($_used);
sort($used);
$remaining = str_replace($used, array(), 'abcdefghijklmnopqrstuvwxyz');
Horde::logMessage('Access key information for ' . $script, __FILE__, __LINE__);
Horde::logMessage('Used labels: ' . implode(',', $labels), __FILE__, __LINE__);
Horde::logMessage('Used keys: ' . implode('', $used), __FILE__, __LINE__);
Horde::logMessage('Free keys: ' . $remaining, __FILE__, __LINE__);
return;
}
/* Use access keys at all? */
static $notsupported;
if (!isset($notsupported)) {
$notsupported = !$GLOBALS['browser']->hasFeature('accesskey') ||
!$GLOBALS['prefs']->getValue('widget_accesskey');
}
if ($notsupported || !preg_match('/_([A-Za-z])/', $label, $match)) {
return '';
}
$key = $match[1];
/* Has this key already been used? */
if (isset($_used[strtolower($key)]) &&
!($nocheck && isset($_labels[$label]))) {
return '';
}
/* Save key and label. */
$_used[strtolower($key)] = true;
$_labels[$label] = true;
return $key;
}
/**
* Strips an access key from a label.
* For multibyte charset strings the access key gets removed completely,
* otherwise only the underscore gets removed.
*
* @access public
*
* @param string $label The label containing an access key.
*
* @return string The label with the access key being stripped.
*/
function stripAccessKey($label)
{
include_once HORDE_BASE . '/config/nls.php';
$multibyte = isset($GLOBALS['nls']['multibyte'][NLS::getCharset(true)]);
return preg_replace('/_([A-Za-z])/',
$multibyte && preg_match('/[\x80-\xff]/', $label) ? '' : '\1',
$label);
}
/**
* Highlights an access key in a label.
*
* @access public
*
* @param string $label The label to to highlight the access key in.
* @param string $accessKey The access key to highlight.
*
* @return string The HTML version of the label with the access key
* highlighted.
*/
function highlightAccessKey($label, $accessKey)
{
$stripped_label = Horde::stripAccesskey($label);
if (empty($accessKey)) {
return $stripped_label;
}
if (isset($GLOBALS['nls']['multibyte'][NLS::getCharset(true)])) {
return $stripped_label . '(' . '<span class="accessKey">' .
strtoupper($accessKey) . '</span>' . ')';
} else {
return str_replace('_' . $accessKey, '<span class="accessKey">' . $accessKey . '</span>', $label);
}
}
/**
* Returns the appropriate "accesskey" and "title" attributes for an HTML
* tag and the given label.
*
* @param string $label The title of an HTML element
* @param boolean $nocheck Don't check if the access key already has been
* used?
*
* @return string The title, and if appropriate, the accesskey attributes
* for the element.
*/
function getAccessKeyAndTitle($label, $nocheck = false)
{
$ak = Horde::getAccessKey($label, $nocheck);
$attributes = 'title="' . Horde::stripAccessKey($label);
if (!empty($ak)) {
$attributes .= sprintf(_(" (Accesskey %s)"), $ak);
$attributes .= '" accesskey="' . $ak;
}
$attributes .= '"';
return $attributes;
}
/**
* Returns a label element including an access key for usage in conjuction
* with a form field. User preferences regarding access keys are respected.
*
* @param string $for The form field's id attribute.
* @param string $label The label text.
* @param string $ak The access key to use. If null a new access key
* will be generated.
*
* @return string The html code for the label element.
*/
function label($for, $label, $ak = null)
{
global $prefs;
if (is_null($ak)) {
$ak = Horde::getAccesskey($label, 1);
}
$label = Horde::highlightAccessKey($label, $ak);
return sprintf('<label for="%s"%s>%s</label>',
$for,
!empty($ak) ? ' accesskey="' . $ak . '"' : '',
$label);
}
/**
* Redirects to the main Horde login page on authentication failure.
*
* @access public
*/
function authenticationFailureRedirect()
{
require_once 'Horde/CLI.php';
if (Horde_CLI::runningFromCLI()) {
$cli = &Horde_CLI::singleton();
$cli->fatal(_("You are not authenticated."));
}
$url = $GLOBALS['registry']->get('webroot', 'horde') . '/login.php';
$url = Util::addParameter($url, 'url', Horde::selfUrl(true));
$url = Auth::addLogoutParameters($url);
header('Location: ' . Horde::url($url, true));
exit;
}
/**
* Uses DOM Tooltips (via javascript) to display the 'title'
* attribute for Horde::link() calls.
*
* If using this function, the following function must be called:
* Horde::addScriptFile('tooltip.js', 'horde', true);
*
* @access public
*
* @param string $url The full URL to be linked to
* @param string $status The JavaScript mouse-over string
* @param string $class The CSS class of the link
* @param string $target The window target to point to.
* @param string $onclick JavaScript action for the 'onclick' event.
* @param string $title The link title (tooltip).
* @param string $accesskey The access key to use.
* @param array $attributes Any other name/value pairs to add to the <a>
* tag.
*
* @return string The full <a href> tag.
*/
function linkTooltip($url, $status = '', $class = '', $target = '',
$onclick = '', $title = '', $accesskey = '',
$attributes = array())
{
$url = substr(Horde::link($url, null, $class, $target, $onclick, null, $accesskey, $attributes), 0, -1);
if (strlen($status)) {
$status = @htmlspecialchars(addslashes($status), ENT_QUOTES, NLS::getCharset());
}
$title = trim($title);
if (strlen($title)) {
require_once 'Horde/Text/Filter.php';
$title = Text_Filter::filter($title, 'text2html', array('parselevel' => TEXT_HTML_NOHTML, 'charset' => '', 'class' => ''));
$title = '<pre style="margin:0px;">' . strtr(addslashes($title), array("\r" => '', "\n" => '')) . '</pre>';
$url .= ' onmouseover="tooltipLink(\'' . @htmlspecialchars($title, ENT_QUOTES, NLS::getCharset()) . '\', \'' . $status . '\'); return true;" onmouseout="tooltipClose();"';
}
$url .= '>';
return $url;
}
/**
* Provides a standardised function to call a Horde hook, checking whether
* a hook config file exists and whether the function itself exists. If
* these two conditions are not satisfied it will return the specified
* value (by default a PEAR error).
*
* @access public
*
* @param string $hook The function to call.
* @param array $args An array of any arguments to pass to the hook
* function.
* @param string $app If specified look for hooks in the config directory
* of this app.
* @param mixed $error What to return if $app/config/hooks.php or $hook
* does not exist. If this is the string 'PEAR_Error'
* a PEAR error object is returned instead, detailing
* the failure.
*
* @return mixed Either the results of the hook or PEAR error on failure.
*/
function callHook($hook, $args = array(), $app = 'horde', $error = 'PEAR_Error')
{
global $registry;
static $hooks_loaded;
if (!isset($hooks_loaded)) {
if (file_exists($registry->get('fileroot', $app) . '/config/hooks.php')) {
require_once $registry->get('fileroot', $app) . '/config/hooks.php';
$hooks_loaded = true;
} else {
$hooks_loaded = false;
}
}
if ($hooks_loaded && function_exists($hook)) {
return call_user_func_array($hook, $args);
}
if (is_string($error) && strcmp($error, 'PEAR_Error') == 0) {
$error = PEAR::raiseError(sprintf('Hook %s in application %s not called.', $hook, $app));
Horde::logMessage($error, __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
return $error;
}
/**
* Return the initial page to load when accessing Horde.
*
* @return string The URL of the initial page.
*/
function initialPage()
{
global $prefs, $registry, $perms;
$initial_app = $prefs->getValue('initial_application');
if (!empty($initial_app) && $registry->hasPermission($initial_app)) {
return Horde::url($registry->getInitialPage($initial_app), true);
} elseif (isset($registry->applications['horde']['initial_page'])) {
return Horde::applicationUrl($registry->applications['horde']['initial_page'], true);
} elseif (Auth::getAuth()) {
return Horde::applicationUrl('services/portal/', true);
} else {
return Horde::applicationUrl('login.php', true);
}
}
/**
* Returns an array of available menu items when in a Horde script.
*
* @return array Available menu items.
*/
function getHordeMenu()
{
global $registry, $prefs;
$menu = array();
/* The home page button. If an initial application has been set in the
* prefs this will default to that application. Otherwise it will go
* to the portal screen. */
$initial_app = $prefs->getValue('initial_application');
if (!empty($initial_app)) {
$url = Horde::url($registry->getInitialPage($initial_app));
} else {
$url = Horde::applicationUrl('services/portal/');
}
$menu[] = array('url' => $url,
'text' => _("Home"),
'icon' => 'horde.png',
'icon_path' => $registry->getImageDir());
if (Auth::isAdmin()) {
$menu[] = array('url' => Horde::applicationUrl('admin/'),
'text' => _("_Administration"),
'icon' => 'administration.png',
'icon_path' => $registry->getImageDir());
}
return $menu;
}
}