move egw and applications class to api including (common_)functions.inc.php

This commit is contained in:
Ralf Becker 2016-04-26 14:38:08 +00:00
parent 7cb470d904
commit 8315cbfee0
14 changed files with 2982 additions and 2921 deletions

601
api/src/Egw.php Normal file
View File

@ -0,0 +1,601 @@
<?php
/**
* EGroupware API - Applications
*
* @link http://www.egroupware.org
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
* Parts Copyright (C) 2003 Free Software Foundation
* @author RalfBecker@outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @version $Id$
*/
namespace EGroupware\Api;
// explicitly list old, non-namespaced classes
// they are only used, if phpgwapi is installed
use accounts;
use egw_session;
/**
* New written class to create the eGW enviroment AND restore it from a php-session
*
* Rewritten by RalfBecker@outdoor-training.de to store the eGW enviroment
* (egw-object and egw_info-array) in a php-session and restore it from
* there instead of creating it completly new on each page-request.
* The enviroment gets now created by the egw-class
*
* Extending Egw\Base which uses now a getter method to create the usual subobject on demand,
* to allow a quicker header include on sites not using php4-restore.
* This also makes a lot of application code, like the following, unnecessary:
* if (!is_object($GLOBALS['egw']->ldap)
* {
* $GLOBALS['egw']->ldap = Api\Ldap::factory();
* }
* You can now simply use $GLOBALS['egw']->ldap, and the egw class instanciates it for you on demand.
*/
class Egw extends Egw\Base
{
/**
* Turn on debug mode. Will output additional data for debugging purposes.
* @var string
* @access public
*/
var $debug = 0; // This will turn on debugging information.
/**
* Instance of the account object
*
* @var Accounts
*/
var $accounts;
/**
* Constructor: Instantiates the sub-classes
*
* @author RalfBecker@outdoor-training.de
* @param array $domain_names array with valid egw-domain names
*/
function __construct($domain_names=null)
{
$GLOBALS['egw'] =& $this; // we need to be immediately available there for the other classes we instantiate
$this->setup($domain_names,True);
}
/**
* Called every time the constructor is called. Also called by sessions to ensure the correct db,
* in which case we do not recreate the session object.
* @author RalfBecker@outdoor-training.de (moved to setup() by milos@groupwhere.org
* @param array $domain_names array with valid egw-domain names
* @param boolean $createsessionobject True to create the session object (default=True)
*/
function setup($domain_names,$createsessionobject=True)
{
// create the DB-object
// as SiteMgr, Wiki, KnowledgeBase and probably more still use eg next_record(), we stick with Db\Deprecated for now
$this->db = new Db\Deprecated($GLOBALS['egw_info']['server']);
if ($this->debug)
{
$this->db->Debug = 1;
}
$this->db->set_app(Db::API_APPNAME);
// check if eGW is already setup, if not redirect to setup/
try {
$this->db->connect();
$num_config = $this->db->select(Config::TABLE,'COUNT(config_name)',false,__LINE__,__FILE__)->fetchColumn();
}
catch(Db\Exception\Connection $e) {
// ignore exception, get handled below
}
catch(Db\Exception\InvalidSql $e1) {
unset($e1); // not used
try {
$phpgw_config = $this->db->select('phpgw_config','COUNT(config_name)',false,__LINE__,__FILE__)->fetchColumn();
}
catch (Db\Exception\InvalidSql $e2) {
unset($e2); // not used
// ignor error, get handled below
}
}
if (!$num_config)
{
// we check for the old table too, to not scare updating users ;-)
if ($phpgw_config)
{
throw new Exception('You need to update EGroupware before you can continue using it.',999);
}
if ($e)
{
throw new Db\Exception\Setup('Connection with '.$e->getMessage()."\n\n".
'Maybe you not created a database for EGroupware yet.',999);
}
throw new Db\Exception\Setup('It appears that you have not created the database tables for EGroupware.',999);
}
// Set the DB's client charset if a system-charset is set and some other values needed by egw_cache (used in Config::read)
foreach($this->db->select(Config::TABLE,'config_name,config_value',array(
'config_app' => 'phpgwapi',
'config_name' => array('system_charset','install_id','temp_dir'),
),__LINE__,__FILE__) as $row)
{
$GLOBALS['egw_info']['server'][$row['config_name']] = $row['config_value'];
}
if ($GLOBALS['egw_info']['server']['system_charset'] && $GLOBALS['egw_info']['server']['system_charset'] != 'utf-8')
{
$this->db->Link_ID->SetCharSet($GLOBALS['egw_info']['server']['system_charset']);
}
// load up the $GLOBALS['egw_info']['server'] array
$GLOBALS['egw_info']['server'] += Config::read('phpgwapi');
// if no server timezone set, use date_default_timezone_get() to determine it once
// it fills to log with deprecated warnings under 5.3 otherwise
if (empty($GLOBALS['egw_info']['server']['server_timezone']) ||
$GLOBALS['egw_info']['server']['server_timezone'] == 'System/Localtime') // treat invalid tz like empty!
{
try
{
$tz = new DateTimeZone(date_default_timezone_get());
Config::save_value('server_timezone',$GLOBALS['egw_info']['server']['server_timezone'] = $tz->getName(),'phpgwapi');
error_log(__METHOD__."() stored server_timezone=".$GLOBALS['egw_info']['server']['server_timezone']);
}
catch(Exception $e)
{
// do nothing if new DateTimeZone fails (eg. 'System/Localtime' returned), specially do NOT store it!
error_log(__METHOD__."() NO valid 'date.timezone' set in your php.ini!");
}
}
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
// if phpgwapi exists we prefer accounts and egw_session, as they have some deprecated methods
if (file_exists(EGW_SERVER_ROOT.'/phpgwapi'))
{
$this->accounts = new accounts();
/* Do not create the session object if called by the sessions class. This way
* we ensure the correct db based on the user domain.
*/
if($createsessionobject)
{
$this->session = new egw_session($domain_names);
}
}
else
{
$this->accounts = new Accounts();
/* Do not create the session object if called by the sessions class. This way
* we ensure the correct db based on the user domain.
*/
if($createsessionobject)
{
$this->session = new Session($domain_names);
}
}
// setup the other subclasses
$this->acl = new Acl();
$this->preferences = new Preferences();
$this->applications = new Egw\Applications();
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout')
{
$this->verify_session();
$this->applications->read_installed_apps(); // to get translated app-titles, has to be after verify_session
$this->define_egw_constants();
$this->check_app_rights();
$this->load_optional_classes();
}
else // set the defines for login, in case it's more then just login
{
$this->define_egw_constants();
}
}
/**
* __wakeup function gets called by php while unserializing the egw-object, eg. reconnects to the DB
*
* @author RalfBecker@outdoor-training.de
*/
function __wakeup()
{
$GLOBALS['egw'] =& $this; // we need to be immediately available there for the other classes we instantiate
// for the migration: reference us to the old phpgw object
$GLOBALS['phpgw'] =& $this;
if ($GLOBALS['egw_info']['server']['system_charset'])
{
$this->db->Link_ID->SetCharSet($GLOBALS['egw_info']['server']['system_charset']);
}
// restoring server timezone, to avoid warnings under php5.3
if (!empty($GLOBALS['egw_info']['server']['server_timezone']))
{
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
}
$this->define_egw_constants();
}
/**
* wakeup2 function needs to be called after unserializing the egw-object
*
* It adapts the restored object/enviroment to the changed (current) application / page-request
*
* @author RalfBecker@outdoor-training.de
*/
function wakeup2()
{
// do some application specific stuff, need to be done as we are different (current) app now
if (isset($this->template))
{
$this->template->set_root(EGW_APP_TPL);
}
// init the translation class, necessary as own wakeup would run before our's
Translation::init(isset($GLOBALS['egw_info']['flags']['load_translations']) ? $GLOBALS['egw_info']['flags']['load_translations'] : true);
$this->unset_datetime();
// verify the session
$GLOBALS['egw']->verify_session();
$GLOBALS['egw']->check_app_rights();
$this->load_optional_classes();
}
/**
* Unsetting datetime object, so time gets updated
*/
function unset_datetime()
{
unset($this->datetime);
}
/**
* load optional classes by mentioning them in egw_info[flags][enable_CLASS_class] => true
*
* Also loads the template-class if not egw_info[flags][disable_Template_class] is set
*
* Maybe the whole thing should be depricated ;-)
*/
function load_optional_classes()
{
// output the header unless the developer turned it off
if (!@$GLOBALS['egw_info']['flags']['noheader'])
{
echo $GLOBALS['egw']->framework->header();
if (!$GLOBALS['egw_info']['flags']['nonavbar'])
{
echo $GLOBALS['egw']->framework->navbar();
}
}
// Load the (depricated) app include files if they exists
if (EGW_APP_INC != "" && ! preg_match ('/phpgwapi/i', EGW_APP_INC) &&
file_exists(EGW_APP_INC . '/functions.inc.php') && !isset($_GET['menuaction']))
{
include(EGW_APP_INC . '/functions.inc.php');
}
if (!@$GLOBALS['egw_info']['flags']['noheader'] && !@$GLOBALS['egw_info']['flags']['noappheader'] &&
file_exists(EGW_APP_INC . '/header.inc.php') && !isset($_GET['menuaction']))
{
include(EGW_APP_INC . '/header.inc.php');
}
}
/**
* Verfiy there is a valid session
*
* One can specify a callback, which gets called if there's no valid session. If the callback returns true, the parameter
* containst account-details (in keys login, passwd and passwd_type) to automatic create an (anonymous session)
*
* It also checks if enforce_ssl is set in the DB and redirects to the https:// version of the site.
*
* If there is no valid session and none could be automatic created, the function will redirect to login and NOT return
*/
function verify_session()
{
if($GLOBALS['egw_info']['server']['enforce_ssl'] === 'redirect' && !$_SERVER['HTTPS'])
{
Header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
exit;
}
// check if we have a session, if not try to automatic create one
if ($this->session->verify()) return true;
$account = null;
if (($account_callback = $GLOBALS['egw_info']['flags']['autocreate_session_callback']) && is_callable($account_callback) &&
($sessionid = call_user_func_array($account_callback,array(&$account))) === true) // $account_call_back returns true, false or a session-id
{
$sessionid = $this->session->create($account);
}
if (!$sessionid)
{
//echo "<p>account_callback='$account_callback', account=".print_r($account,true).", sessionid=$sessionid</p>\n"; exit;
// we forward to the same place after the re-login
if ($GLOBALS['egw_info']['server']['webserver_url'] && $GLOBALS['egw_info']['server']['webserver_url'] != '/' &&
($webserver_path = parse_url($GLOBALS['egw_info']['server']['webserver_url'],PHP_URL_PATH)) && $webserver_path != '/')
{
// we have to use only path component, to cope with domains like http://egroupware.domain.com and /egroupware
list(,$relpath) = explode($webserver_path,parse_url($_SERVER['PHP_SELF'],PHP_URL_PATH),2);
}
else // the webserver-url is empty or just a slash '/' (eGW is installed in the docroot and no domain given)
{
$matches = null;
if (preg_match('/^https?:\/\/[^\/]*\/(.*)$/',$relpath=$_SERVER['PHP_SELF'],$matches))
{
$relpath = $matches[1];
}
}
// this removes the sessiondata if its saved in the URL
$query = preg_replace('/[&]?sessionid(=|%3D)[^&]+&kp3(=|%3D)[^&]+&domain=.*$/','',$_SERVER['QUERY_STRING']);
if ($GLOBALS['egw_info']['server']['http_auth_types'])
{
$redirect = '/phpgwapi/ntlm/index.php?';
}
else
{
$redirect = '/login.php?';
// only add "your session could not be verified", if a sessionid is given (cookie or on url)
if (Session::get_sessionid()) $redirect .= 'cd=10&';
}
if ($relpath) $redirect .= 'phpgw_forward='.urlencode($relpath.(!empty($query) ? '?'.$query : ''));
self::redirect_link($redirect);
}
}
/**
* Verify the user has rights for the requested app
*
* If the user has no rights for the app (eg. called via URL) he get a permission denied page (this function does NOT return)
*
* @throws Exception\Redirect for anonymous user accessing something he has no rights to
* @throws Exception\NoPermission\Admin
* @throws Exception\NoPermission\App
*/
function check_app_rights()
{
$this->currentapp = $GLOBALS['egw_info']['flags']['currentapp']; // some apps change it later
if (!in_array($GLOBALS['egw_info']['flags']['currentapp'], array('api', 'home'))) // give everyone implicit home rights
{
// This will need to use ACL in the future
if (!$GLOBALS['egw_info']['user']['apps'][$currentapp = $GLOBALS['egw_info']['flags']['currentapp']] ||
($GLOBALS['egw_info']['flags']['admin_only'] && !$GLOBALS['egw_info']['user']['apps']['admin']))
{
// present a login page, if anon user has no right for an application
if ($this->session->session_flags == 'A')
{
// need to destroy a basic auth session here, because it will only be available on current url
if (($sessionid = Session::get_sessionid(true)))
{
$GLOBALS['egw']->session->destroy($sessionid);
}
throw new Exception\Redirect(egw::link('/logout.php'));
}
if ($currentapp == 'admin' || $GLOBALS['egw_info']['flags']['admin_only'])
{
throw new Exception\NoPermission\Admin();
}
throw new Exception\NoPermission\App($currentapp);
}
}
}
/**
* create all the defines / constants of the eGW-environment (plus the deprecated phpgw ones)
*/
function define_egw_constants()
{
define('EGW_ACL_READ',1);
define('EGW_ACL_ADD',2);
define('EGW_ACL_EDIT',4);
define('EGW_ACL_DELETE',8);
define('EGW_ACL_PRIVATE',16);
define('EGW_ACL_GROUP_MANAGERS',32);
define('EGW_ACL_CUSTOM_1',64);
define('EGW_ACL_CUSTOM_2',128);
define('EGW_ACL_CUSTOM_3',256);
// and the old ones
define('PHPGW_ACL_READ',1);
define('PHPGW_ACL_ADD',2);
define('PHPGW_ACL_EDIT',4);
define('PHPGW_ACL_DELETE',8);
define('PHPGW_ACL_PRIVATE',16);
define('PHPGW_ACL_GROUP_MANAGERS',32);
define('PHPGW_ACL_CUSTOM_1',64);
define('PHPGW_ACL_CUSTOM_2',128);
define('PHPGW_ACL_CUSTOM_3',256);
// A few hacker resistant constants that will be used throught the program
define('EGW_TEMPLATE_DIR', $this->common->get_tpl_dir('phpgwapi'));
define('EGW_IMAGES_DIR', $this->common->get_image_path('phpgwapi'));
define('EGW_IMAGES_FILEDIR', $this->common->get_image_dir('phpgwapi'));
define('EGW_APP_ROOT', $this->common->get_app_dir());
define('EGW_APP_INC', $this->common->get_inc_dir());
define('EGW_APP_TPL', $this->common->get_tpl_dir());
define('EGW_IMAGES', $this->common->get_image_path());
define('EGW_APP_IMAGES_DIR', $this->common->get_image_dir());
// and the old ones
define('PHPGW_TEMPLATE_DIR',EGW_TEMPLATE_DIR);
define('PHPGW_IMAGES_DIR',EGW_IMAGES_DIR);
define('PHPGW_IMAGES_FILEDIR',EGW_IMAGES_FILEDIR);
define('PHPGW_APP_ROOT',EGW_APP_ROOT);
define('PHPGW_APP_INC',EGW_APP_INC);
define('PHPGW_APP_TPL',EGW_APP_TPL);
define('PHPGW_IMAGES',EGW_IMAGES);
define('PHPGW_APP_IMAGES_DIR',EGW_APP_IMAGES_DIR);
}
/**
* force the session cache to be re-created, because some of it's data changed
*
* Needs to be called if user-preferences, system-config or enabled apps of the current user have been changed and
* the change should have immediate effect
*/
static function invalidate_session_cache()
{
unset($_SESSION['egw_info_cache']);
unset($_SESSION['egw_object_cache']);
}
/**
* run string through htmlspecialchars and stripslashes
*
* @param string $s
* @return string The string with html special characters replaced with entities
*/
static function strip_html($s)
{
return htmlspecialchars(stripslashes($s));
}
/**
* Link url generator
*
* @param string $url url link is for
* @param string|array $extravars ='' extra params to be added to url
* @param string $link_app =null if appname or true, some templates generate a special link-handler url
* @return string The full url after processing
*/
static function link($url, $extravars = '', $link_app=null)
{
return $GLOBALS['egw']->framework->link($url, $extravars, $link_app);
}
/**
* Redirects direct to a generated link
*
* @param string $url url link is for
* @param string|array $extravars ='' extra params to be added to url
* @param string $link_app =null if appname or true, some templates generate a special link-handler url
* @return string The full url after processing
*/
static function redirect_link($url, $extravars='', $link_app=null)
{
return $GLOBALS['egw']->framework->redirect_link($url, $extravars, $link_app);
}
/**
* Handles redirects under iis and apache, it does NOT return (calls exit)
*
* This function handles redirects under iis and apache it assumes that $phpgw->link() has already been called
*
* @param string $url url to redirect to
* @param string $link_app =null appname to redirect for, default currentapp
*/
static function redirect($url, $link_app=null)
{
Framework::redirect($url, $link_app);
}
/**
* Shortcut to translation class
*
* This function is a basic wrapper to Translation::translate()
*
* @deprecated only used in the old timetracker
* @param string The key for the phrase
* @see Translation::translate()
*/
static function lang($key,$args=null)
{
if (!is_array($args))
{
$args = func_get_args();
array_shift($args);
}
return Translation::translate($key,$args);
}
/**
* registered shutdown callbacks and optional arguments
*
* @var array
*/
private static $shutdown_callbacks = array();
/**
* Register a callback to run on shutdown AFTER output send to user
*
* Allows eg. static classes (no destructor) to run on shutdown AND
* garanties to run AFTER output send to user.
*
* @param callable $callback use array($classname, $method) for static methods
* @param array $args =array()
*/
public static function on_shutdown($callback, array $args=array())
{
array_unshift($args, $callback);
// prepend new callback, to run them in oposite order they are registered
array_unshift(self::$shutdown_callbacks, $args);
}
/**
* Shutdown handler running all registered on_shutdown callbacks and then disconnecting from db
*/
function __destruct()
{
if (!defined('EGW_SHUTDOWN'))
{
define('EGW_SHUTDOWN',True);
// send json response BEFORE flushing output
if (Json\Request::isJSONRequest())
{
Json\Response::sendResult();
}
// run all on_shutdown callbacks with session in their name (eg. egw_link::save_session_cache), do NOT stop on exceptions
foreach(self::$shutdown_callbacks as $n => $data)
{
try {
//error_log(__METHOD__."() running ".array2string($data));
$callback = array_shift($data);
if (!is_array($callback) || strpos($callback[1], 'session') === false) continue;
call_user_func_array($callback, $data);
}
catch (\Exception $ex) {
_egw_log_exception($ex);
}
unset(self::$shutdown_callbacks[$n]);
}
// now we can close the session
// without closing the session fastcgi_finish_request() will NOT send output to user
if (isset($GLOBALS['egw']->session) && is_object($GLOBALS['egw']->session)) $GLOBALS['egw']->session->commit_session();
// flush all output to user
/* does NOT work on Apache :-(
for($i = 0; ob_get_level() && $i < 10; ++$i)
{
ob_end_flush();
}
flush();*/
// working for fastCGI :-)
if (function_exists('fastcgi_finish_request') && substr($_SERVER['PHP_SELF'], -32) != '/phpgwapi/cron/asyncservices.php')
{
fastcgi_finish_request();
}
// run all on_shutdown, do NOT stop on exceptions
foreach(self::$shutdown_callbacks as $data)
{
try {
//error_log(__METHOD__."() running ".array2string($data));
$callback = array_shift($data);
call_user_func_array($callback, $data);
}
catch (\Exception $ex) {
_egw_log_exception($ex);
}
}
// call the asyncservice check_run function if it is not explicitly set to cron-only
if (!$GLOBALS['egw_info']['server']['asyncservice']) // is default
{
$async = new Asyncservice();
$async->fallback();
}
$this->db->disconnect();
}
}
}

109
api/src/Egw/Applications.php Executable file
View File

@ -0,0 +1,109 @@
<?php
/**
* EGroupware API - Applications
*
* @link http://www.egroupware.org
* @author Mark Peters <skeeter@phpgroupware.org>
* Copyright (C) 2001 Mark Peters
* @license http://opensource.org/licenses/lgpl-license.php LGPL - GNU Lesser General Public License
* @package api
* @subpackage egw
* @version $Id$
*/
namespace EGroupware\Api\Egw;
/**
* Application (sub-)object of Egw-object used to load $GLOBALS['egw_info'](['user'])['apps']
*/
class Applications
{
var $account_id;
var $data = Array();
/**
* Reference to the global db class
*
* @var egw_db
*/
var $db;
var $table_name = 'egw_applications';
/**************************************************************************\
* Standard constructor for setting $this->account_id *
\**************************************************************************/
/**
* standard constructor for setting $this->account_id
*
* @param $account_id account id
*/
function __construct($account_id = '')
{
if (is_object($GLOBALS['egw_setup']) && is_object($GLOBALS['egw_setup']->db))
{
$this->db = $GLOBALS['egw_setup']->db;
}
else
{
$this->db = $GLOBALS['egw']->db;
}
$this->account_id = get_account_id($account_id);
}
/**
* Get applications of user
*
* Used to populate $GLOBALS['egw_info']['user']['apps'] in Api\Session
*/
function read_repository()
{
if (!isset($GLOBALS['egw_info']['apps']) || !is_array($GLOBALS['egw_info']['apps']))
{
$this->read_installed_apps();
}
$this->data = Array();
if(!$this->account_id)
{
return False;
}
$apps = $GLOBALS['egw']->acl->get_user_applications($this->account_id);
foreach(array_keys($GLOBALS['egw_info']['apps']) as $app)
{
if (isset($apps[$app]) && $apps[$app])
{
$this->data[$app] =& $GLOBALS['egw_info']['apps'][$app];
}
}
return $this->data;
}
/**
* populate array with a list of installed apps
*
*/
function read_installed_apps()
{
foreach($this->db->select($this->table_name,'*',false,__LINE__,__FILE__,false,'ORDER BY app_order ASC') as $row)
{
$title = $app_name = $row['app_name'];
if (@is_array($GLOBALS['egw_info']['user']['preferences']) && ($t = lang($app_name)) != $app_name.'*')
{
$title = $t;
}
$GLOBALS['egw_info']['apps'][$app_name] = Array(
'title' => $title,
'name' => $app_name,
'enabled' => True,
'status' => $row['app_enabled'],
'id' => (int)$row['app_id'],
'order' => (int)$row['app_order'],
'version' => $row['app_version'],
'index' => $row['app_index'],
'icon' => $row['app_icon'],
'icon_app'=> $row['app_icon_app'],
);
}
}
}

125
api/src/Egw/Base.php Normal file
View File

@ -0,0 +1,125 @@
<?php
/**
* EGroupware API - Applications
*
* @link http://www.egroupware.org
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
* Parts Copyright (C) 2003 Free Software Foundation
* @author RalfBecker@outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage egw
* @version $Id$
*/
namespace EGroupware\Api\Egw;
use EGroupware\Api;
// explicitly list old, non-namespaced classes
use common; // get_tpl_dir
/**
* Egw\Base object used in setup, does not instanciate anything by default
*
* Extending Egw\Base which uses now a getter method to create the usual subobject on demand,
* to allow a quicker header include on sites not using php4-restore.
* This also makes a lot of application code, like the following, unnecessary:
* if (!is_object($GLOBALS['egw']->ldap)
* {
* $GLOBALS['egw']->ldap = Api\Ldap::factory();
* }
* You can now simply use $GLOBALS['egw']->ldap, and the egw class instanciates it for you on demand.
*/
class Base
{
/**
* Instance of the db-object
*
* @var Api\Db
*/
var $db;
/**
* Current app at the instancation of the class
*
* @var string
*/
var $currentapp;
/**
* Global ADOdb object, need to be defined here, to not call magic __get method
*
* @var ADOConnection
*/
var $ADOdb;
/**
* Classes which get instanciated in a different name
*
* @var array
*/
static $sub_objects = array(
'log' => 'errorlog',
'link' => 'bolink', // depricated use static egw_link methods
'datetime' => 'egw_datetime',
'template' => 'Template',
'session' => 'egw_session', // otherwise $GLOBALS['egw']->session->appsession() fails
// classes moved to new api dir
'framework' => true, // special handling in __get()
'ldap' => true,
'auth' => 'EGroupware\\Api\\Auth',
);
/**
* Magic function to check if a sub-object is set
*
* @param string $name
* @return boolean
*/
function __isset($name)
{
//error_log(__METHOD__."($name)");
return isset($this->$name);
}
/**
* Magic function to return a sub-object
*
* @param string $name
* @return mixed
*/
function __get($name)
{
//error_log(__METHOD__."($name)".function_backtrace());
if ($name == 'js') $name = 'framework'; // javascript class is integrated now into framework
if (isset($this->$name))
{
return $this->$name;
}
if (!isset(self::$sub_objects[$name]) && !class_exists($name))
{
if ($name != 'ADOdb') error_log(__METHOD__.": There's NO $name object! ".function_backtrace());
return null;
}
switch($name)
{
case 'framework':
return $this->framework = Api\Framework::factory();
case 'template': // need to be instancated for the current app
if (!($tpl_dir = common::get_tpl_dir($this->currentapp)))
{
return null;
}
return $this->template = new Api\Framework\Template($tpl_dir);
case 'ldap':
return $this->ldap = Api\Ldap::factory(false);
default:
$class = isset(self::$sub_objects[$name]) ? self::$sub_objects[$name] : $name;
break;
}
return $this->$name = new $class();
}
}

104
api/src/autoload.php Executable file
View File

@ -0,0 +1,104 @@
<?php
/**
* EGroupware autloader
*
* Normally included by either:
* - header.inc.php
* - api/src/loader.php
* - api/src/loader/common.php
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
// this is only neccessary, if header.inc.php is not included, but api/src/autoload.php directly
if (!defined('EGW_SERVER_ROOT'))
{
define('EGW_SERVER_ROOT', dirname(dirname(__DIR__)));
define('EGW_INCLUDE_ROOT', EGW_SERVER_ROOT);
define('EGW_API_INC', __DIR__);
}
/**
* New PSR-4 autoloader for EGroupware
*
* class_exists('\\EGroupware\\Api\\Vfs'); // /api/src/Vfs.php
* class_exists('\\EGroupware\\Api\\Vfs\\Dav\\Directory'); // /api/src/Vfs/Dav/Directory.php
* class_exists('\\EGroupware\\Api\\Vfs\\Sqlfs\\StreamWrapper'); // /api/src/Vfs/Sqlfs/StreamWrapper.php
* class_exists('\\EGroupware\\Api\\Vfs\\Sqlfs\\Utils'); // /api/src/Vfs/Sqlfs/Utils.php
* class_exists('\\EGroupware\\Stylite\\Versioning\\StreamWrapper'); // /stylite/src/Versioning/StreamWrapper.php
* class_exists('\\EGroupware\\Calendar\\Ui'); // /calendar/src/Ui.php
* class_exists('\\EGroupware\\Calendar\\Ui\\Lists'); // /calendar/src/Ui/Lists.php
* class_exists('\\EGroupware\\Calendar\\Ui\\Views'); // /calendar/src/Ui/Views.php
*/
spl_autoload_register(function($class)
{
$parts = explode('\\', $class);
if (array_shift($parts) != 'EGroupware') return; // not our prefix
$app = lcfirst(array_shift($parts));
$base = EGW_INCLUDE_ROOT.'/'.$app.'/src/';
$path = $base.implode('/', $parts).'.php';
if (file_exists($path))
{
require_once $path;
//error_log("PSR4_autoload('$class') --> require_once($path) --> class_exists('$class')=".array2string(class_exists($class,false)));
}
});
/**
* Old autoloader for EGroupware understanding the following naming schema:
*
* 1. new (prefered) nameing schema: app_class_something loading app/inc/class.class_something.inc.php
* 2. API classes: classname loading phpgwapi/inc/class.classname.inc.php
* 2a.API classes containing multiple classes per file eg. egw_exception* in class.egw_exception.inc.php
* 3. eTemplate classes: classname loading etemplate/inc/class.classname.inc.php
*
* @param string $class name of class to load
*/
spl_autoload_register(function($class)
{
// fixing warnings generated by php 5.3.8 is_a($obj) trying to autoload huge strings
if (strlen($class) > 64 || strpos($class, '.') !== false) return;
$components = explode('_',$class);
$app = array_shift($components);
// classes using the new naming schema app_class_name, eg. admin_cmd
if (file_exists($file = EGW_INCLUDE_ROOT.'/'.$app.'/inc/class.'.$class.'.inc.php') ||
// classes using the new naming schema app_class_name, eg. admin_cmd
isset($components[0]) && file_exists($file = EGW_INCLUDE_ROOT.'/'.$app.'/inc/class.'.$app.'_'.$components[0].'.inc.php') ||
// classes with an underscore in their name
!isset($GLOBALS['egw_info']['apps'][$app]) && isset($GLOBALS['egw_info']['apps'][$app . '_' . $components[0]]) &&
file_exists($file = EGW_INCLUDE_ROOT.'/'.$app.'_'.$components[0].'/inc/class.'.$class.'.inc.php') ||
// eGW api classes using the old naming schema, eg. html
file_exists($file = EGW_API_INC.'/class.'.$class.'.inc.php') ||
// eGW api classes containing multiple classes in on file, eg. egw_exception
isset($components[0]) && file_exists($file = EGW_API_INC.'/class.'.$app.'_'.$components[0].'.inc.php') ||
// eGW eTemplate classes using the old naming schema, eg. etemplate
file_exists($file = EGW_INCLUDE_ROOT.'/etemplate/inc/class.'.$class.'.inc.php') ||
// include PEAR and PSR0 classes from include_path
// need to use include (not include_once) as eg. a previous included EGW_API_INC/horde/Horde/String.php causes
// include_once('Horde/String.php') to return true, even if the former was included with an absolute path
// only use include_path, if no Composer vendor directory exists
!isset($GLOBALS['egw_info']['apps'][$app]) && !file_exists(EGW_SERVER_ROOT.'/vendor') &&
@include($file = strtr($class, array('_'=>'/','\\'=>'/')).'.php'))
{
include_once($file);
//if (!class_exists($class, false) && !interface_exists($class, false)) error_log("autoloading class $class by include_once($file) failed!");
}
// allow apps to define an own autoload method
elseif (isset($GLOBALS['egw_info']['flags']['autoload']) && is_callable($GLOBALS['egw_info']['flags']['autoload']))
{
call_user_func($GLOBALS['egw_info']['flags']['autoload'],$class);
}
});
// if we have a Composer vendor directory, also load it's autoloader, to allow manage our requirements with Composer
if (file_exists(EGW_SERVER_ROOT.'/vendor'))
{
require_once EGW_SERVER_ROOT.'/vendor/autoload.php';
}

143
api/src/loader.php Normal file
View File

@ -0,0 +1,143 @@
<?php
/**
* EGroupware API loader
*
* Rewritten by RalfBecker@outdoor-training.de to store the eGW enviroment
* (egw-object and egw_info-array) in a php-session and restore it from
* there instead of creating it completly new on each page-request.
* The enviroment gets now created by the egw-class
*
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
use EGroupware\Api\Session;
use EGroupware\Api\Egw;
// E_STRICT in PHP 5.4 gives various strict warnings in working code, which can NOT be easy fixed in all use-cases :-(
// Only variables should be assigned by reference, eg. soetemplate::tree_walk()
// Declaration of <extended method> should be compatible with <parent method>, varios places where method parameters change
// --> switching it off for now, as it makes error-log unusable
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
if (function_exists('get_magic_quotes_runtime') && get_magic_quotes_runtime())
{
set_magic_quotes_runtime(false);
}
$egw_min_php_version = '5.4';
if (!function_exists('version_compare') || version_compare(PHP_VERSION,$egw_min_php_version) < 0)
{
die("EGroupware requires PHP $egw_min_php_version or greater.<br />Please contact your System Administrator to upgrade PHP!");
}
if (!defined('EGW_API_INC')) define('EGW_API_INC',PHPGW_API_INC); // this is to support the header upgrade
/* Make sure the header.inc.php is current. */
if (!isset($GLOBALS['egw_domain']) || $GLOBALS['egw_info']['server']['versions']['header'] < $GLOBALS['egw_info']['server']['versions']['current_header'])
{
echo '<center><b>You need to update your header.inc.php file to version '.
$GLOBALS['egw_info']['server']['versions']['current_header'].
' by running <a href="setup/manageheader.php">setup/headeradmin</a>.</b></center>';
exit;
}
/* Make sure the developer is following the rules. */
if (!isset($GLOBALS['egw_info']['flags']['currentapp']))
{
echo "<p><b>!!! YOU DO NOT HAVE YOUR \$GLOBALS['egw_info']['flags']['currentapp'] SET !!!<br>\n";
echo '!!! PLEASE CORRECT THIS SITUATION !!!</b></p>';
}
require_once(__DIR__.'/loader/common.php');
// init eGW's sessions-handler and check if we can restore the eGW enviroment from the php-session
if (Session::init_handler())
{
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout')
{
if (is_array($_SESSION[Session::EGW_INFO_CACHE]) && $_SESSION[Session::EGW_OBJECT_CACHE] && $_SESSION[Session::EGW_REQUIRED_FILES])
{
// marking the context as restored from the session, used by session->verify to not read the data from the db again
$GLOBALS['egw_info']['flags']['restored_from_session'] = true;
// restoring the egw_info-array
$GLOBALS['egw_info'] = array_merge($_SESSION[Session::EGW_INFO_CACHE],array('flags' => $GLOBALS['egw_info']['flags']));
// include required class-definitions
if (is_array($_SESSION[Session::EGW_REQUIRED_FILES])) // all classes, which can not be autoloaded
{
foreach($_SESSION[Session::EGW_REQUIRED_FILES] as $file)
{
require_once($file);
}
}
$GLOBALS['egw'] = unserialize($_SESSION[Session::EGW_OBJECT_CACHE]);
if (is_object($GLOBALS['egw']) && ($GLOBALS['egw'] instanceof Egw)) // only egw object has wakeup2, setups egw_minimal eg. has not!
{
$GLOBALS['egw']->wakeup2(); // adapt the restored egw-object/enviroment to this request (eg. changed current app)
$GLOBALS['egw_info']['flags']['session_restore_time'] = microtime(true) - $GLOBALS['egw_info']['flags']['page_start_time'];
if (is_object($GLOBALS['egw']->translation)) return; // exit this file, as the rest of the file creates a new egw-object and -enviroment
}
// egw object could NOT be restored from the session, create a new one
unset($GLOBALS['egw']);
$GLOBALS['egw_info'] = array('flags'=>$GLOBALS['egw_info']['flags']);
unset($GLOBALS['egw_info']['flags']['restored_from_session']);
unset($_SESSION[Session::EGW_INFO_CACHE]);
unset($_SESSION[Session::EGW_REQUIRED_FILES]);
unset($_SESSION[Session::EGW_OBJECT_CACHE]);
}
}
else // destroy the session-cache if called by login or logout
{
unset($_SESSION[Session::EGW_INFO_CACHE]);
unset($_SESSION[Session::EGW_REQUIRED_FILES]);
unset($_SESSION[Session::EGW_OBJECT_CACHE]);
}
}
/****************************************************************************\
* Multi-Domain support *
\****************************************************************************/
$GLOBALS['egw_info']['user']['domain'] = Session::search_instance(
isset($_POST['login']) ? $_POST['login'] : (isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : $_SERVER['REMOTE_USER']),
Session::get_request('domain'),$GLOBALS['egw_info']['server']['default_domain'],
array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']),$GLOBALS['egw_domain']);
$GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_host'];
$GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_port'];
$GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_name'];
$GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_user'];
$GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_pass'];
$GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_type'];
// the egw-object instanciates all sub-classes (eg. $GLOBALS['egw']->db) and the egw_info array
$GLOBALS['egw'] = new Egw(array_keys($GLOBALS['egw_domain']));
// store domain config user&pw as a hash (originals get unset)
$GLOBALS['egw_info']['server']['config_hash'] = Session::user_pw_hash($GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['config_user'],
$GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['config_passwd'],true);
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && !$GLOBALS['egw_info']['server']['show_domain_selectbox'])
{
unset($GLOBALS['egw_domain']); // we kill this for security reasons
unset($GLOBALS['egw_info']['server']['header_admin_user']);
unset($GLOBALS['egw_info']['server']['header_admin_password']);
}
// saving the the egw_info array and the egw-object in the session
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login')
{
$_SESSION[Session::EGW_INFO_CACHE] = $GLOBALS['egw_info'];
unset($_SESSION[Session::EGW_INFO_CACHE]['flags']); // dont save the flags, they change on each request
$_SESSION[Session::EGW_OBJECT_CACHE] = serialize($GLOBALS['egw']);
}

417
api/src/loader/common.php Executable file
View File

@ -0,0 +1,417 @@
<?php
/**
* EGroupware create enviroment:
* - autoloader
* - exception handler
* - XSS and other security stuff
* - global functions (incl. deprecated ones, if /phpgwapi dir is there)
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
use EGroupware\Api;
require_once dirname(__DIR__).'/autoload.php';
/**
* applies stripslashes recursivly on each element of an array
*
* @param array &$var
* @return array
*/
function array_stripslashes($var)
{
if (!is_array($var))
{
return stripslashes($var);
}
foreach($var as $key => $val)
{
$var[$key] = is_array($val) ? array_stripslashes($val) : stripslashes($val);
}
return $var;
}
/**
* Return the number of bytes of a string, independent of mbstring.func_overload
* AND the availability of mbstring
*
* @param string $str
* @return int
*/
function bytes($str)
{
static $func_overload = null;
if (is_null($func_overload)) $func_overload = extension_loaded('mbstring') ? ini_get('mbstring.func_overload') : 0;
return $func_overload & 2 ? mb_strlen($str,'ascii') : strlen($str);
}
/**
* mbstring.func_overload safe substr
*
* @param string $data
* @param int $offset
* @param int $len
* @return string
*/
function cut_bytes(&$data,$offset,$len=null)
{
static $func_overload = null;
if (is_null($func_overload)) $func_overload = extension_loaded('mbstring') ? ini_get('mbstring.func_overload') : 0;
if (is_null($len))
{
return $func_overload & 2 ? mb_substr($data,$offset,bytes($data),'ascii') : substr($data,$offset);
}
return $func_overload & 2 ? mb_substr($data,$offset,$len,'ascii') : substr($data,$offset,$len);
}
if (!function_exists('imap_rfc822_parse_adrlist'))
{
/**
* parses a (comma-separated) address string
*
* Examples:
* - Joe Doe <doe@example.com>
* - "Doe, Joe" <doe@example.com>
* - "\'Joe Doe\'" <doe@example.com> // actually not necessary to quote
* - postmaster@example.com
* - root
* - "Joe on its way Down Under :-\)" <doe@example.com>
* - "Giant; \"Big\" Box" <sysservices@example.net>
* - sysservices@example.net <sysservices@example.net> // this is wrong, because @ need to be quoted
*
* Invalid addresses, if detected, set host to '.SYNTAX-ERROR.'
*
* @param string $address - A string containing addresses
* @param string $default_host - The default host name
* @return array of objects. The objects properties are:
* mailbox - the mailbox name (username)
* host - the host name
* personal - the personal name
* adl - at domain source route
*/
function imap_rfc822_parse_adrlist($address, $default_host)
{
$addresses = array();
$pending = '';
foreach(explode(',', $address) as $part)
{
$trimmed = trim(($pending ? $pending.',' : '').$part);
if (($trimmed[0] == '"' && substr($trimmed, -1) != '>')||strpos($part, '@')===false)
{
$pending .= ($pending ? $pending.',' : '').$part;
continue;
}
$pending = '';
$matches = $personal = $mailbox = $host = null;
if (preg_match('/^(.*)<([^>@]+)(@([^>]+))?>$/', $trimmed, $matches))
{
$personal = trim($matches[1]);
$mailbox = $matches[2];
$host = $matches[4];
}
elseif (strpos($trimmed, '@') !== false)
{
list($mailbox, $host) = explode('@', $trimmed);
}
else
{
$mailbox = $trimmed;
}
if ($personal[0] == '"' && substr($personal, -1) == '"')
{
$personal = str_replace('\\', '', substr($personal, 1, -1));
}
if (empty($host)) $host = $default_host;
$addresses[] = (object)array_diff(array(
'mailbox' => $mailbox,
'host' => $host,
'personal' => $personal,
), array(null, ''));
}
return $addresses;
}
}
if (!function_exists('imap_rfc822_write_address'))
{
/**
* Returns a properly formatted email address given the mailbox, host, and personal info
* @param string $mailbox - The mailbox name, see imap_open() for more information
* @param string $host - The email host part
* @param string $personal - The name of the account owner
* @return string properly formatted email address as defined in » RFC2822.
*/
function imap_rfc822_write_address($mailbox, $host, $personal)
{
if (is_array($personal)) $personal = implode(' ', $personal);
//if (!preg_match('/^[!#$%&\'*+/0-9=?A-Z^_`a-z{|}~-]+$/u', $personal)) // that's how I read the rfc(2)822
if ($personal && !preg_match('/^[0-9A-Z -]*$/iu', $personal)) // but quoting is never wrong, so quote more then necessary
{
$personal = '"'.str_replace(array('\\', '"'),array('\\\\', '\\"'), $personal).'"';
}
return ($personal ? $personal.' <' : '').$mailbox.($host ? '@'.$host : '').($personal ? '>' : '');
}
}
if (!function_exists('imap_mime_header_decode'))
{
/**
* Decodes MIME message header extensions that are non ASCII text (RFC2047)
*
* Uses Horde_Mime::decode() and therefore always returns only a single array element!
*
* @param string $text
* @return array with single object with attribute text already in our internal encoding and charset
* @deprecated use Horde_Mime::decode()
*/
function imap_mime_header_decode($text)
{
return array((object)array(
'text' => Horde_Mime::decode($text),
'charset' => Api\Translation::charset(), // is already in our internal encoding!
));
}
}
if (!function_exists('mb_strlen'))
{
/**
* Number of characters in a string
*
* @param string $str
* @return int
*/
function mb_strlen($str)
{
return strlen($str);
}
}
if (!function_exists('mb_substr'))
{
/**
* Return part of a string
*
* @param string $data
* @param int $offset
* @param int $len
* @return string
*/
function mb_substr(&$data, $offset, $len=null)
{
return is_null($len) ? substr($data, $offset) : substr($data, $offset, $len);
}
}
/**
* Format array or other types as (one-line) string, eg. for error_log statements
*
* @param mixed $var variable to dump
* @return string
*/
function array2string($var)
{
switch (($type = gettype($var)))
{
case 'boolean':
return $var ? 'TRUE' : 'FALSE';
case 'string':
return "'$var'";
case 'integer':
case 'double':
case 'resource':
return $var;
case 'NULL':
return 'NULL';
case 'object':
case 'array':
return str_replace(array("\n",' '/*,'Array'*/),'',print_r($var,true));
}
return 'UNKNOWN TYPE!';
}
/**
* Check if a given extension is loaded or load it if possible (requires sometimes disabled or unavailable dl function)
*
* @param string $extension
* @param boolean $throw =false should we throw an exception, if $extension could not be loaded, default false = no
* @return boolean true if loaded now, false otherwise
*/
function check_load_extension($extension,$throw=false)
{
if (!defined('PHP_SHLIB_PREFIX'))
{
define('PHP_SHLIB_PREFIX',PHP_SHLIB_SUFFIX == 'dll' ? 'php_' : '');
}
// we check for the existens of 'dl', as multithreaded webservers dont have it and some hosters disable it !!!
$loaded = extension_loaded($extension) || function_exists('dl') && @dl($dl=PHP_SHLIB_PREFIX.$extension.'.'.PHP_SHLIB_SUFFIX);
if (!$loaded && $throw)
{
throw new Exception ("PHP extension '$extension' not loaded AND can NOT be loaded via dl('$dl')!");
}
return $loaded;
}
// include deprecated global functions, if phpgwapi is installed
if (file_exists(EGW_SERVER_ROOT.'/phpgwapi'))
{
include_once EGW_SERVER_ROOT.'/phpgwapi/inc/deprecated_functions.inc.php';
}
/**
* Return a properly formatted account_id.
*
* @author skeeter
* This function will return a properly formatted account_id. This can take either a name or an account_id as paramters. If a name is provided it will return the associated id.
* $account_id = get_account_id($accountid);
* @param int/string $account_id either a name or an id
* @param int/string $default_id either a name or an id
* @return int account_id
*/
function get_account_id($account_id = '',$default_id = '')
{
if (gettype($account_id) == 'integer')
{
return $account_id;
}
elseif ($account_id == '')
{
if ($default_id == '')
{
return (isset($GLOBALS['egw_info']['user']['account_id'])?$GLOBALS['egw_info']['user']['account_id']:0);
}
elseif (is_string($default_id))
{
return $GLOBALS['egw']->accounts->name2id($default_id);
}
return (int)$default_id;
}
elseif (is_string($account_id))
{
if($GLOBALS['egw']->accounts->exists((int)$account_id) == True)
{
return (int)$account_id;
}
else
{
return $GLOBALS['egw']->accounts->name2id($account_id);
}
}
}
/**
* print an array or object as pre-formatted html
*
* @param mixed $array
* @param boolean $print =true print or return the content
* @return string if !$print
*/
function _debug_array($array,$print=True)
{
$output = '<pre>'.print_r($array,true)."</pre>\n";
if ($print)
{
echo $output;
}
else
{
return $output;
}
}
/**
* backtrace of the calling functions for php4.3+ else menuaction/scriptname
*
* @author RalfBecker-AT-outdoor-training.de
* @param int $remove =0 number of levels to remove
* @return string function-names separated by slashes (beginning with the calling function not this one)
*/
function function_backtrace($remove=0)
{
if (function_exists('debug_backtrace'))
{
$backtrace = debug_backtrace();
//echo "function_backtrace($remove)<pre>".print_r($backtrace,True)."</pre>\n";
foreach($backtrace as $n => $level)
{
if ($remove-- < 0)
{
$ret[] = (isset($level['class'])?$level['class'].$level['type']:'').$level['function'].
($n > 0 && isset($backtrace[$n-1]['line']) ? ':'.$backtrace[$n-1]['line'] : ''). // add line number of call
(!$level['class'] && !is_object($level['args'][0]) && $level['function'] != 'unserialize' ?
'('.substr(str_replace(EGW_SERVER_ROOT,'',(string)$level['args'][0]),0,64).')' : '');
}
}
if (is_array($ret))
{
return implode(' / ',$ret);
}
}
return $_GET['menuaction'] ? $_GET['menuaction'] : str_replace(EGW_SERVER_ROOT,'',$_SERVER['SCRIPT_FILENAME']);
}
if (!function_exists('lang') || defined('NO_LANG')) // setup declares an own version
{
/**
* function to handle multilanguage support
*
* @param string $key message in englich with %1, %2, ... placeholders
* @param string $vars =null multiple values to replace the placeholders
* @return string translated message with placeholders replaced
*/
function lang($key,$vars=null)
{
if(!is_array($vars))
{
$vars = func_get_args();
array_shift($vars); // remove $key
}
return Api\Translation::translate($key,$vars);
}
}
require_once __DIR__.'/security.php';
require_once __DIR__.'/exception.php';
/**
* Public functions to be compatible with the exiting eGW framework
*/
if (!function_exists('parse_navbar'))
{
/**
* echo's out the navbar
*
* @deprecated use $GLOBALS['egw']->framework->navbar() or $GLOBALS['egw']->framework::render()
*/
function parse_navbar()
{
echo $GLOBALS['egw']->framework->navbar();
}
}
if (!function_exists('display_sidebox'))
{
/**
* echo's out a sidebox menu
*
* @deprecated use $GLOBALS['egw']->framework->sidebox()
*/
function display_sidebox($appname,$menu_title,$_file)
{
$file = str_replace('preferences.uisettings.index', 'preferences.preferences_settings.index', $_file);
$GLOBALS['egw']->framework->sidebox($appname,$menu_title,$file);
}
}

195
api/src/loader/exception.php Executable file
View File

@ -0,0 +1,195 @@
<?php
/**
* EGroupware exception handler and friends
*
* Usually loaded via header.inc.php or api/src/loader/common.php
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
use EGroupware\Api;
/**
* Translate message only if translation object is already loaded
*
* This function is usefull for exception handlers or early stages of the initialisation of the egw object,
* as calling lang would try to load the translations, evtl. cause more errors, eg. because there's no db-connection.
*
* @param string $key message in englich with %1, %2, ... placeholders
* @param string $vars =null multiple values to replace the placeholders
* @return string translated message with placeholders replaced
*/
function try_lang($key,$vars=null)
{
static $varnames = array('%1','%2','%3','%4');
if(!is_array($vars))
{
$vars = func_get_args();
array_shift($vars); // remove $key
}
return class_exists('EGroupware\Api\Translations',false) ? Api\Translation::translate($key,$vars) : str_replace($varnames,$vars,$key);
}
/**
* Clasify exception for a headline and log it to error_log, if not running as cli
*
* @param Exception|Error $e
* @param string &$headline
*/
function _egw_log_exception($e,&$headline=null)
{
$trace = explode("\n", $e->getTraceAsString());
if ($e instanceof Api\Exception\NoPermission)
{
$headline = try_lang('Permission denied!');
}
elseif ($e instanceof Api\Db\Exception)
{
$headline = try_lang('Database error');
}
elseif ($e instanceof Api\Exception\WrongUserinput)
{
$headline = ''; // message contains the whole message, it's usually no real error but some input validation
}
elseif ($e instanceof egw_exception_warning)
{
$headline = 'PHP Warning';
array_shift($trace);
}
else
{
$headline = try_lang('An error happened');
}
// log exception to error log, if not running as cli,
// which outputs the error_log to stderr and therefore output it twice to the user
if(isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] !== 'cli')
{
error_log($headline.($e instanceof egw_exception_warning ? ': ' : ' ('.get_class($e).'): ').$e->getMessage());
foreach($trace as $line)
{
error_log($line);
}
error_log('# Instance='.$GLOBALS['egw_info']['user']['domain'].', User='.$GLOBALS['egw_info']['user']['account_lid'].
', Request='.$_SERVER['REQUEST_METHOD'].' '.($_SERVER['HTTPS']?'https://':'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].
', User-agent='.$_SERVER['HTTP_USER_AGENT']);
}
}
/**
* Fail a little bit more gracefully then an uncought exception
*
* Does NOT return
*
* @param Exception|Error $e
*/
function egw_exception_handler($e)
{
// handle redirects without logging
if (is_a($e, 'egw_exception_redirect'))
{
egw::redirect($e->url, $e->app);
}
// logging all exceptions to the error_log (if not cli) and get headline
$headline = null;
_egw_log_exception($e,$headline);
// exception handler for cli (command line interface) clients, no html, no logging
if(!isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] == 'cli')
{
echo ($headline ? $headline.': ' : '').$e->getMessage()."\n";
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
{
echo $e->getTraceAsString()."\n";
}
exit($e->getCode() ? $e->getCode() : 9999); // allways give a non-zero exit code
}
// regular GUI exception
if (!isset($GLOBALS['egw_info']['flags']['no_exception_handler']))
{
header('HTTP/1.1 500 '.$headline);
$message = '<h3>'.Api\Html::htmlspecialchars($headline)."</h3>\n".
'<pre><b>'.Api\Html::htmlspecialchars($e->getMessage())."</b>\n\n";
// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
{
$message .= Api\Html::htmlspecialchars($e->getTraceAsString());
}
$message .= "</pre>\n";
if (is_a($e, 'EGroupware\Api\Db\Exception\Setup'))
{
$setup_dir = str_replace(array('home/index.php','index.php'),'setup/',$_SERVER['PHP_SELF']);
$message .= '<a href="'.$setup_dir.'">Run setup to install or configure EGroupware.</a>';
}
elseif (is_object($GLOBALS['egw']) && isset($GLOBALS['egw']->session) && method_exists($GLOBALS['egw'],'link'))
{
$message .= '<p><a href="'.$GLOBALS['egw']->link('/index.php').'">'.try_lang('Click here to resume your eGroupWare Session.').'</a></p>';
}
if (is_object($GLOBALS['egw']) && isset($GLOBALS['egw']->framework))
{
$GLOBALS['egw']->framework->render($message,$headline);
}
else
{
echo "<html>\n<head>\n<title>".Api\Html::htmlspecialchars($headline)."</title>\n</head>\n<body>\n$message\n</body>\n</html>\n";
}
}
// exception handler sending message back to the client as basic auth message
elseif($GLOBALS['egw_info']['flags']['no_exception_handler'] == 'basic_auth')
{
$error = str_replace(array("\r", "\n"), array('', ' | '), $e->getMessage());
header('WWW-Authenticate: Basic realm="'.$headline.' '.$error.'"');
header('HTTP/1.1 401 Unauthorized');
header('X-WebDAV-Status: 401 Unauthorized', true);
}
exit;
}
if (!isset($GLOBALS['egw_info']['flags']['no_exception_handler']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] !== true)
{
set_exception_handler('egw_exception_handler');
}
/**
* Fail a little bit more gracefully then a catchable fatal error, by throwing an exception
*
* @param int $errno level of the error raised: E_* constants
* @param string $errstr error message
* @param string $errfile filename that the error was raised in
* @param int $errline line number the error was raised at
* @link http://www.php.net/manual/en/function.set-error-handler.php
* @throws ErrorException
*/
function egw_error_handler ($errno, $errstr, $errfile, $errline)
{
switch ($errno)
{
case E_RECOVERABLE_ERROR:
case E_USER_ERROR:
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
case E_WARNING:
case E_USER_WARNING:
// skip message for warnings supressed via @-error-control-operator (eg. @is_dir($path))
// can be commented out to get suppressed warnings too!
if (error_reporting())
{
_egw_log_exception(new egw_exception_warning($errstr.' in '.$errfile.' on line '.$errline));
}
break;
}
}
/**
* Used internally to trace warnings
*/
class egw_exception_warning extends Exception {}
// install our error-handler only for catchable fatal errors and warnings
// following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
set_error_handler('egw_error_handler', E_RECOVERABLE_ERROR|E_USER_ERROR|E_WARNING|E_USER_WARNING);

332
api/src/loader/security.php Executable file
View File

@ -0,0 +1,332 @@
<?php
/**
* EGroupware XSS protection and other security relevant functions
*
* Usually loaded via header.inc.php or api/src/loader/common.php
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
use EGroupware\Api;
/**
* check $_REQUEST data for XSS, vars containing script tags are moved to $GLOBALS['egw_unset_vars']
*
* @internal
* @param array &$var reference of array to check
* @param string $name ='' name of the array
*/
function _check_script_tag(&$var,$name='')
{
static $preg=null;
//old: '/<\/?[^>]*\b(iframe|script|javascript|on(before)?(abort|blur|change|click|dblclick|error|focus|keydown|keypress|keyup|load|mousedown|mousemove|mouseout|mouseover|mouseup|reset|select|submit|unload))\b[^>]*>/i';
if (!isset($preg)) $preg =
// forbidden tags like iframe or script
'/(<(\s*\/)?\s*(iframe|script|object|embed|math|meta)[^a-z0-9]|'.
// on* attributes
'<[^>]*on(before)?(abort|blur|change|click|dblclick|error|focus|keydown|keypress|keyup|load|mouse[^=]+|reset|select|submit|unload|resize|propertychange|page[^=]*|scroll|readystatechange|start|popstate|form[^=]+|input)\s*=|'.
// ="javascript:*" diverse javascript attribute value
'<[^>]+(href|src|dynsrc|lowsrc|background|style|poster|action)\s*=\s*("|\')?[^"\']*javascript|'.
// benavior:url and expression in style attribute
'<[^>]+style\s*=\s*("|\')[^>]*(behavior\s*:\s*url|expression)\s*\()/i';
if (is_array($var))
{
foreach($var as $key => $val)
{
if (is_array($val))
{
_check_script_tag($var[$key],$name.'['.$key.']');
}
elseif(strpos($val, '<') !== false) // speedup: ignore everything without <
{
if (preg_match($preg,$val))
{
// special handling for $_POST[json_data], to decend into it's decoded content, fixing json direct might break json syntax
if ($name == '_POST' && $key == 'json_data' && ($json_data = json_decode($val, true)))
{
_check_script_tag($json_data, $name.'[json_data]');
$_REQUEST[$key] = $var[$key] = json_encode($json_data);
continue;
}
error_log(__FUNCTION__."(,$name) ${name}[$key] = ".$var[$key]);
$GLOBALS['egw_unset_vars'][$name.'['.$key.']'] = $var[$key];
// attempt to clean the thing
$var[$key] = $val = Api\Html\HtmLawed::purify($val);
// check if we succeeded, if not drop the var anyway, keep the egw_unset_var in any case
if (preg_match($preg,$val))
{
error_log("*** _check_script_tag($name): unset(${name}[$key]) with value $val***");
unset($var[$key]);
}
}
}
}
// in case some stupid old code expects the array-pointer to be at the start of the array
reset($var);
}
}
/* some _check_script_tag tests, should be commented out by default
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
{
if (!defined('EGW_INCLUDE_ROOT'))
{
define(EGW_INCLUDE_ROOT, realpath(dirname(__FILE__).'/../..'));
define(EGW_API_INC, realpath(dirname(__FILE__)));
}
$total = $num_failed = 0;
$patterns = array(
// pattern => true: should fail, false: should not fail
'< script >alert(1)< / script >' => true,
'<span onMouseOver ="alert(1)">blah</span>' => true,
'<a href= "JaVascript: alert(1)">Click Me</a>' => true,
// from https://www.acunetix.com/websitesecurity/cross-site-scripting/
'<body onload=alert("XSS")>' => true,
'<body background="javascript:alert("XSS")">' => true,
'<iframe src=”http://evil.com/xss.html”>' => true,
'<input type="image" src="javascript:alert(\'XSS\');">' => true,
'<link rel="stylesheet" href="javascript:alert(\'XSS\');">' => true,
'<table background="javascript:alert(\'XSS\')">' => true,
'<td background="javascript:alert(\'XSS\')">' => true,
'<div style="background-image: url(javascript:alert(\'XSS\'))">' => true,
'<div style="width: expression(alert(\'XSS\'));">' => true,
'<object type="text/x-scriptlet" data="http://hacker.com/xss.html">' => true,
// false positiv tests
'If 1 < 2, what does that mean for description, if 2 > 1.' => false,
'If 1 < 2, what does that mean for a script, if 2 > 1.' => false,
'<div>Script and Javascript: not evil ;-)' => false,
'<span>style=background-color' => false,
'<font face="Script MT Bold" size="4"><span style="font-size:16pt;">Hugo Sonstwas</span></font>' => false,
'<mathias@stylite.de>' => false,
);
foreach($patterns as $pattern => $should_fail)
{
$test = array($pattern);
unset($GLOBALS['egw_unset_vars']);
_check_script_tag($test,'test');
$failed = isset($GLOBALS['egw_unset_vars']) !== $should_fail;
++$total;
if ($failed) $num_failed++;
echo "<p style='color: ".($failed?'red':'black')."'> ".Api\Html::htmlspecialchars($pattern).' '.
(isset($GLOBALS['egw_unset_vars'])?'removed':'passed')."</p>";
}
$x = 1;
// urls with attack vectors
$urls = array(
// we currently fail 76 of 666 test, thought they seem not to apply to our use case, as we check request data
'https://gist.github.com/JohannesHoppe/5612274' => file(
'https://gist.githubusercontent.com/JohannesHoppe/5612274/raw/60016bccbfe894dcd61a6be658a4469e403527de/666_lines_of_XSS_vectors.html'),
// we currently fail 44 of 140 tests, thought they seem not to apply to our use case, as we check request data
'https://html5sec.org/' => call_user_func(function() {
$payloads = $items = null;
if (!($items_js = file_get_contents('https://html5sec.org/items.js')) ||
!preg_match_all("|^\s+'data'\s+:\s+'(.*)',$|m", $items_js, $items, PREG_PATTERN_ORDER) ||
!($payload_js = file_get_contents('https://html5sec.org/payloads.js')) ||
!preg_match_all("|^\s+'([^']+)'\s+:\s+'(.*)',$|m", $payload_js, $payloads, PREG_PATTERN_ORDER))
{
return false;
}
$replace = array(
"\\'" => "'",
'\\\\'=> '\\,',
'\r' => "\r",
'\n' => "\n",
);
foreach($payloads[1] as $n => $from) {
$replace['%'.$from.'%'] = $payloads[2][$n];
}
return array_map(function($item) use ($replace) {
return strtr($item, $replace);
}, $items[1]);
}),
);
foreach($urls as $url => $vectors)
{
// no all xss attack vectors from http://ha.ckers.org/xssAttacks.xml are relevant here! (needs interpretation)
if (!$vectors)
{
echo "<p style='color:red'>Could NOT download or parse $url with attack vectors!</p>\n";
continue;
}
echo "<p><b>Attacks from <a href='$url' target='_blank'>$url</a> with ".count($vectors)." tests:</b></p>";
foreach($vectors as $line => $pattern)
{
$test = array($pattern);
unset($GLOBALS['egw_unset_vars']);
_check_script_tag($test, 'line '.(1+$line));
$failed = !isset($GLOBALS['egw_unset_vars']);
++$total;
if ($failed) $num_failed++;
echo "<p style='color: ".($failed?'red':'black')."'>".(1+$line).": ".Api\Html::htmlspecialchars($pattern).' '.
(isset($GLOBALS['egw_unset_vars'])?'removed':'passed')."</p>";
}
}
die("<p style='color: ".($num_failed?'red':'black')."'>Tests finished: $num_failed / $total failed</p>");
}*/
foreach(array('_GET','_POST','_REQUEST','HTTP_GET_VARS','HTTP_POST_VARS') as $n => $where)
{
$pregs = array(
'order' => '/^[a-zA-Z0-9_,]*$/',
'sort' => '/^(ASC|DESC|asc|desc|0|1|2|3|4|5|6|7){0,1}$/',
);
foreach(array('order','sort') as $name)
{
if (isset($GLOBALS[$where][$name]) && !is_array($GLOBALS[$where][$name]) && !preg_match($pregs[$name],$GLOBALS[$where][$name]))
{
$GLOBALS[$where][$name] = '';
}
}
// do the check for script-tags only for _GET and _POST or if we found something in _GET and _POST
// speeds up the execusion a bit
if (isset($GLOBALS[$where]) && is_array($GLOBALS[$where]) && ($n < 2 || isset($GLOBALS['egw_unset_vars'])))
{
_check_script_tag($GLOBALS[$where],$where);
}
}
//if (is_array($GLOBALS['egw_unset_vars'])) { echo "egw_unset_vars=<pre>".htmlspecialchars(print_r($GLOBALS['egw_unset_vars'],true))."</pre>"; exit; }
// $GLOBALS[egw_info][flags][currentapp] and die if it contains something nasty or unexpected
if (isset($GLOBALS['egw_info']) && isset($GLOBALS['egw_info']['flags']) &&
isset($GLOBALS['egw_info']['flags']['currentapp']) && !preg_match('/^[A-Za-z0-9_-]+$/',$GLOBALS['egw_info']['flags']['currentapp']))
{
error_log(__FILE__.': '.__LINE__.' Invalid $GLOBALS[egw_info][flags][currentapp]='.array2string($GLOBALS['egw_info']['flags']['currentapp']).', $_SERVER[REQUEST_URI]='.array2string($_SERVER[REQUEST_URI]));
die('Invalid $GLOBALS[egw_info][flags][currentapp]!');
}
// neutralises register_globals On, which is not used by eGW
// some code from the hardend php project: http://www.hardened-php.net/articles/PHPUG-PHP-Sicherheit-Parametermanipulationen.pdf
if (ini_get('register_globals'))
{
function unregister_globals()
{
// protect against GLOBALS overwrite or setting egw_info
if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']) || isset($_REQUEST['egw_info']) || isset($_FILES['egw_info']))
{
die('GLOBALS overwrite detected!!!');
}
// unregister all globals
$noUnset = array('GLOBALS','_GET','_POST','_COOKIE','_SERVER','_ENV','_FILES','xajax');
foreach(array_unique(array_merge(
array_keys($_GET),array_keys($_POST),array_keys($_COOKIE),array_keys($_SERVER),array_keys($_ENV),array_keys($_FILES),
isset($_SESSION) && is_array($_SESSION) ? array_keys($_SESSION) : array())) as $k)
{
if (!in_array($k,$noUnset) && isset($GLOBALS[$k]))
{
unset($GLOBALS[$k]);
}
}
}
unregister_globals();
}
/**
* Unserialize a php serialized string, but only if it contains NO objects 'O:\d:"' or 'C:\d:"' pattern
*
* Should be used for all external content, to guard against exploidts.
*
* PHP 7.0+ can be told not to instanciate any classes (and calling eg. it's destructor).
* In fact it instanciates it as __PHP_Incomplete_Class without any methods and therefore disarming threads.
*
* @param string $str
* @return mixed
*/
function php_safe_unserialize($str)
{
if (PHP_VERSION >= 7)
{
return unserialize($str, array('allowed_classes' => false));
}
if ((strpos($str, 'O:') !== false || strpos($str, 'C:') !== false) &&
preg_match('/(^|;|{)[OC]:\d+:"/', $str))
{
error_log(__METHOD__."('$str') contains objects --> return NULL");
return null; // null, not false, to not trigger behavior of returning string itself to app code
}
return unserialize($str);
}
/* some test for object safe unserialisation
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
{
if (php_sapi_name() !== 'cli') echo "<pre>\n";
foreach(array(
// things unsafe to unserialize
"O:34:\"Horde_Kolab_Server_Decorator_Clean\":2:{s:43:\"\x00Horde_Kolab_Server_Decorator_Clean\x00_server\";" => false,
"O:20:\"Horde_Prefs_Identity\":2:{s:9:\"\x00*\x00_prefs\";O:11:\"Horde_Prefs\":2:{s:8:\"\x00*\x00_opts\";a:1:{s:12:\"sizecallback\";" => false,
"a:2:{i:0;O:12:\"Horde_Config\":1:{s:13:\"\x00*\x00_oldConfig\";s:#{php_injection.length}:\"#{php_injection}\";}i:1;s:13:\"readXMLConfig\";}}" => false,
'a:6:{i:0;i:0;i:1;d:2;i:2;s:4:"ABCD";i:3;r:3;i:4;O:8:"my_Class":2:{s:1:"a";r:6;s:1:"b";N;};i:5;C:16:"SplObjectStorage":14:{x:i:0;m:a:0:{}}' => false,
serialize(new stdClass()) => false,
serialize(array(new stdClass(), new SplObjectStorage())) => false,
// string content, safe to unserialize
serialize('O:8:"stdClass"') => true,
serialize('C:16:"SplObjectStorage"') => true,
serialize(array('a' => 'O:8:"stdClass"', 'b' => 'C:16:"SplObjectStorage"')) => true,
// false positive: failing our php<7 regular expression, because it has correct delimiter (^|;|{) in front of pattern :-(
serialize('O:8:"stdClass";C:16:"SplObjectStorage"') => true,
) as $str => $result)
{
if ((bool)($r=php_safe_unserialize($str)) !== $result)
{
if (!$result)
{
if (PHP_VERSION >= 7)
{
if (preg_match_all('/([^ ]+) Object\(/', array2string($r), $matches))
{
foreach($matches[1] as $class)
{
if (!preg_match('/^__PHP_Incomplete_Class(#\d+)?$/', $class))
{
echo "FAILED: $str\n";
continue 2;
}
}
}
echo "passed: ".array2string($str)." = ".array2string($r)."\n";
}
else
{
echo "FAILED: $str\n";
}
}
else
{
echo "false positive: $str\n";
}
}
else
{
echo "passed: $str\n";
}
//echo "result=".array2string($result).", php_save_unserialize('".htmlspecialchars($str)."') = ".array2string(php_safe_unserialize($str))." --> ".array2string((bool)php_safe_unserialize($str))."\n";
}
}*/
/**
* Unserialize a json or php serialized array
*
* Used to migrate from PHP serialized database values to json-encoded ones.
*
* @param string $str string with serialized array
* @param boolean $allow_not_serialized =false true: return $str as is, if it is no serialized array
* @return array|str|false
*/
function json_php_unserialize($str, $allow_not_serialized=false)
{
if ((in_array($str[0], array('a', 'i', 's', 'b', 'O', 'C')) && $str[1] == ':' || $str === 'N;') &&
($arr = php_safe_unserialize($str)) !== false || $str === 'b:0;')
{
return $arr;
}
if (!$allow_not_serialized || $str[0] == '[' || $str[0] == '{' || $str[0] == '"' || $str === 'null' || ($val = json_decode($str)) !== null)
{
return isset($val) ? $val : json_decode($str, true);
}
return $str;
}

View File

@ -1,8 +1,8 @@
<?php <?php
/** /**
* eGroupWare - configuration file * EGroupware - configuration file
* *
* Use eGroupWare's setup to create or edit this configuration file. * Use EGroupware's setup to create or edit this configuration file.
* You do NOT need to copy and edit this file manually! * You do NOT need to copy and edit this file manually!
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
@ -12,20 +12,6 @@
* @version $Id$ * @version $Id$
*/ */
// allow to migrate from phpgw_info to egw_info
if (!isset($GLOBALS['egw_info']) || in_array($GLOBALS['egw_info']['flags']['currentapp'],array('jinn','mydms','tts')))
{
if (!isset($GLOBALS['egw_info']))
{
$GLOBALS['egw_info'] =& $GLOBALS['phpgw_info'];
}
else
{
$GLOBALS['phpgw_info'] =& $GLOBALS['egw_info'];
}
$GLOBALS['egw_info']['flags']['phpgw_compatibility'] = true;
}
// eGW install dir, need to be changed if you copy the server to an other directory // eGW install dir, need to be changed if you copy the server to an other directory
define('EGW_SERVER_ROOT','{SERVER_ROOT}'); define('EGW_SERVER_ROOT','{SERVER_ROOT}');
@ -52,12 +38,6 @@ $GLOBALS['egw_info']['server']['show_domain_selectbox'] = {DOMAIN_SELECTBOX};
$GLOBALS['egw_info']['server']['db_persistent'] = {DB_PERSISTENT}; $GLOBALS['egw_info']['server']['db_persistent'] = {DB_PERSISTENT};
/*
** used session handler: egw_session_files works for all build in php session handlers
** other handlers (like egw_session_memcache) can be enabled here
*/
$GLOBALS['egw_info']['server']['session_handler'] = '{SESSION_HANDLER}';
/* This is used to control mcrypt's use */ /* This is used to control mcrypt's use */
$GLOBALS['egw_info']['server']['mcrypt_enabled'] = {ENABLE_MCRYPT}; $GLOBALS['egw_info']['server']['mcrypt_enabled'] = {ENABLE_MCRYPT};
@ -71,11 +51,8 @@ $GLOBALS['egw_info']['server']['mcrypt_iv'] = '{MCRYPT_IV}';
$GLOBALS['egw_info']['flags']['page_start_time'] = microtime(true); $GLOBALS['egw_info']['flags']['page_start_time'] = microtime(true);
define('DEBUG_API', False); include(EGW_SERVER_ROOT.'/api/setup/setup.inc.php');
define('DEBUG_APP', False); $GLOBALS['egw_info']['server']['versions']['phpgwapi'] = $GLOBALS['egw_info']['server']['versions']['api'] = $setup_info['api']['version'];
include(EGW_SERVER_ROOT.'/phpgwapi/setup/setup.inc.php');
$GLOBALS['egw_info']['server']['versions']['phpgwapi'] = $setup_info['phpgwapi']['version'];
$GLOBALS['egw_info']['server']['versions']['current_header'] = $setup_info['phpgwapi']['versions']['current_header']; $GLOBALS['egw_info']['server']['versions']['current_header'] = $setup_info['phpgwapi']['versions']['current_header'];
unset($setup_info); unset($setup_info);
$GLOBALS['egw_info']['server']['versions']['header'] = '1.29'; $GLOBALS['egw_info']['server']['versions']['header'] = '1.29';
@ -88,11 +65,11 @@ if(!isset($GLOBALS['egw_info']['flags']['noapi']) || !$GLOBALS['egw_info']['flag
{ {
ob_start(); // to prevent error messages to be send before our headers ob_start(); // to prevent error messages to be send before our headers
} }
require_once(EGW_API_INC . '/functions.inc.php'); require_once(EGW_SERVER_ROOT.'/api/src/loader.php');
} }
else else
{ {
require_once(EGW_API_INC . '/common_functions.inc.php'); require_once(EGW_SERVER_ROOT.'/api/src/loader/common.php');
} }
/* /*

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* eGroupWare API - Applications * EGroupware API - Applications
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Mark Peters <skeeter@phpgroupware.org> * @author Mark Peters <skeeter@phpgroupware.org>
@ -10,77 +10,17 @@
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* functions for managing and installing apps * functions for managing and installing apps
* *
* Author: skeeter * Author: skeeter
*/
class applications
{
var $account_id;
var $data = Array();
/**
* Reference to the global db class
* *
* @var egw_db * @deprecated use just methods from Api\Egw\Applications
*/ */
var $db; class applications extends Api\Egw\Applications
var $table_name = 'egw_applications';
/**************************************************************************\
* Standard constructor for setting $this->account_id *
\**************************************************************************/
/**
* standard constructor for setting $this->account_id
*
* @param $account_id account id
*/
function __construct($account_id = '')
{ {
if (is_object($GLOBALS['egw_setup']) && is_object($GLOBALS['egw_setup']->db))
{
$this->db = $GLOBALS['egw_setup']->db;
}
else
{
$this->db = $GLOBALS['egw']->db;
}
$this->account_id = get_account_id($account_id);
}
/**************************************************************************\
* These are the standard $this->account_id specific functions *
\**************************************************************************/
/**
* read from repository
*
* private should only be called from withing this class
*/
function read_repository()
{
if (!isset($GLOBALS['egw_info']['apps']) || !is_array($GLOBALS['egw_info']['apps']))
{
$this->read_installed_apps();
}
$this->data = Array();
if(!$this->account_id)
{
return False;
}
$apps = $GLOBALS['egw']->acl->get_user_applications($this->account_id);
foreach($GLOBALS['egw_info']['apps'] as $app => $data)
{
if (isset($apps[$app]) && $apps[$app])
{
$this->data[$app] =& $GLOBALS['egw_info']['apps'][$app];
}
}
return $this->data;
}
/** /**
* read from the repository * read from the repository
* *
@ -148,7 +88,7 @@ class applications
function save_repository() function save_repository()
{ {
$GLOBALS['egw']->acl->delete_repository("%%", 'run', $this->account_id); $GLOBALS['egw']->acl->delete_repository("%%", 'run', $this->account_id);
foreach($this->data as $app => $data) foreach(array_keys($this->data) as $app)
{ {
if(!$this->is_system_enabled($app)) if(!$this->is_system_enabled($app))
{ {
@ -169,7 +109,7 @@ class applications
{ {
$this->read_repository(); $this->read_repository();
} }
foreach ($this->data as $app => $data) foreach (array_keys($this->data) as $app)
{ {
$apps[] = $this->data[$app]['name']; $apps[] = $this->data[$app]['name'];
} }
@ -195,39 +135,6 @@ class applications
return $this->data; return $this->data;
} }
/**************************************************************************\
* These are the generic functions. Not specific to $this->account_id *
\**************************************************************************/
/**
* populate array with a list of installed apps
*
*/
function read_installed_apps()
{
foreach($this->db->select($this->table_name,'*',false,__LINE__,__FILE__,false,'ORDER BY app_order ASC') as $row)
{
$title = $app_name = $row['app_name'];
if (@is_array($GLOBALS['egw_info']['user']['preferences']) && ($t = lang($app_name)) != $app_name.'*')
{
$title = $t;
}
$GLOBALS['egw_info']['apps'][$app_name] = Array(
'title' => $title,
'name' => $app_name,
'enabled' => True,
'status' => $row['app_enabled'],
'id' => (int)$row['app_id'],
'order' => (int)$row['app_order'],
'version' => $row['app_version'],
'index' => $row['app_index'],
'icon' => $row['app_icon'],
'icon_app'=> $row['app_icon_app'],
);
}
}
/** /**
* check if an app is enabled * check if an app is enabled
* *

View File

@ -1,11 +1,8 @@
<?php <?php
/** /**
* eGroupWare API - Applications * EGroupware API - Applications
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
* Parts Copyright (C) 2003 Free Software Foundation
* @author RalfBecker@outdoor-training.de * @author RalfBecker@outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api * @package api
@ -15,677 +12,11 @@
use EGroupware\Api; use EGroupware\Api;
/** /**
* New written class to create the eGW enviroment AND restore it from a php-session * @deprecated use Api\Egw
*
* Rewritten by RalfBecker@outdoor-training.de to store the eGW enviroment
* (egw-object and egw_info-array) in a php-session and restore it from
* there instead of creating it completly new on each page-request.
* The enviroment gets now created by the egw-class
*
* Use now a php5 getter method to create the usuall subobject on demand, to allow a quicker
* header include on sites not useing php4-restore.
* This also makes a lot of application code, like the following, unnecessary:
* if (!is_object($GLOBALS['egw']->datetime)
* {
* $GLOBALS['egw']->datetime = CreateObject('phpgwapi.datetime');
* }
* You can now simply use $GLOBALS['egw']->datetime, and the egw class instanciates it for you on demand.
*/ */
class egw extends egw_minimal class egw extends Api\Egw{}
{
/**
* Turn on debug mode. Will output additional data for debugging purposes.
* @var string
* @access public
*/
var $debug = 0; // This will turn on debugging information.
/**
* Instance of the account object
*
* @var accounts
*/
var $accounts;
/**
* Instace of the common object
*
* @var common
*/
var $common;
/**
* Instace of the hooks object
*
* @var hooks
*/
var $hooks;
/** /**
* Constructor: Instantiates the sub-classes * @deprecated use Api\Egw\Base
*
* @author RalfBecker@outdoor-training.de
* @param array $domain_names array with valid egw-domain names
*/ */
function __construct($domain_names=null) class egw_minimal extends Api\Egw\Base{}
{
$GLOBALS['egw'] =& $this; // we need to be immediately available there for the other classes we instantiate
// for the migration: reference us to the old phpgw object
$GLOBALS['phpgw'] =& $this;
$this->setup($domain_names,True);
}
/**
* Called every time the constructor is called. Also called by sessions to ensure the correct db,
* in which case we do not recreate the session object.
* @author RalfBecker@outdoor-training.de (moved to setup() by milos@groupwhere.org
* @param array $domain_names array with valid egw-domain names
* @param boolean $createsessionobject True to create the session object (default=True)
*/
function setup($domain_names,$createsessionobject=True)
{
// create the DB-object
// as SiteMgr, Wiki, KnowledgeBase and probably more still use eg next_record(), we stick with Db\Deprecated for now
$this->db = new Api\Db\Deprecated($GLOBALS['egw_info']['server']);
if ($this->debug)
{
$this->db->Debug = 1;
}
$this->db->set_app(Api\Db::API_APPNAME);
// check if eGW is already setup, if not redirect to setup/
try {
$this->db->connect();
$num_config = $this->db->select(config::TABLE,'COUNT(config_name)',false,__LINE__,__FILE__)->fetchColumn();
}
catch(Api\Db\Exception\Connection $e) {
// ignore exception, get handled below
}
catch(Api\Db\Exception\InvalidSql $e1) {
unset($e1); // not used
try {
$phpgw_config = $this->db->select('phpgw_config','COUNT(config_name)',false,__LINE__,__FILE__)->fetchColumn();
}
catch (Api\Db\Exception\InvalidSql $e2) {
unset($e2); // not used
// ignor error, get handled below
}
}
if (!$num_config)
{
// we check for the old table too, to not scare updating users ;-)
if ($phpgw_config)
{
throw new Exception('You need to update EGroupware before you can continue using it.',999);
}
if ($e)
{
throw new Api\Db\Exception\Setup('Connection with '.$e->getMessage()."\n\n".
'Maybe you not created a database for EGroupware yet.',999);
}
throw new Api\Db\Exception\Setup('It appears that you have not created the database tables for EGroupware.',999);
}
// Set the DB's client charset if a system-charset is set and some other values needed by egw_cache (used in config::read)
foreach($this->db->select(config::TABLE,'config_name,config_value',array(
'config_app' => 'phpgwapi',
'config_name' => array('system_charset','install_id','temp_dir'),
),__LINE__,__FILE__) as $row)
{
$GLOBALS['egw_info']['server'][$row['config_name']] = $row['config_value'];
}
if ($GLOBALS['egw_info']['server']['system_charset'] && $GLOBALS['egw_info']['server']['system_charset'] != 'utf-8')
{
$this->db->Link_ID->SetCharSet($GLOBALS['egw_info']['server']['system_charset']);
}
// load up the $GLOBALS['egw_info']['server'] array
$GLOBALS['egw_info']['server'] += config::read('phpgwapi');
// if no server timezone set, use date_default_timezone_get() to determine it once
// it fills to log with deprecated warnings under 5.3 otherwise
if (empty($GLOBALS['egw_info']['server']['server_timezone']) ||
$GLOBALS['egw_info']['server']['server_timezone'] == 'System/Localtime') // treat invalid tz like empty!
{
try
{
$tz = new DateTimeZone(date_default_timezone_get());
config::save_value('server_timezone',$GLOBALS['egw_info']['server']['server_timezone'] = $tz->getName(),'phpgwapi');
error_log(__METHOD__."() stored server_timezone=".$GLOBALS['egw_info']['server']['server_timezone']);
}
catch(Exception $e)
{
// do nothing if new DateTimeZone fails (eg. 'System/Localtime' returned), specially do NOT store it!
error_log(__METHOD__."() NO valid 'date.timezone' set in your php.ini!");
}
}
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
// setup the other subclasses
// translation class is here only for backward compatibility, as all it's methods can be called static now
$this->translation = new translation();
$this->common = new common();
$this->accounts = new accounts();
$this->acl = new acl();
// we instanciate the hooks object here manually, to cache it's hooks in the session
$this->hooks = new hooks();
/* Do not create the session object if called by the sessions class. This way
* we ensure the correct db based on the user domain.
*/
if($createsessionobject)
{
$this->session = new egw_session($domain_names);
}
$this->preferences = new preferences();
$this->applications = new applications();
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout')
{
$this->verify_session();
$this->applications->read_installed_apps(); // to get translated app-titles, has to be after verify_session
$this->define_egw_constants();
$this->check_app_rights();
$this->load_optional_classes();
}
else // set the defines for login, in case it's more then just login
{
$this->define_egw_constants();
}
}
/**
* __wakeup function gets called by php while unserializing the egw-object, eg. reconnects to the DB
*
* @author RalfBecker@outdoor-training.de
*/
function __wakeup()
{
$GLOBALS['egw'] =& $this; // we need to be immediately available there for the other classes we instantiate
// for the migration: reference us to the old phpgw object
$GLOBALS['phpgw'] =& $this;
if ($GLOBALS['egw_info']['server']['system_charset'])
{
$this->db->Link_ID->SetCharSet($GLOBALS['egw_info']['server']['system_charset']);
}
// restoring server timezone, to avoid warnings under php5.3
if (!empty($GLOBALS['egw_info']['server']['server_timezone']))
{
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
}
$this->define_egw_constants();
}
/**
* wakeup2 function needs to be called after unserializing the egw-object
*
* It adapts the restored object/enviroment to the changed (current) application / page-request
*
* @author RalfBecker@outdoor-training.de
*/
function wakeup2()
{
// do some application specific stuff, need to be done as we are different (current) app now
if (isset($this->template))
{
$this->template->set_root(EGW_APP_TPL);
}
// init the translation class, necessary as own wakeup would run before our's
translation::init(isset($GLOBALS['egw_info']['flags']['load_translations']) ? $GLOBALS['egw_info']['flags']['load_translations'] : true);
$this->unset_datetime();
// verify the session
$GLOBALS['egw']->verify_session();
$GLOBALS['egw']->check_app_rights();
$this->load_optional_classes();
}
/**
* Unsetting datetime object, so time gets updated
*/
function unset_datetime()
{
unset($this->datetime);
}
/**
* load optional classes by mentioning them in egw_info[flags][enable_CLASS_class] => true
*
* Also loads the template-class if not egw_info[flags][disable_Template_class] is set
*
* Maybe the whole thing should be depricated ;-)
*/
function load_optional_classes()
{
// output the header unless the developer turned it off
if (!@$GLOBALS['egw_info']['flags']['noheader'])
{
common::egw_header();
}
// Load the (depricated) app include files if they exists
if (EGW_APP_INC != "" && ! preg_match ('/phpgwapi/i', EGW_APP_INC) &&
file_exists(EGW_APP_INC . '/functions.inc.php') && !isset($_GET['menuaction']))
{
include(EGW_APP_INC . '/functions.inc.php');
}
if (!@$GLOBALS['egw_info']['flags']['noheader'] && !@$GLOBALS['egw_info']['flags']['noappheader'] &&
file_exists(EGW_APP_INC . '/header.inc.php') && !isset($_GET['menuaction']))
{
include(EGW_APP_INC . '/header.inc.php');
}
}
/**
* Verfiy there is a valid session
*
* One can specify a callback, which gets called if there's no valid session. If the callback returns true, the parameter
* containst account-details (in keys login, passwd and passwd_type) to automatic create an (anonymous session)
*
* It also checks if enforce_ssl is set in the DB and redirects to the https:// version of the site.
*
* If there is no valid session and none could be automatic created, the function will redirect to login and NOT return
*/
function verify_session()
{
if($GLOBALS['egw_info']['server']['enforce_ssl'] === 'redirect' && !$_SERVER['HTTPS'])
{
Header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
exit;
}
// check if we have a session, if not try to automatic create one
if ($this->session->verify()) return true;
$account = null;
if (($account_callback = $GLOBALS['egw_info']['flags']['autocreate_session_callback']) && is_callable($account_callback) &&
($sessionid = call_user_func_array($account_callback,array(&$account))) === true) // $account_call_back returns true, false or a session-id
{
$sessionid = $this->session->create($account);
}
if (!$sessionid)
{
//echo "<p>account_callback='$account_callback', account=".print_r($account,true).", sessionid=$sessionid</p>\n"; exit;
// we forward to the same place after the re-login
if ($GLOBALS['egw_info']['server']['webserver_url'] && $GLOBALS['egw_info']['server']['webserver_url'] != '/' &&
($webserver_path = parse_url($GLOBALS['egw_info']['server']['webserver_url'],PHP_URL_PATH)) && $webserver_path != '/')
{
// we have to use only path component, to cope with domains like http://egroupware.domain.com and /egroupware
list(,$relpath) = explode($webserver_path,parse_url($_SERVER['PHP_SELF'],PHP_URL_PATH),2);
}
else // the webserver-url is empty or just a slash '/' (eGW is installed in the docroot and no domain given)
{
$matches = null;
if (preg_match('/^https?:\/\/[^\/]*\/(.*)$/',$relpath=$_SERVER['PHP_SELF'],$matches))
{
$relpath = $matches[1];
}
}
// this removes the sessiondata if its saved in the URL
$query = preg_replace('/[&]?sessionid(=|%3D)[^&]+&kp3(=|%3D)[^&]+&domain=.*$/','',$_SERVER['QUERY_STRING']);
if ($GLOBALS['egw_info']['server']['http_auth_types'])
{
$redirect = '/phpgwapi/ntlm/index.php?';
}
else
{
$redirect = '/login.php?';
// only add "your session could not be verified", if a sessionid is given (cookie or on url)
if (egw_session::get_sessionid()) $redirect .= 'cd=10&';
}
if ($relpath) $redirect .= 'phpgw_forward='.urlencode($relpath.(!empty($query) ? '?'.$query : ''));
self::redirect_link($redirect);
}
}
/**
* Verify the user has rights for the requested app
*
* If the user has no rights for the app (eg. called via URL) he get a permission denied page (this function does NOT return)
*
* @throws Api\Exception\Redirect for anonymous user accessing something he has no rights to
* @throws Api\Exception\NoPermission\Admin
* @throws Api\Exception\NoPermission\App
*/
function check_app_rights()
{
$this->currentapp = $GLOBALS['egw_info']['flags']['currentapp']; // some apps change it later
if (!in_array($GLOBALS['egw_info']['flags']['currentapp'], array('api', 'home'))) // give everyone implicit home rights
{
// This will need to use ACL in the future
if (!$GLOBALS['egw_info']['user']['apps'][$currentapp = $GLOBALS['egw_info']['flags']['currentapp']] ||
($GLOBALS['egw_info']['flags']['admin_only'] && !$GLOBALS['egw_info']['user']['apps']['admin']))
{
// present a login page, if anon user has no right for an application
if ($this->session->session_flags == 'A')
{
// need to destroy a basic auth session here, because it will only be available on current url
if (($sessionid = egw_session::get_sessionid(true)))
{
$GLOBALS['egw']->session->destroy($sessionid);
}
throw new Api\Exception\Redirect(egw::link('/logout.php'));
}
if ($currentapp == 'admin' || $GLOBALS['egw_info']['flags']['admin_only'])
{
throw new Api\Exception\NoPermission\Admin();
}
throw new Api\Exception\NoPermission\App($currentapp);
}
}
}
/**
* create all the defines / constants of the eGW-environment (plus the deprecated phpgw ones)
*/
function define_egw_constants()
{
define('EGW_ACL_READ',1);
define('EGW_ACL_ADD',2);
define('EGW_ACL_EDIT',4);
define('EGW_ACL_DELETE',8);
define('EGW_ACL_PRIVATE',16);
define('EGW_ACL_GROUP_MANAGERS',32);
define('EGW_ACL_CUSTOM_1',64);
define('EGW_ACL_CUSTOM_2',128);
define('EGW_ACL_CUSTOM_3',256);
// and the old ones
define('PHPGW_ACL_READ',1);
define('PHPGW_ACL_ADD',2);
define('PHPGW_ACL_EDIT',4);
define('PHPGW_ACL_DELETE',8);
define('PHPGW_ACL_PRIVATE',16);
define('PHPGW_ACL_GROUP_MANAGERS',32);
define('PHPGW_ACL_CUSTOM_1',64);
define('PHPGW_ACL_CUSTOM_2',128);
define('PHPGW_ACL_CUSTOM_3',256);
// A few hacker resistant constants that will be used throught the program
define('EGW_TEMPLATE_DIR', $this->common->get_tpl_dir('phpgwapi'));
define('EGW_IMAGES_DIR', $this->common->get_image_path('phpgwapi'));
define('EGW_IMAGES_FILEDIR', $this->common->get_image_dir('phpgwapi'));
define('EGW_APP_ROOT', $this->common->get_app_dir());
define('EGW_APP_INC', $this->common->get_inc_dir());
define('EGW_APP_TPL', $this->common->get_tpl_dir());
define('EGW_IMAGES', $this->common->get_image_path());
define('EGW_APP_IMAGES_DIR', $this->common->get_image_dir());
// and the old ones
define('PHPGW_TEMPLATE_DIR',EGW_TEMPLATE_DIR);
define('PHPGW_IMAGES_DIR',EGW_IMAGES_DIR);
define('PHPGW_IMAGES_FILEDIR',EGW_IMAGES_FILEDIR);
define('PHPGW_APP_ROOT',EGW_APP_ROOT);
define('PHPGW_APP_INC',EGW_APP_INC);
define('PHPGW_APP_TPL',EGW_APP_TPL);
define('PHPGW_IMAGES',EGW_IMAGES);
define('PHPGW_APP_IMAGES_DIR',EGW_APP_IMAGES_DIR);
}
/**
* force the session cache to be re-created, because some of it's data changed
*
* Needs to be called if user-preferences, system-config or enabled apps of the current user have been changed and
* the change should have immediate effect
*/
static function invalidate_session_cache()
{
unset($_SESSION['egw_info_cache']);
unset($_SESSION['egw_object_cache']);
}
/**
* run string through htmlspecialchars and stripslashes
*
* @param string $s
* @return string The string with html special characters replaced with entities
*/
static function strip_html($s)
{
return htmlspecialchars(stripslashes($s));
}
/**
* Link url generator
*
* @param string $url url link is for
* @param string|array $extravars ='' extra params to be added to url
* @param string $link_app =null if appname or true, some templates generate a special link-handler url
* @return string The full url after processing
*/
static function link($url, $extravars = '', $link_app=null)
{
return $GLOBALS['egw']->framework->link($url, $extravars, $link_app);
}
/**
* Redirects direct to a generated link
*
* @param string $url url link is for
* @param string|array $extravars ='' extra params to be added to url
* @param string $link_app =null if appname or true, some templates generate a special link-handler url
* @return string The full url after processing
*/
static function redirect_link($url, $extravars='', $link_app=null)
{
return $GLOBALS['egw']->framework->redirect_link($url, $extravars, $link_app);
}
/**
* Handles redirects under iis and apache, it does NOT return (calls exit)
*
* This function handles redirects under iis and apache it assumes that $phpgw->link() has already been called
*
* @param string $url url to redirect to
* @param string $link_app =null appname to redirect for, default currentapp
*/
static function redirect($url, $link_app=null)
{
Api\Framework::redirect($url, $link_app);
}
/**
* Shortcut to translation class
*
* This function is a basic wrapper to translation::translate()
*
* @deprecated only used in the old timetracker
* @param string The key for the phrase
* @see translation::translate()
*/
static function lang($key,$args=null)
{
if (!is_array($args))
{
$args = func_get_args();
array_shift($args);
}
return translation::translate($key,$args);
}
/**
* registered shutdown callbacks and optional arguments
*
* @var array
*/
private static $shutdown_callbacks = array();
/**
* Register a callback to run on shutdown AFTER output send to user
*
* Allows eg. static classes (no destructor) to run on shutdown AND
* garanties to run AFTER output send to user.
*
* @param callable $callback use array($classname, $method) for static methods
* @param array $args =array()
*/
public static function on_shutdown($callback, array $args=array())
{
array_unshift($args, $callback);
// prepend new callback, to run them in oposite order they are registered
array_unshift(self::$shutdown_callbacks, $args);
}
/**
* Shutdown handler running all registered on_shutdown callbacks and then disconnecting from db
*/
function __destruct()
{
if (!defined('EGW_SHUTDOWN'))
{
define('EGW_SHUTDOWN',True);
// send json response BEFORE flushing output
if (egw_json_request::isJSONRequest())
{
egw_json_response::sendResult();
}
// run all on_shutdown callbacks with session in their name (eg. egw_link::save_session_cache), do NOT stop on exceptions
foreach(self::$shutdown_callbacks as $n => $data)
{
try {
//error_log(__METHOD__."() running ".array2string($data));
$callback = array_shift($data);
if (!is_array($callback) || strpos($callback[1], 'session') === false) continue;
call_user_func_array($callback, $data);
}
catch (Exception $ex) {
_egw_log_exception($ex);
}
unset(self::$shutdown_callbacks[$n]);
}
// now we can close the session
// without closing the session fastcgi_finish_request() will NOT send output to user
if (isset($GLOBALS['egw']->session) && is_object($GLOBALS['egw']->session)) $GLOBALS['egw']->session->commit_session();
// flush all output to user
/* does NOT work on Apache :-(
for($i = 0; ob_get_level() && $i < 10; ++$i)
{
ob_end_flush();
}
flush();*/
// working for fastCGI :-)
if (function_exists('fastcgi_finish_request') && substr($_SERVER['PHP_SELF'], -32) != '/phpgwapi/cron/asyncservices.php')
{
fastcgi_finish_request();
}
// run all on_shutdown, do NOT stop on exceptions
foreach(self::$shutdown_callbacks as $data)
{
try {
//error_log(__METHOD__."() running ".array2string($data));
$callback = array_shift($data);
call_user_func_array($callback, $data);
}
catch (Exception $ex) {
_egw_log_exception($ex);
}
}
// call the asyncservice check_run function if it is not explicitly set to cron-only
if (!$GLOBALS['egw_info']['server']['asyncservice']) // is default
{
ExecMethod('phpgwapi.asyncservice.check_run','fallback');
}
$this->db->disconnect();
}
}
}
/**
* Minimal eGW object used in setup, does not instanciate anything by default
*
*/
class egw_minimal
{
/**
* Instance of the db-object
*
* @var egw_db
*/
var $db;
/**
* Current app at the instancation of the class
*
* @var string
*/
var $currentapp;
/**
* Global ADOdb object, need to be defined here, to not call magic __get method
*
* @var ADOConnection
*/
var $ADOdb;
/**
* Classes which get instanciated in a different name
*
* @var array
*/
static $sub_objects = array(
'log' => 'errorlog',
// 'js' => 'javascript',
'link' => 'bolink', // depricated use static egw_link methods
'datetime' => 'egw_datetime',
'framework' => true, // special handling in __get()
'template' => 'Template',
'session' => 'egw_session', // otherwise $GLOBALS['egw']->session->appsession() fails
// classes moved to new api dir
'ldap' => true,
'auth' => 'EGroupware\\Api\\Auth',
);
/**
* Magic function to check if a sub-object is set
*
* @param string $name
* @return boolean
*/
function __isset($name)
{
//error_log(__METHOD__."($name)");
return isset($this->$name);
}
/**
* Magic function to return a sub-object
*
* @param string $name
* @return mixed
*/
function __get($name)
{
//error_log(__METHOD__."($name)".function_backtrace());
if ($name == 'js') $name = 'framework'; // javascript class is integrated now into framework
if (isset($this->$name))
{
return $this->$name;
}
if (!isset(self::$sub_objects[$name]) && !class_exists($name))
{
if ($name != 'ADOdb') error_log(__METHOD__.": There's NO $name object! ".function_backtrace());
return null;
}
switch($name)
{
case 'framework':
return $this->framework = egw_framework::factory();
case 'template': // need to be instancated for the current app
if (!($tpl_dir = common::get_tpl_dir($this->currentapp)))
{
return null;
}
return $this->template = new Template($tpl_dir);
case 'ldap':
return $this->ldap = Api\Ldap::factory(false);
default:
$class = isset(self::$sub_objects[$name]) ? self::$sub_objects[$name] : $name;
break;
}
return $this->$name = new $class();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,931 @@
<?php
/**
* EGroupware deprecated global functions
*
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
*
* @link http://www.egroupware.org
* @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
use EGroupware\Api;
/**
* Load a class and include the class file if not done so already.
*
* This function is used to create an instance of a class, and if the class file has not been included it will do so.
* $GLOBALS['egw']->acl =& CreateObject('phpgwapi.acl');
*
* @author RalfBecker@outdoor-training.de
* @param $classname name of class
* @param $p1,$p2,... class parameters (all optional)
* @return object reference to an object
*/
function CreateObject($class)
{
list($appname,$classname) = explode('.',$class);
if (!class_exists($classname))
{
static $replace = array(
'datetime' => 'egw_datetime',
'uitimesheet' => 'timesheet_ui',
'uiinfolog' => 'infolog_ui',
'uiprojectmanager' => 'projectmanager_ui',
'uiprojectelements' => 'projectmanager_elements_ui',
'uiroles' => 'projectmanager_roles_ui',
'uimilestones' => 'projectmanager_milestones_ui',
'uipricelist' => 'projectmanager_pricelist_ui',
'bowiki' => 'wiki_bo',
'uicategories' => 'admin_categories',
'defaultimap' => 'emailadmin_oldimap',
);
if (!file_exists(EGW_INCLUDE_ROOT.'/'.$appname.'/inc/class.'.$classname.'.inc.php') || isset($replace[$classname]))
{
if (isset($replace[$classname]))
{
//throw new Exception(__METHOD__."('$class') old classname '$classname' used in menuaction=$_GET[menuaction]!");
error_log(__METHOD__."('$class') old classname '$classname' used in menuaction=$_GET[menuaction]!");
$classname = $replace[$classname];
}
}
if (!file_exists($f=EGW_INCLUDE_ROOT.'/'.$appname.'/inc/class.'.$classname.'.inc.php'))
{
throw new Api\Exception\AssertionFailed(__FUNCTION__."($classname) file $f not found!");
}
// this will stop php with a 500, if the class does not exist or there are errors in it (syntax error go into the error_log)
require_once(EGW_INCLUDE_ROOT.'/'.$appname.'/inc/class.'.$classname.'.inc.php');
}
$args = func_get_args();
switch(count($args))
{
case 1:
$obj = new $classname;
break;
case 2:
$obj = new $classname($args[1]);
break;
case 3:
$obj = new $classname($args[1],$args[2]);
break;
case 4:
$obj = new $classname($args[1],$args[2],$args[3]);
break;
default:
$code = '$obj = new ' . $classname . '(';
foreach(array_keys($args) as $n)
{
if ($n)
{
$code .= ($n > 1 ? ',' : '') . '$args[' . $n . ']';
}
}
$code .= ');';
eval($code);
break;
}
if (!is_object($obj))
{
echo "<p>CreateObject('$class'): Cant instanciate class!!!<br />\n".function_backtrace(1)."</p>\n";
}
return $obj;
}
/**
* Execute a function with multiple arguments
* We take object $GLOBALS[classname] from class if exists
*
* @param string app.class.method method to execute
* @example ExecObject('etemplates.so_sql.search',$criteria,$key_only,...);
* @return mixed reference to returnvalue of the method
*/
function &ExecMethod2($acm)
{
// class::method is php5.2.3+
if (strpos($acm,'::') !== false && version_compare(PHP_VERSION,'5.2.3','<'))
{
list($class,$method) = explode('::',$acm);
$acm = array($class,$method);
}
if (!is_callable($acm))
{
list(,$class,$method) = explode('.',$acm);
if (!is_object($obj =& $GLOBALS[$class]))
{
if (class_exists($class))
{
$obj = new $class;
}
else
{
$obj = CreateObject($acm);
}
}
if (!method_exists($obj,$method))
{
echo "<p><b>".function_backtrace()."</b>: no methode '$method' in class '$class'</p>\n";
return False;
}
$acm = array($obj,$method);
}
$args = func_get_args();
unset($args[0]);
return call_user_func_array($acm,$args);
}
/**
* Execute a function, and load a class and include the class file if not done so already.
*
* This function is used to create an instance of a class, and if the class file has not been included it will do so.
*
* @author seek3r
* @param $method to execute
* @param $functionparam function param should be an array
* @param $loglevel developers choice of logging level
* @param $classparams params to be sent to the contructor
* @return mixed returnvalue of method
*/
function ExecMethod($method, $functionparam = '_UNDEF_', $loglevel = 3, $classparams = '_UNDEF_')
{
unset($loglevel); // not used
/* Need to make sure this is working against a single dimensional object */
$partscount = count(explode('.',$method)) - 1;
if (!is_callable($method) && $partscount == 2)
{
list($appname,$classname,$functionname) = explode(".", $method);
if (!is_object($GLOBALS[$classname]))
{
// please note: no reference assignment (=&) here, as $GLOBALS is a reference itself!!!
if ($classparams != '_UNDEF_' && ($classparams || $classparams != 'True'))
{
$GLOBALS[$classname] = CreateObject($appname.'.'.$classname, $classparams);
}
elseif (class_exists($classname))
{
$GLOBALS[$classname] = new $classname;
}
else
{
$GLOBALS[$classname] = CreateObject($appname.'.'.$classname);
}
}
if (!method_exists($GLOBALS[$classname],$functionname))
{
error_log("ExecMethod('$method', ...) No methode '$functionname' in class '$classname'! ".function_backtrace());
return false;
}
$method = array($GLOBALS[$classname],$functionname);
}
if (is_callable($method))
{
return $functionparam != '_UNDEF_' ? call_user_func($method,$functionparam) : call_user_func($method);
}
error_log("ExecMethod('$method', ...) Error in parts! ".function_backtrace());
return false;
}
/**
* prepend a prefix to an array of table names
*
* @author Adam Hull (aka fixe) - No copyright claim
* @param $prefix the string to be prepended
* @param $tables and array of tables to have the prefix prepended to
* @return array of table names with the prefix prepended
*/
function prepend_tables_prefix($prefix,$tables)
{
foreach($tables as $key => $value)
{
$tables[$key] = $prefix.$value;
}
return $tables;
}
/**
* print debug data only when debugging mode is turned on.
*
* @author seek3r
* This function is used to debugging data.
* print_debug('this is some debugging data',$somevar);
*/
function print_debug($message,$var = 'messageonly',$part = 'app', $level = 3)
{
unset($message, $var, $part, $level);
}
/**
* Allows for array and direct function params as well as sanatization.
*
* @author seek3r
* This function is used to validate param data as well as offer flexible function usage.
*
function somefunc()
{
$expected_args[0] = Array('name'=>'fname','default'=>'joe', 'type'=>'string');
$expected_args[1] = Array('name'=>'mname','default'=>'hick', 'type'=>'string');
$expected_args[2] = Array('name'=>'lname','default'=>'bob', 'type'=>'string');
$recieved_args = func_get_args();
$args = safe_args($expected_args, $recieved_args,__LINE__,__FILE__);
echo 'Full name: '.$args['fname'].' '.$args['fname'].' '.$args['lname'].'<br>';
//default result would be:
// Full name: joe hick bob<br>
}
Using this it is possible to use the function in any of the following ways
somefunc('jack','city','brown');
or
somefunc(array('fname'=>'jack','mname'=>'city','lname'=>'brown'));
or
somefunc(array('lname'=>'brown','fname'=>'jack','mname'=>'city'));
For the last one, when using named params in an array you dont have to follow any order
All three would result in - Full name: jack city brown<br>
When you use this method of handling params you can secure your functions as well offer
flexibility needed for both normal use and web services use.
If you have params that are required just set the default as ##REQUIRED##
Users of your functions can also use ##DEFAULT## to use your default value for a param
when using the standard format like this:
somefunc('jack','##DEFAULT##','brown');
This would result in - Full name: jack hick brown<br>
Its using the default value for the second param.
Of course if you have the second param as a required field it will fail to work.
*/
function safe_args($expected, $recieved, $line='??', $file='??')
{
/* This array will contain all the required fields */
$required = Array();
/* This array will contain all types for sanatization checking */
/* only used when an array is passed as the first arg */
$types = Array();
/* start by looping thru the expected list and set params with */
/* the default values */
$num = count($expected);
for ($i = 0; $i < $num; $i++)
{
$args[$expected[$i]['name']] = $expected[$i]['default'];
if ($expected[$i]['default'] === '##REQUIRED##')
{
$required[$expected[$i]['name']] = True;
}
$types[$expected[$i]['name']] = $expected[$i]['type'];
}
/* Make sure they passed at least one param */
if(count($recieved) != 0)
{
/* if used as standard function we loop thru and set by position */
if(!is_array($recieved[0]))
{
for ($i = 0; $i < $num; $i++)
{
if(isset($recieved[$i]) && $recieved[$i] !== '##DEFAULT##')
{
if(sanitize($recieved[$i],$expected[$i]['type']))
{
$args[$expected[$i]['name']] = $recieved[$i];
unset($required[$expected[$i]['name']]);
}
else
{
echo 'Fatal Error: Invalid paramater type for '.$expected[$i]['name'].' on line '.$line.' of '.$file.'<br>';
exit;
}
}
}
}
/* if used as standard function we loop thru and set by position */
else
{
for ($i = 0; $i < $num; $i++)
{
$types[$expected[$i]['name']] = $expected[$i]['type'];
}
while(list($key,$val) = each($recieved[0]))
{
if($val !== '##DEFAULT##')
{
if(sanitize($val,$types[$key]) == True)
{
$args[$key] = $val;
unset($required[$key]);
}
else
{
echo 'Fatal Error: Invalid paramater type for '.$key.' on line '.$line.' of '.$file.'<br>';
exit;
}
}
}
}
}
if(count($required) != 0)
{
while (list($key) = each($required))
{
echo 'Fatal Error: Missing required paramater '.$key.' on line '.$line.' of '.$file.'<br>';
}
exit;
}
return $args;
}
/**
* Validate data.
*
* @author seek3r
* This function is used to validate input data.
* sanitize('number',$somestring);
*/
function sanitize($string,$type)
{
switch ($type)
{
case 'bool':
if ($string == 1 || $string == 0)
{
return True;
}
break;
case 'isprint':
$length = strlen($string);
$position = 0;
while ($length > $position)
{
$char = substr($string, $position, 1);
if ($char < ' ' || $char > '~')
{
return False;
}
$position = $position + 1;
}
return True;
case 'alpha':
if (preg_match("/^[a-z]+$/i", $string))
{
return True;
}
break;
case 'number':
if (preg_match("/^[0-9]+$/i", $string))
{
return True;
}
break;
case 'alphanumeric':
if (preg_match("/^[a-z0-9 -._]+$/i", $string))
{
return True;
}
break;
case 'string':
if (preg_match("/^[a-z]+$/i", $string))
{
return True;
}
break;
case 'ip':
if (preg_match('/'."^[0-9]{1,3}(\.[0-9]{1,3}){3}$".'/i',$string))
{
$octets = preg_split('/\./',$string);
for ($i=0; $i != count($octets); $i++)
{
if ($octets[$i] < 0 || $octets[$i] > 255)
{
return False;
}
}
return True;
}
return False;
case 'file':
if (preg_match("/^[a-z0-9_]+\.+[a-z]+$/i", $string))
{
return True;
}
break;
case 'email':
if (preg_match('/'."^([[:alnum:]_%+=.-]+)@([[:alnum:]_.-]+)\.([a-z]{2,3}|[0-9]{1,3})$".'/i',$string))
{
return True;
}
break;
case 'password':
$password_length = strlen($string);
$password_numbers = Array('0','1','2','3','4','5','6','7','8','9');
$password_special_chars = Array(' ','~','`','!','@','#','$','%','^','&','*','(',')','_','+','-','=','{','}','|','[',']',"\\",':','"',';',"'",'<','>','?',',','.','/');
if(@isset($GLOBALS['egw_info']['server']['pass_min_length']) && is_int($GLOBALS['egw_info']['server']['pass_min_length']) && $GLOBALS['egw_info']['server']['pass_min_length'] > 1)
{
$min_length = $GLOBALS['egw_info']['server']['pass_min_length'];
}
else
{
$min_length = 1;
}
if(@isset($GLOBALS['egw_info']['server']['pass_require_non_alpha']) && $GLOBALS['egw_info']['server']['pass_require_non_alpha'] == True)
{
$pass_verify_non_alpha = False;
}
else
{
$pass_verify_non_alpha = True;
}
if(@isset($GLOBALS['egw_info']['server']['pass_require_numbers']) && $GLOBALS['egw_info']['server']['pass_require_numbers'] == True)
{
$pass_verify_num = False;
}
else
{
$pass_verify_num = True;
}
if(@isset($GLOBALS['egw_info']['server']['pass_require_special_char']) && $GLOBALS['egw_info']['server']['pass_require_special_char'] == True)
{
$pass_verify_special_char = False;
}
else
{
$pass_verify_special_char = True;
}
if ($password_length >= $min_length)
{
for ($i=0; $i != $password_length; $i++)
{
$cur_test_string = substr($string, $i, 1);
if (in_array($cur_test_string, $password_numbers) || in_array($cur_test_string, $password_special_chars))
{
$pass_verify_non_alpha = True;
if (in_array($cur_test_string, $password_numbers))
{
$pass_verify_num = True;
}
elseif (in_array($cur_test_string, $password_special_chars))
{
$pass_verify_special_char = True;
}
}
}
if ($pass_verify_num == False)
{
$GLOBALS['egw_info']['flags']['msgbox_data']['Password requires at least one non-alpha character']=False;
}
if ($pass_verify_num == False)
{
$GLOBALS['egw_info']['flags']['msgbox_data']['Password requires at least one numeric character']=False;
}
if ($pass_verify_special_char == False)
{
$GLOBALS['egw_info']['flags']['msgbox_data']['Password requires at least one special character (non-letter and non-number)']=False;
}
if ($pass_verify_num == True && $pass_verify_special_char == True)
{
return True;
}
return False;
}
$GLOBALS['egw_info']['flags']['msgbox_data']['Password must be at least '.$min_length.' characters']=False;
return False;
case 'any':
return True;
default :
if (isset($GLOBALS['egw_info']['server']['sanitize_types'][$type]['type']))
{
if ($GLOBALS['egw_info']['server']['sanitize_types'][$type]['type']($GLOBALS['egw_info']['server']['sanitize_types'][$type]['string'], $string))
{
return True;
}
}
return False;
}
}
function reg_var($varname, $method='any', $valuetype='alphanumeric',$default_value='',$register=True)
{
if($method == 'any' || $method == array('any'))
{
$method = Array('POST','GET','COOKIE','SERVER','FILES','GLOBAL','DEFAULT');
}
elseif(!is_array($method))
{
$method = Array($method);
}
$cnt = count($method);
for($i=0;$i<$cnt;$i++)
{
switch(strtoupper($method[$i]))
{
case 'DEFAULT':
if($default_value)
{
$value = $default_value;
$i = $cnt+1; /* Found what we were looking for, now we end the loop */
}
break;
case 'GLOBAL':
if(@isset($GLOBALS[$varname]))
{
$value = $GLOBALS[$varname];
$i = $cnt+1;
}
break;
case 'POST':
case 'GET':
case 'COOKIE':
case 'SERVER':
if(phpversion() >= '4.1.0')
{
$meth = '_'.strtoupper($method[$i]);
}
else
{
$meth = 'HTTP_'.strtoupper($method[$i]).'_VARS';
}
if(@isset($GLOBALS[$meth][$varname]))
{
$value = $GLOBALS[$meth][$varname];
$i = $cnt+1;
}
if(get_magic_quotes_gpc() && isset($value))
{
// we need to stripslash 3 levels of arrays
// because of the password function in preferences
// it's named ['user']['variablename']['pw']
// or something like this in projects
// $values['budgetBegin']['1']['year']
if(@is_array($value))
{
/* stripslashes on the first level of array values */
foreach($value as $name => $val)
{
if(@is_array($val))
{
foreach($val as $name2 => $val2)
{
if(@is_array($val2))
{
foreach($val2 as $name3 => $val3)
{
$value[$name][$name2][$name3] = stripslashes($val3);
}
}
else
{
$value[$name][$name2] = stripslashes($val2);
}
}
}
else
{
$value[$name] = stripslashes($val);
}
}
}
else
{
/* stripslashes on this (string) */
$value = stripslashes($value);
}
}
break;
case 'FILES':
if(phpversion() >= '4.1.0')
{
$meth = '_FILES';
}
else
{
$meth = 'HTTP_POST_FILES';
}
if(@isset($GLOBALS[$meth][$varname]))
{
$value = $GLOBALS[$meth][$varname];
$i = $cnt+1;
}
break;
default:
if(@isset($GLOBALS[strtoupper($method[$i])][$varname]))
{
$value = $GLOBALS[strtoupper($method[$i])][$varname];
$i = $cnt+1;
}
break;
}
}
if (@!isset($value))
{
$value = $default_value;
}
if (@!is_array($value))
{
if ($value == '')
{
$result = $value;
}
else
{
if (sanitize($value,$valuetype) == 1)
{
$result = $value;
}
else
{
$result = $default_value;
}
}
}
else
{
reset($value);
while(list($k, $v) = each($value))
{
if ($v == '')
{
$result[$k] = $v;
}
else
{
if (is_array($valuetype))
{
$vt = $valuetype[$k];
}
else
{
$vt = $valuetype;
}
if (sanitize($v,$vt) == 1)
{
$result[$k] = $v;
}
else
{
if (is_array($default_value))
{
$result[$k] = $default_value[$k];
}
else
{
$result[$k] = $default_value;
}
}
}
}
}
if($register)
{
$GLOBALS['egw_info'][$GLOBALS['egw_info']['flags']['currentapp']][$varname] = $result;
}
return $result;
}
/**
* retrieve a value from either a POST, GET, COOKIE, SERVER or from a class variable.
*
* @author skeeter
* This function is used to retrieve a value from a user defined order of methods.
* $this->id = get_var('id',array('HTTP_POST_VARS'||'POST','HTTP_GET_VARS'||'GET','HTTP_COOKIE_VARS'||'COOKIE','GLOBAL','DEFAULT'));
* @param $variable name
* @param $method ordered array of methods to search for supplied variable
* @param $default_value (optional)
*/
function get_var($variable,$method='any',$default_value='')
{
if(!@is_array($method))
{
$method = array($method);
}
return reg_var($variable,$method,'any',$default_value,False);
}
/**
* sets the file system seperator depending on OS
*
* This is completely unnecessary, as you can use forward slashes in php under every OS -- RalfBecker 2005/11/09
*
* @deprecated just use forward slashes supported by PHP on all OS
* @return file system separator
*/
function filesystem_separator()
{
if(PHP_OS == 'Windows' || PHP_OS == 'OS/2' || PHP_OS == 'WINNT')
{
return '\\';
}
else
{
return '/';
}
}
/**
* @deprecated just use forward slashes supported by PHP on all OS
*/
define('SEP', filesystem_separator());
/**
* eGW version checking, is eGW version in $a < $b
*
* @param string $a egw version number to check if less than $b
* @param string $b egw version number to check $a against
* @return boolean True if $a < $b
*/
function alessthanb($a,$b,$DEBUG=False)
{
$num = array('1st','2nd','3rd','4th');
if ($DEBUG)
{
echo'<br>Input values: ' . 'A="'.$a.'", B="'.$b.'"';
}
$newa = str_replace('pre','.',$a);
$newb = str_replace('pre','.',$b);
$testa = explode('.',$newa);
if(@$testa[1] == '')
{
$testa[1] = 0;
}
if(@$testa[3] == '')
{
$testa[3] = 0;
}
$testb = explode('.',$newb);
if(@$testb[1] == '')
{
$testb[1] = 0;
}
if(@$testb[3] == '')
{
$testb[3] = 0;
}
$less = 0;
for ($i=0;$i<count($testa);$i++)
{
if ($DEBUG) { echo'<br>Checking if '. (int)$testa[$i] . ' is less than ' . (int)$testb[$i] . ' ...'; }
if ((int)$testa[$i] < (int)$testb[$i])
{
if ($DEBUG) { echo ' yes.'; }
$less++;
if ($i<3)
{
/* Ensure that this is definitely smaller */
if ($DEBUG) { echo" This is the $num[$i] octet, so A is definitely less than B."; }
$less = 5;
break;
}
}
elseif((int)$testa[$i] > (int)$testb[$i])
{
if ($DEBUG) { echo ' no.'; }
$less--;
if ($i<2)
{
/* Ensure that this is definitely greater */
if ($DEBUG) { echo" This is the $num[$i] octet, so A is definitely greater than B."; }
$less = -5;
break;
}
}
else
{
if ($DEBUG) { echo ' no, they are equal.'; }
$less = 0;
}
}
if ($DEBUG) { echo '<br>Check value is: "'.$less.'"'; }
if ($less>0)
{
if ($DEBUG) { echo '<br>A is less than B'; }
return True;
}
elseif($less<0)
{
if ($DEBUG) { echo '<br>A is greater than B'; }
return False;
}
else
{
if ($DEBUG) { echo '<br>A is equal to B'; }
return False;
}
}
/**
* eGW version checking, is eGW version in $a > $b
*
* @param string $a eGW version number to check if more than $b
* @param string $b eGW version number to check check $a against
* @return boolean True if $a > $b
*/
function amorethanb($a,$b,$DEBUG=False)
{
$num = array('1st','2nd','3rd','4th');
if ($DEBUG)
{
echo'<br>Input values: ' . 'A="'.$a.'", B="'.$b.'"';
}
$newa = str_replace('pre','.',$a);
$newb = str_replace('pre','.',$b);
$testa = explode('.',$newa);
if($testa[3] == '')
{
$testa[3] = 0;
}
$testb = explode('.',$newb);
if($testb[3] == '')
{
$testb[3] = 0;
}
$less = 0;
for ($i=0;$i<count($testa);$i++)
{
if ($DEBUG) { echo'<br>Checking if '. (int)$testa[$i] . ' is more than ' . (int)$testb[$i] . ' ...'; }
if ((int)$testa[$i] > (int)$testb[$i])
{
if ($DEBUG) { echo ' yes.'; }
$less++;
if ($i<3)
{
/* Ensure that this is definitely greater */
if ($DEBUG) { echo" This is the $num[$i] octet, so A is definitely greater than B."; }
$less = 5;
break;
}
}
elseif((int)$testa[$i] < (int)$testb[$i])
{
if ($DEBUG) { echo ' no.'; }
$less--;
if ($i<2)
{
/* Ensure that this is definitely smaller */
if ($DEBUG) { echo" This is the $num[$i] octet, so A is definitely less than B."; }
$less = -5;
break;
}
}
else
{
if ($DEBUG) { echo ' no, they are equal.'; }
$less = 0;
}
}
if ($DEBUG) { echo '<br>Check value is: "'.$less.'"'; }
if ($less>0)
{
if ($DEBUG) { echo '<br>A is greater than B'; }
return True;
}
elseif($less<0)
{
if ($DEBUG) { echo '<br>A is less than B'; }
return False;
}
else
{
if ($DEBUG) { echo '<br>A is equal to B'; }
return False;
}
}
// some not longer necessary defines
if (isset($GLOBALS['egw_info']['flags']['phpgw_compatibility']) && $GLOBALS['egw_info']['flags']['phpgw_compatibility'])
{
define('PHPGW_API_INC',EGW_API_INC);
define('PHPGW_SERVER_ROOT',EGW_SERVER_ROOT);
define('PHPGW_INCLUDE_ROOT',EGW_INCLUDE_ROOT);
/* debugging settings */
define('DEBUG_DATATYPES', True);
define('DEBUG_LEVEL', 3);
define('DEBUG_OUTPUT', 2); /* 1 = screen, 2 = DB. For both use 3. */
define('DEBUG_TIMER', False);
}

View File

@ -1,144 +1,13 @@
<?php <?php
/** /**
* eGroupWare API loader * EGroupware API loader
*
* Rewritten by RalfBecker@outdoor-training.de to store the eGW enviroment
* (egw-object and egw_info-array) in a php-session and restore it from
* there instead of creating it completly new on each page-request.
* The enviroment gets now created by the egw-class
*
* This file was originaly written by Dan Kuykendall and Joseph Engo
* Copyright (C) 2000, 2001 Dan Kuykendall
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package api * @package api
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @deprecated use api/src/loader.php
* @version $Id$ * @version $Id$
*/ */
// E_STRICT in PHP 5.4 gives various strict warnings in working code, which can NOT be easy fixed in all use-cases :-( require_once dirname(dirname(__DIR__)).'/api/src/loader.php';
// Only variables should be assigned by reference, eg. soetemplate::tree_walk()
// Declaration of <extended method> should be compatible with <parent method>, varios places where method parameters change
// --> switching it off for now, as it makes error-log unusable
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
if (function_exists('get_magic_quotes_runtime') && get_magic_quotes_runtime())
{
set_magic_quotes_runtime(false);
}
$egw_min_php_version = '5.4';
if (!function_exists('version_compare') || version_compare(PHP_VERSION,$egw_min_php_version) < 0)
{
die("eGroupWare requires PHP $egw_min_php_version or greater.<br />Please contact your System Administrator to upgrade PHP!");
}
if (!defined('EGW_API_INC')) define('EGW_API_INC',PHPGW_API_INC); // this is to support the header upgrade
/* Make sure the header.inc.php is current. */
if (!isset($GLOBALS['egw_domain']) || $GLOBALS['egw_info']['server']['versions']['header'] < $GLOBALS['egw_info']['server']['versions']['current_header'])
{
echo '<center><b>You need to update your header.inc.php file to version '.
$GLOBALS['egw_info']['server']['versions']['current_header'].
' by running <a href="setup/manageheader.php">setup/headeradmin</a>.</b></center>';
exit;
}
/* Make sure the developer is following the rules. */
if (!isset($GLOBALS['egw_info']['flags']['currentapp']))
{
echo "<p><b>!!! YOU DO NOT HAVE YOUR \$GLOBALS['egw_info']['flags']['currentapp'] SET !!!<br>\n";
echo '!!! PLEASE CORRECT THIS SITUATION !!!</b></p>';
}
require_once(EGW_API_INC.'/common_functions.inc.php');
// init eGW's sessions-handler and check if we can restore the eGW enviroment from the php-session
if (egw_session::init_handler())
{
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout')
{
if (is_array($_SESSION[egw_session::EGW_INFO_CACHE]) && $_SESSION[egw_session::EGW_OBJECT_CACHE] && $_SESSION[egw_session::EGW_REQUIRED_FILES])
{
// marking the context as restored from the session, used by session->verify to not read the data from the db again
$GLOBALS['egw_info']['flags']['restored_from_session'] = true;
// restoring the egw_info-array
$GLOBALS['egw_info'] = array_merge($_SESSION[egw_session::EGW_INFO_CACHE],array('flags' => $GLOBALS['egw_info']['flags']));
// include required class-definitions
if (is_array($_SESSION[egw_session::EGW_REQUIRED_FILES])) // all classes, which can not be autoloaded
{
foreach($_SESSION[egw_session::EGW_REQUIRED_FILES] as $file)
{
require_once($file);
}
}
$GLOBALS['egw'] = unserialize($_SESSION[egw_session::EGW_OBJECT_CACHE]);
if (is_object($GLOBALS['egw']) && ($GLOBALS['egw'] instanceof egw)) // only egw object has wakeup2, setups egw_minimal eg. has not!
{
$GLOBALS['egw']->wakeup2(); // adapt the restored egw-object/enviroment to this request (eg. changed current app)
//printf("<p style=\"position: absolute; right: 0px; top: 0px;\">egw-enviroment restored in %d ms</p>\n",1000*(perfgetmicrotime()-$GLOBALS['egw_info']['flags']['page_start_time']));
$GLOBALS['egw_info']['flags']['session_restore_time'] = microtime(true) - $GLOBALS['egw_info']['flags']['page_start_time'];
if (is_object($GLOBALS['egw']->translation)) return; // exit this file, as the rest of the file creates a new egw-object and -enviroment
}
// egw object could NOT be restored from the session, create a new one
unset($GLOBALS['egw']);
$GLOBALS['egw_info'] = array('flags'=>$GLOBALS['egw_info']['flags']);
unset($GLOBALS['egw_info']['flags']['restored_from_session']);
unset($_SESSION[egw_session::EGW_INFO_CACHE]);
unset($_SESSION[egw_session::EGW_REQUIRED_FILES]);
unset($_SESSION[egw_session::EGW_OBJECT_CACHE]);
}
//echo "<p>could not restore egw_info and the egw-object!!!</p>\n";
}
else // destroy the session-cache if called by login or logout
{
unset($_SESSION[egw_session::EGW_INFO_CACHE]);
unset($_SESSION[egw_session::EGW_REQUIRED_FILES]);
unset($_SESSION[egw_session::EGW_OBJECT_CACHE]);
}
}
print_debug('sane environment','messageonly','api');
/****************************************************************************\
* Multi-Domain support *
\****************************************************************************/
$GLOBALS['egw_info']['user']['domain'] = egw_session::search_instance(
isset($_POST['login']) ? $_POST['login'] : (isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : $_SERVER['REMOTE_USER']),
egw_session::get_request('domain'),$GLOBALS['egw_info']['server']['default_domain'],
array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']),$GLOBALS['egw_domain']);
$GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_host'];
$GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_port'];
$GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_name'];
$GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_user'];
$GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_pass'];
$GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['db_type'];
print_debug('domain',@$GLOBALS['egw_info']['user']['domain'],'api');
// the egw-object instanciates all sub-classes (eg. $GLOBALS['egw']->db) and the egw_info array
$GLOBALS['egw'] = new egw(array_keys($GLOBALS['egw_domain']));
// store domain config user&pw as a hash (originals get unset)
$GLOBALS['egw_info']['server']['config_hash'] = egw_session::user_pw_hash($GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['config_user'],
$GLOBALS['egw_domain'][$GLOBALS['egw_info']['user']['domain']]['config_passwd'],true);
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && !$GLOBALS['egw_info']['server']['show_domain_selectbox'])
{
unset($GLOBALS['egw_domain']); // we kill this for security reasons
unset($GLOBALS['egw_info']['server']['header_admin_user']);
unset($GLOBALS['egw_info']['server']['header_admin_password']);
}
// saving the the egw_info array and the egw-object in the session
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login')
{
$_SESSION[egw_session::EGW_INFO_CACHE] = $GLOBALS['egw_info'];
unset($_SESSION[egw_session::EGW_INFO_CACHE]['flags']); // dont save the flags, they change on each request
$_SESSION[egw_session::EGW_OBJECT_CACHE] = serialize($GLOBALS['egw']);
}