commit a388d0b8b2ed0dd88d978e4cae0f578f3a1757b7
parent d06b2b213a1412ee0359452bdd6e89a10d22a3d8
Author: Jan Dankert <devnull@localhost>
Date: Fri, 3 Nov 2017 01:29:45 +0100
Fehlerhandling überarbeitet. Eine Exception wird im Dispatcher gefangen und ordentlich geloggt und als HTTP-Serverfehler gemeldet.
Diffstat:
4 files changed, 435 insertions(+), 346 deletions(-)
diff --git a/action/Action.class.php b/action/Action.class.php
@@ -348,22 +348,6 @@ class Action
$db = db_connection();
-// if ( isset($this->actionConfig[$this->subActionName]['direct']) )
-// {
-// if ( is_object( $db ) )
-// $db->commit();
-// exit; // Die Ausgabe ist bereits erfolgt (z.B. Bin�rdateien o. WebDAV)
-// }
-
- // Pruefen, ob HTTP-Header gesendet wurden. Dies deutet stark darauf hin, dass eine
- // PHP-Fehlermeldung ausgegeben wurde. In diesem Fall wird hier abgebrochen.
- // Weitere Ausgabe wuerde keinen Sinn machen, da wir nicht wissen, was
- // passiert ist.
-// if ( headers_sent() )
-// {
-// Http::serverError("Some server error messages occured - see above - CMS canceled.");
-// }
-
if ( is_object( $db ) )
$db->commit();
@@ -476,25 +460,26 @@ class Action
if ( $conf['theme']['compiler']['enable'] )
{
- $te = new TemplateEngine();
- $te->compile( $tplName );
- unset($te);
+ try
+ {
+ $te = new TemplateEngine();
+ $te->compile( $tplName );
+ unset($te);
+ }
+ catch (Exception $e)
+ {
+ throw new DomainException("Template compilation failed",0,$e );
+ }
}
$iFile = FileUtils::getTempDir().'/'.'or.cache.tpl.'.str_replace('/', '.',$tplName).'.tpl.'.PHP_EXT;;
+ header("X-CMS-Template-File: ".$iFile);
- //try
- //{
- if ( is_file($iFile))
- // Einbinden des Templates
- require_once( $iFile );
- else
- echo Http::serverError("File not found: $iFile","Template not found: $iFile");
- //}
- //catch( Exception $e )
- //{
- // echo "Error occured:".$e;
- //}
+ if ( is_file($iFile))
+ // Einbinden des Templates
+ require_once( $iFile );
+ else
+ throw new LogicException("File not found: $iFile");
}
diff --git a/dispatcher.php b/dispatcher.php
@@ -23,233 +23,219 @@
// Statische Resourcen (CSS,JS,Bilder,...) gehen nicht über diesen Dispatcher, sondern werden
// direkt geladen.
-require_once( 'init.php' );
-
-
-// Werkzeugklassen einbinden.
-require_once( OR_OBJECTCLASSES_DIR ."include.inc.".PHP_EXT );
-require_once( OR_TEXTCLASSES_DIR ."include.inc.".PHP_EXT );
-
-// Datenbank-Funktionen einbinden.
-require_once( OR_DBCLASSES_DIR."include.inc.".PHP_EXT );
-
-// Jetzt erst die Sitzung starten (nachdem alle Klassen zur Verfügung stehen).
-session_start();
-require_once( OR_SERVICECLASSES_DIR."Session.class.".PHP_EXT );
-
-// Vorhandene Konfiguration aus der Sitzung lesen.
-$conf = Session::getConfig();
-
-// Konfiguration lesen.
-// Wenn Konfiguration noch nicht in Session vorhanden oder die Konfiguration geändert wurde (erkennbar anhand des Datei-Datums)
-// dann die Konfiguration neu einlesen.
-if ( !is_array( $conf ) || $conf['config']['auto_reload'] && Preferences::lastModificationTime()>$conf['config']['last_modification'] )
-{
- // Da die Konfiguration neu eingelesen wird, sollten wir auch die Sitzung komplett leeren.
- if ( is_array($conf) && $conf['config']['session_destroy_on_config_reload'] )
- session_unset();
-
- $conf = Preferences::load();
-
- $conf['build'] = parse_ini_file('build.ini');
- // Sprache lesen
-
- if ( $conf['i18n']['use_http'] )
- // Die vom Browser angeforderten Sprachen ermitteln
- $languages = Http::getLanguages();
- else
- // Nur Default-Sprache erlauben
- $languages = array();
-
- if ( isset($_COOKIE['or_language']) )
- $languages = array($_COOKIE['or_language']) + $languages;
-
- // Default-Sprache hinzufuegen.
- // Wird dann verwendet, wenn die vom Browser angeforderten Sprachen
- // nicht vorhanden sind
- $languages[] = $conf['i18n']['default'];
- $available = explode(',',$conf['i18n']['available']);
-
- foreach( $languages as $l )
- {
- if ( !in_array($l,$available) )
- continue;
-
- // Pruefen, ob Sprache vorhanden ist.
- $langFile = OR_LANGUAGE_DIR.$l.'.ini.'.PHP_EXT;
-
- if ( !file_exists( $langFile ) )
- Http::serverError("File does not exist: ".$langFile);
-
- $conf['language'] = parse_ini_file( $langFile );
- $conf['language']['language_code'] = $l;
- break;
- }
-
-
- if ( !isset($conf['language']) )
- Http::serverError('no language found! (languages='.implode(',',$languages).')' );
-
- // Schreibt die Konfiguration in die Sitzung. Diese wird anschliessend nicht
- // mehr veraendert.
- Session::setConfig( $conf );
-}
-
-// Nachdem die Konfiguration gelesen wurde, kann nun der Logger benutzt werden.
-require_once( OR_SERVICECLASSES_DIR."Logger.class.".PHP_EXT );
-
-if ( !empty($conf['security']['umask']) )
- umask( octdec($conf['security']['umask']) );
-
-if ( !empty($conf['interface']['timeout']) )
- set_time_limit( intval($conf['interface']['timeout']) );
-
-if ( config('security','use_post_token') && $_SERVER['REQUEST_METHOD'] == 'POST' && @$REQ[REQ_PARAM_TOKEN]!=token() )
-{
- Logger::error('Token mismatch: Needed '.token().' but got '.@$REQ[REQ_PARAM_TOKEN].'. Maybe an attacker?');
- Http::notAuthorized("Token mismatch","Token mismatch");
-}
-
-
-define('FILE_SEP',$conf['interface']['file_separator']);
-
-define('TEMPLATE_DIR',OR_THEMES_DIR.$conf['interface']['theme'].'/templates');
-define('CSS_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/css' );
-define('IMAGE_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/images' );
-define('DEVELOPMENT' ,!$conf['production']);
-
-require_once( "functions/config.inc.php" );
-require_once( "functions/language.inc.".PHP_EXT );
-require_once( "functions/db.inc.".PHP_EXT );
-
-// Verbindung zur Datenbank
-//
-$db = Session::getDatabase();
-if ( is_object( $db ) )
-{
- $ok = $db->connect();
- if ( !$ok )
- Http::sendStatus('503','Service Unavailable','Database is not available: '.$db->error);
-
- Session::setDatabase( $db );
- $db->start();
-}
-
-if ( !empty($REQ[REQ_PARAM_ACTION]) )
- $action = $REQ[REQ_PARAM_ACTION];
-else
- Http::serverError("no action supplied");
- //$action = 'login';
-
-if ( !empty( $REQ[REQ_PARAM_SUBACTION] ) )
- $subaction = $REQ[REQ_PARAM_SUBACTION];
-else
-{
- Http::serverError("no method (subaction) supplied");
-}
-
-require( OR_ACTIONCLASSES_DIR.'/Action.class.php' );
-require( OR_ACTIONCLASSES_DIR.'/ObjectAction.class.php' );
-
-
-$actionClassName = ucfirst($action).'Action';
-
-require_once( OR_ACTIONCLASSES_DIR.'/'.$actionClassName.'.class.php' );
-
-// Erzeugen der Action-Klasse
try
{
- $do = new $actionClassName;
+ require_once( 'init.php' );
+
+
+ // Werkzeugklassen einbinden.
+ require_once( OR_OBJECTCLASSES_DIR ."include.inc.".PHP_EXT );
+ require_once( OR_TEXTCLASSES_DIR ."include.inc.".PHP_EXT );
+
+ // Datenbank-Funktionen einbinden.
+ require_once( OR_DBCLASSES_DIR."include.inc.".PHP_EXT );
+
+ // Jetzt erst die Sitzung starten (nachdem alle Klassen zur Verfügung stehen).
+ session_start();
+ require_once( OR_SERVICECLASSES_DIR."Session.class.".PHP_EXT );
+
+ // Vorhandene Konfiguration aus der Sitzung lesen.
+ $conf = Session::getConfig();
+
+ // Konfiguration lesen.
+ // Wenn Konfiguration noch nicht in Session vorhanden oder die Konfiguration geändert wurde (erkennbar anhand des Datei-Datums)
+ // dann die Konfiguration neu einlesen.
+ if ( !is_array( $conf ) || $conf['config']['auto_reload'] && Preferences::lastModificationTime()>$conf['config']['last_modification'] )
+ {
+ // Da die Konfiguration neu eingelesen wird, sollten wir auch die Sitzung komplett leeren.
+ if ( is_array($conf) && $conf['config']['session_destroy_on_config_reload'] )
+ session_unset();
+
+ $conf = Preferences::load();
+
+ $conf['build'] = parse_ini_file('build.ini');
+ // Sprache lesen
+
+ if ( $conf['i18n']['use_http'] )
+ // Die vom Browser angeforderten Sprachen ermitteln
+ $languages = Http::getLanguages();
+ else
+ // Nur Default-Sprache erlauben
+ $languages = array();
+
+ if ( isset($_COOKIE['or_language']) )
+ $languages = array($_COOKIE['or_language']) + $languages;
+
+ // Default-Sprache hinzufuegen.
+ // Wird dann verwendet, wenn die vom Browser angeforderten Sprachen
+ // nicht vorhanden sind
+ $languages[] = $conf['i18n']['default'];
+ $available = explode(',',$conf['i18n']['available']);
+
+ foreach( $languages as $l )
+ {
+ if ( !in_array($l,$available) )
+ continue;
+
+ // Pruefen, ob Sprache vorhanden ist.
+ $langFile = OR_LANGUAGE_DIR.$l.'.ini.'.PHP_EXT;
+
+ if ( !file_exists( $langFile ) )
+ Http::serverError("File does not exist: ".$langFile);
+
+ $conf['language'] = parse_ini_file( $langFile );
+ $conf['language']['language_code'] = $l;
+ break;
+ }
+
+
+ if ( !isset($conf['language']) )
+ Http::serverError('no language found! (languages='.implode(',',$languages).')' );
+
+ // Schreibt die Konfiguration in die Sitzung. Diese wird anschliessend nicht
+ // mehr veraendert.
+ Session::setConfig( $conf );
+ }
+
+ // Nachdem die Konfiguration gelesen wurde, kann nun der Logger benutzt werden.
+ require_once( OR_SERVICECLASSES_DIR."Logger.class.".PHP_EXT );
+
+ if ( !empty($conf['security']['umask']) )
+ umask( octdec($conf['security']['umask']) );
+
+ if ( !empty($conf['interface']['timeout']) )
+ set_time_limit( intval($conf['interface']['timeout']) );
+
+ if ( config('security','use_post_token') && $_SERVER['REQUEST_METHOD'] == 'POST' && @$REQ[REQ_PARAM_TOKEN]!=token() )
+ {
+ Logger::error('Token mismatch: Needed '.token().' but got '.@$REQ[REQ_PARAM_TOKEN].'. Maybe an attacker?');
+ Http::notAuthorized("Token mismatch","Token mismatch");
+ }
+
+
+ define('FILE_SEP',$conf['interface']['file_separator']);
+
+ define('TEMPLATE_DIR',OR_THEMES_DIR.$conf['interface']['theme'].'/templates');
+ define('CSS_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/css' );
+ define('IMAGE_DIR' ,OR_THEMES_DIR.$conf['interface']['theme'].'/images' );
+ define('DEVELOPMENT' ,!$conf['production']);
+
+ require_once( "functions/config.inc.php" );
+ require_once( "functions/language.inc.".PHP_EXT );
+ require_once( "functions/db.inc.".PHP_EXT );
+
+ // Verbindung zur Datenbank
+ //
+ $db = Session::getDatabase();
+ if ( is_object( $db ) )
+ {
+ $ok = $db->connect();
+ if ( !$ok )
+ Http::sendStatus('503','Service Unavailable','Database is not available: '.$db->error);
+
+ Session::setDatabase( $db );
+ $db->start();
+ }
+
+ if ( !empty($REQ[REQ_PARAM_ACTION]) )
+ $action = $REQ[REQ_PARAM_ACTION];
+ else
+ Http::serverError("no action supplied");
+
+ if ( !empty( $REQ[REQ_PARAM_SUBACTION] ) )
+ $subaction = $REQ[REQ_PARAM_SUBACTION];
+ else
+ {
+ Http::serverError("no method (subaction) supplied");
+ }
+
+ require( OR_ACTIONCLASSES_DIR.'/Action.class.php' );
+ require( OR_ACTIONCLASSES_DIR.'/ObjectAction.class.php' );
+
+
+ $actionClassName = ucfirst($action).'Action';
+
+ require_once( OR_ACTIONCLASSES_DIR.'/'.$actionClassName.'.class.php' );
+
+ // Erzeugen der Action-Klasse
+ try
+ {
+ $do = new $actionClassName;
+ }
+ catch( ObjectNotFoundException $e )
+ {
+ Logger::debug( "Object not found: ".$e->__toString() );
+ Http::noContent();
+ }
+
+ $do->actionClassName = $actionClassName;
+ $do->actionName = $action;
+ $do->subActionName = $subaction;
+
+ $do->init();
+
+
+ switch( @$do->security )
+ {
+ case SECURITY_GUEST:
+ // Ok.
+ break;
+ case SECURITY_USER:
+ if ( !is_object($do->currentUser) )
+ throw new SecurityException('No user logged in, but this action requires a valid user');
+ break;
+ case SECURITY_ADMIN:
+ if ( !is_object($do->currentUser) || !$do->currentUser->isAdmin )
+ throw new SecurityException('This action requires administration privileges, but user '.$do->currentUser->name.' is not an admin');
+ break;
+ default:
+ }
+
+
+
+ $isAction = $_SERVER['REQUEST_METHOD'] == 'POST';
+
+ if ( $isAction )
+ {
+ // POST-Request => ...Post() wird aufgerufen.
+ $subactionMethodName = $subaction.'Post';
+ }
+ else
+ {
+ // GET-Request => ...View() wird aufgerufen.
+ $subactionMethodName = $subaction.'View';
+ // Daten werden nur angezeigt, die Sitzung kann also schon geschlossen werden.
+ if ( $action != 'index' ) // In Index wird die Perspektive manipuliert.
+ Session::close();
+ }
+
+ Logger::debug("Executing $action/$subaction/".@$REQ[REQ_PARAM_ID]);
+
+ if ( ! method_exists($do,$subactionMethodName) )
+ Http::noContent();
+
+ // Jetzt wird die Aktion aus der Actionklasse aufgerufen.
+ $do->$subactionMethodName();
+
+ $do->forward();
}
catch( ObjectNotFoundException $e )
{
- Logger::debug( "Object not found: ".$e->__toString() );
+ Logger::warn( "Object not found: ".$e->__toString() ); // Nur Debug, da dies bei gelöschten Objekten vorkommen kann.
Http::noContent();
-}
-catch( Exception $e )
-{
- Http::serverError($e->getMessage(),$e->getTraceAsString() );
-}
-
-$do->actionClassName = $actionClassName;
-$do->actionName = $action;
-$do->subActionName = $subaction;
-
-$do->init();
-
-
-switch( @$do->security )
-{
- case SECURITY_GUEST:
- // Ok.
- break;
- case SECURITY_USER:
- if ( !is_object($do->currentUser) )
- {
- Logger::debug('No user logged in, but this action requires a valid user');
- Http::notAuthorized( lang('SESSION_EXPIRED'),'login required' );
- $do->templateVars['error'] = 'not logged in';
- exit;
- }
- break;
- case SECURITY_ADMIN:
- if ( !is_object($do->currentUser) || !$do->currentUser->isAdmin )
- {
- Logger::debug('This action requires administration privileges, but user '.$do->currentUser->name.' is not an admin');
- Http::notAuthorized( lang('SESSION_EXPIRED'),'intrusion detection' );
- $do->templateVars['error'] = 'no admin';
- exit;
- }
- break;
- default:
- Http::notAuthorized( lang('SESSION_EXPIRED'),'no security information for this action' );
-}
-
-
-
-$isAction = $_SERVER['REQUEST_METHOD'] == 'POST';
-
-if ( $isAction )
-{
- // POST-Request => ...Post() wird aufgerufen.
- $subactionMethodName = $subaction.'Post';
-}
-else
-{
- // GET-Request => ...View() wird aufgerufen.
- $subactionMethodName = $subaction.'View';
- // Daten werden nur angezeigt, die Sitzung kann also schon geschlossen werden.
- if ( $action != 'index' ) // In Index wird die Perspektive manipuliert.
- Session::close();
-}
-
-Logger::debug("Executing $action/$subaction/".@$REQ[REQ_PARAM_ID]);
-
-if ( ! method_exists($do,$subactionMethodName) )
- Http::noContent();
-
-// Jetzt wird die Aktion aus der Actionklasse aufgerufen.
-try
-{
- $do->$subactionMethodName();
-}
-catch( ObjectNotFoundException $e )
-{
- Logger::debug( $e->__toString() ); // Nur Debug, da dies bei gelöschten Objekten vorkommen kann.
- Http::noContent();
-}
-catch( RuntimeException $e )
-{
- Logger::warn( $e->__toString() );
- Http::serverError($e->__toString() );
}
catch( OpenRatException $e )
{
- Logger::warn( $e->__toString() );
Http::serverError( lang($e->key),$e->__toString());
+}
+catch( SecurityException $e )
+{
+ Http::notAuthorized("You are not allowed to execute this action.");
}
-
-$do->forward();
+catch( Exception $e )
+{
+ Http::serverError( "Internal CMS error",$e->__toString() );
+}
// fertig :)
?>
\ No newline at end of file
diff --git a/themes/default/js/openrat.js b/themes/default/js/openrat.js
@@ -432,8 +432,10 @@ function loadView(contentEl,action,method,id,params )
if ( status == "error" )
{
// Seite nicht gefunden.
- $(this).html("");
- $(this).removeClass("loader");
+ $(targetEl).html("");
+ $(targetEl).removeClass("loader");
+
+ notify('error',response);
// OK-button Ausblenden.
//$(targetEl).closest('div.panel').find('div.bottom > div.command > input').addClass('invisible');
// var msg = "Sorry but there was an error: ";
@@ -441,7 +443,7 @@ function loadView(contentEl,action,method,id,params )
return;
}
- $(this).removeClass("loader");
+ $(targetEl).removeClass("loader");
registerViewEvents( targetEl );
});
}
@@ -629,7 +631,7 @@ function registerViewEvents( viewEl )
$(viewEl).find('textarea').orAutoheight();
// Autosave in Formularen. Bei Veränderungen wird das Formular sofort abgeschickt.
- $(viewEl).find('form.[data-autosave="true"] input[type="checkbox"]').click( function() {
+ $(viewEl).find('form[data-autosave="true"] input[type="checkbox"]').click( function() {
formSubmit( $(this).closest('form') );
});
@@ -637,11 +639,103 @@ function registerViewEvents( viewEl )
$(viewEl).find('input').change( function() {
$(this).closest('div.panel').find('ul.views li.action.active').addClass('dirty');
});
+
+
+
+
+ var form = $(viewEl).find('form');
+
+ // Dateiupload über Drag and Drop
+ var dropzone = $(viewEl).find('div.filedropzone > div.input');
+ dropzone.on('dragenter', function (e)
+ {
+ e.stopPropagation();
+ e.preventDefault();
+ $(this).css('border', '1px dotted gray');
+ });
+ dropzone.on('dragover', function (e)
+ {
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ dropzone.on('drop', function (e)
+ {
+ $(this).css('border','1px dotted red');
+ e.preventDefault();
+ var files = e.originalEvent.dataTransfer.files;
+
+ //We need to send dropped files to Server
+ handleFileUpload(form,files);
+ });
+
+
+ // Dateiupload über File-Input-Button
+ $(viewEl).find('input[type=file]').change( function() {
+
+ var files = $(this).prop('files');
+
+ handleFileUpload(form,files);
+ });
+
+ // QR-Code anzeigen.
+ $(viewEl).find('[data-qrcode]').each( function() {
+
+ var qrcodetext = $(this).attr('data-qrcode');
+ $(this).removeAttr('data-qrcode');
+
+ $(this).qrcode( { render : 'div',
+ text : qrcodetext,
+ fill : 'currentColor' } );
+ } );
}
+function handleFileUpload(form,files)
+{
+ for (var i = 0, f; f = files[i]; i++)
+ {
+ var form_data = new FormData();
+ form_data.append('file' , f);
+ form_data.append('action' ,'folder');
+ form_data.append('subaction','createfile');
+ form_data.append('output' ,'json');
+ form_data.append('token' ,$(form).find('input[name=token]').val() );
+ form_data.append('id' ,$(form).find('input[name=id]' ).val() );
+
+ var status = $('<div class="notice info"><div class="text loader"></div></div');
+ $('#noticebar').prepend(status); // Notice anhängen.
+ $(status).show();
+
+ $.ajax( { 'type':'POST',url:'dispatcher.php', cache:false,contentType: false, processData: false, data:form_data, success:function(data, textStatus, jqXHR)
+ {
+ $(status).remove();
+ doResponse(data,textStatus,form);
+ },
+ error:function(jqXHR, textStatus, errorThrown) {
+ $(form).closest('div.content').removeClass('loader');
+ $(status).remove();
+
+ var msg;
+ try
+ {
+ var error = jQuery.parseJSON( jqXHR.responseText );
+ msg = error.error + '/' + error.description + ': ' + error.reason;
+ }
+ catch( e )
+ {
+ msg = jqXHR.responseText;
+ }
+
+ notify('error',msg);
+ }
+
+ } );
+ }
+}
+
+
function registerHeaderEvents()
{
// Links aktivieren...
@@ -1116,16 +1210,7 @@ function formSubmit(form)
msg = jqXHR.responseText;
}
- // Notice-Bar mit dieser Meldung erweitern.
- var notice = $('<div class="notice error"><div class="text">'+msg+'</div></div');
- $('#noticebar').prepend(notice); // Notice anhängen.
- notifyBrowser(msg);
-
- // Per Klick wird die Notice entfernt.
- $(notice).fadeIn().click( function()
- {
- $(this).fadeOut('fast',function() { $(this).remove(); } );
- } );
+ notify('error',msg);
}
@@ -1611,4 +1696,20 @@ function help(el,url,suffix)
var method = $(el).closest('div.panel').find('li.action.active').attr('data-method');
window.open(url + action + '/'+ method + suffix, 'OpenRat_Help', 'location=no,menubar=no,scrollbars=yes,toolbar=no,resizable=yes');
+}
+
+
+function notify( type,msg )
+{
+ // Notice-Bar mit dieser Meldung erweitern.
+ var notice = $('<div class="notice '+type+'"><div class="text">'+msg+'</div></div');
+ $('#noticebar').prepend(notice); // Notice anhängen.
+ notifyBrowser(msg);
+
+ // Per Klick wird die Notice entfernt.
+ $(notice).fadeIn().click( function()
+ {
+ $(this).fadeOut('fast',function() { $(this).remove(); } );
+ } );
+
}
\ No newline at end of file
diff --git a/util/TemplateEngine.class.php b/util/TemplateEngine.class.php
@@ -26,8 +26,6 @@
*/
class TemplateEngine
{
- private $actualTagName = '';
-
/**
* Name Template.
*
@@ -52,77 +50,87 @@ class TemplateEngine
*/
public function compile( $tplName = '')
{
- if ( empty($tplName) )
- $tplName = $this->tplName;
-
- global $conf;
- $confCompiler = $conf['theme']['compiler'];
-
- $srcXmlFilename = 'themes/default/templates/'.$tplName.'.tpl.src.xml';
-
-
- if ( is_file($srcXmlFilename) )
- $srcFilename = $srcXmlFilename;
- else
- // Wenn Vorlage (noch) nicht existiert
- die( get_class($this).': Template not found: "'.$tplName.'"' );
-
- $filename = FileUtils::getTempDir().'/'.'or.cache.tpl.'.str_replace('/', '.',$tplName).'.tpl.'.PHP_EXT;
-
- // Wenn Vorlage gaendert wurde, dann Umwandlung erneut ausf�hren.
- if ( $confCompiler['cache'] && is_file($filename) && filemtime($srcFilename) <= filemtime($filename))
- return;
-
- if ( is_file($filename) && !is_writable($filename) )
- die( get_class($this).': File is read-only: '.$filename);
-
- Logger::debug("Compile template: ".$srcFilename.' to '.$filename);
-
- // Vorlage und Zieldatei oeffnen
- $document = $this->loadDocument( $srcFilename );
-
- $outFile = @fopen($filename,'w');
-
- if ( !is_resource($outFile) )
- Http::serverError( get_class($this).': Unable to open file for writing: '.$filename);
-
- $openCmd = array();
- $depth = 0;
-
- foreach( $document as $line )
+ try {
+ if ( empty($tplName) )
+ $tplName = $this->tplName;
+
+ global $conf;
+ $confCompiler = $conf['theme']['compiler'];
+
+ $srcXmlFilename = 'themes/default/templates/'.$tplName.'.tpl.src.xml';
+
+
+ if ( is_file($srcXmlFilename) )
+ $srcFilename = $srcXmlFilename;
+ else
+ // Wenn Vorlage (noch) nicht existiert
+ throw new LogicException( "Template not found: $tplName" );
+
+ $filename = FileUtils::getTempDir().'/'.'or.cache.tpl.'.str_replace('/', '.',$tplName).'.tpl.'.PHP_EXT;
+
+ // Wenn Vorlage gaendert wurde, dann Umwandlung erneut ausf�hren.
+ if ( $confCompiler['cache'] && is_file($filename) && filemtime($srcFilename) <= filemtime($filename))
+ return;
+
+ if ( is_file($filename) && !is_writable($filename) )
+ throw new LogicException("File is read-only: $filename");
+
+ Logger::debug("Compile template: ".$srcFilename.' to '.$filename);
+
+ // Vorlage und Zieldatei oeffnen
+ $document = $this->loadDocument( $srcFilename );
+
+ // Wir legen erstmal eine temporaere Datei an.
+ // Falls ein Fehler auftritt, ist nur die temporaere Datei defekt.
+ $tmpFilename = $filename.'.tmp';
+ $outFile = @fopen($tmpFilename,'w');
+
+ if ( !is_resource($outFile) )
+ throw new LogicException( "Template $tplName: Unable to open file for writing: $filename" );
+
+ $openCmd = array();
+ $depth = 0;
+
+ foreach( $document as $line )
+ {
+ // Initialisieren der m�glichen Element-Inhalte
+ $type = '';
+ $attributes = array();
+ $value = '';
+ $tag = '';
+
+
+ // Setzt: $tag, $attributes, $value, $type
+ extract( $line );
+
+ if ($type == 'complete' || $type == 'open')
+ $attributes = $this->checkAttributes($tag,$attributes);
+
+ if ( $type == 'open' )
+ $this->copyFileContents( $tag,$outFile,$attributes,++$depth );
+ elseif ( $type == 'complete' )
+ {
+ $this->copyFileContents( $tag ,$outFile,$attributes,++$depth );
+ $this->copyFileContents( $tag.'-end',$outFile,array() , $depth-- );
+ }
+ elseif ( $type == 'close' )
+ $this->copyFileContents( $tag.'-end',$outFile,array(),$depth-- );
+ }
+
+ fclose($outFile);
+
+ rename($tmpFilename,$filename);
+
+ // CHMOD ausfuehren.
+ if ( !empty($confCompiler['chmod']))
+ if ( !@chmod($filename,octdec($confCompiler['chmod'])) )
+ throw new InvalidArgumentException( "Template {$this->tplName} failed to compile: CHMOD '{$confCompiler['chmod']}' failed on file {$filename}." );
+
+ }
+ catch( Exception $e)
{
- // Initialisieren der m�glichen Element-Inhalte
- $type = '';
- $attributes = array();
- $value = '';
- $tag = '';
-
-
- // Setzt: $tag, $attributes, $value, $type
- extract( $line );
-
- $this->actualTagName = $tag;
-
- if ($type == 'complete' || $type == 'open')
- $attributes = $this->checkAttributes($tag,$attributes);
-
- if ( $type == 'open' )
- $this->copyFileContents( $tag,$outFile,$attributes,++$depth );
- elseif ( $type == 'complete' )
- {
- $this->copyFileContents( $tag ,$outFile,$attributes,++$depth );
- $this->copyFileContents( $tag.'-end',$outFile,array() , $depth-- );
- }
- elseif ( $type == 'close' )
- $this->copyFileContents( $tag.'-end',$outFile,array(),$depth-- );
+ throw new LogicException("Template $tplName failed to compile", 0, $e);
}
-
- fclose($outFile);
-
- // CHMOD ausfuehren.
- if ( !empty($confCompiler['chmod']))
- if ( !@chmod($filename,octdec($confCompiler['chmod'])) )
- die( "CHMOD failed on file ".$filename );
}
@@ -194,8 +202,8 @@ class TemplateEngine
return $invert.'@$conf['."'".implode("'".']'.'['."'",$config_parts)."'".']';
default:
- //Http::serverError( get_class($this).': Unknown type "'.$type.'" in attribute. Allowed: var|method|property|message|messagevar|config or none');
- }
+ throw new LogicException("Unknown type '$type' in attribute. Allowed: var|function|method|text|size|property|message|messagevar|arrayvar|config or none");
+ }
}
@@ -214,7 +222,8 @@ class TemplateEngine
return;
else
// Baustein nicht vorhanden, Abbbruch.
- die( get_class($this).': Compile failed, file not found: '.$inFileName );
+
+ throw new LogicException("Compile failed, file not found: $inFileName" );
if ( DEVELOPMENT )
fwrite( $outFileHandler,"<!-- Compiling $infile @ ".date('r')." -->" );
@@ -326,7 +335,7 @@ class TemplateEngine
$elements = parse_ini_file( OR_THEMES_DIR.$conf['interface']['theme'].'/include/elements.ini.'.PHP_EXT);
if ( !isset($elements[$cmd]) )
- Http::serverError( get_class($this).': Parser error, unknown element "'.$cmd.'". Allowed: '.implode(',',array_keys($elements)) );
+ throw new InvalidArgumentException("Parser error, unknown element $cmd. Allowed: "+implode(',',array_keys($elements)) );
$checkedAttr = array();
@@ -337,31 +346,39 @@ class TemplateEngine
if ( $al=='')
continue; // Leeres Attribut... nicht zu gebrauchen.
-
- $pair = explode(':',$al,2);
- if ( count($pair) == 1 ) $pair[] = null;
- list($a,$default) = $pair;
-
+ $rpos = strrpos($al,':');
+ if ($rpos===FALSE)
+ {
+ $a = $al;
+ $default = null;
+ }
+ else
+ {
+ $a = substr($al,0,$rpos);
+ $default = substr($al,$rpos+1);
+ }
if ( is_string($default))
$default = str_replace('COMMA',',',$default); // Komma in Default-Werten ersetzen.
if ( isset($attr[$a]))
$checkedAttr[$a]=$attr[$a]; // Attribut ist bereits vorhanden, alles ok.
elseif ( $default=='*') // Pflichtfeld!
- die( get_class($this).': Element "'.$cmd.'" needs the required attribute "'.$a.'"' );
+ throw new InvalidArgumentException( "Template {$this->tplName} failed to compile: Element {$cmd} needs the required attribute {$a}" );
elseif ( !is_null($default) )
$checkedAttr[$a]=$default;
else
;
- unset( $attr[$a] ); // Damit am Ende das Urprungsarray leer wird.
+ unset( $attr[$a] ); // Damit am Ende das Ursprungsarray leer wird.
}
+
+ unset( $attr['xmlns' ]);
+ unset( $attr['xmlns:xsi' ]);
+ unset( $attr['xsi:schemaLocation']);
if ( count($attr) > 0 )
{
-
- //foreach($attr as $name=>$value)
- //Http::serverError( get_class($this).': Unknown attribute "'.$name.'" in element "'.$cmd.'". Allowed: '.$elements[$cmd]."\n" );
+ throw new InvalidArgumentException( "Template {$this->tplName} failed to compile: Unknown attributes '[".implode(',',array_keys($attr))."]' in element $cmd. Allowed attributes are: {$elements[$cmd]}" );
}
return $checkedAttr;