Switch to the new trigger pattern.
[platal.git] / classes / platalpage.php
index 243c4b1..f3bb2fa 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /***************************************************************************
- *  Copyright (C) 2003-2007 Polytechnique.org                              *
+ *  Copyright (C) 2003-2008 Polytechnique.org                              *
  *  http://opensource.polytechnique.org/                                   *
  *                                                                         *
  *  This program is free software; you can redistribute it and/or modify   *
 
 require_once 'smarty/libs/Smarty.class.php';
 
-class PlatalPage extends Smarty
+abstract class PlatalPage extends Smarty
 {
-    var $_page_type;
-    var $_tpl;
-    var $_errors;
-    var $_failure;
-
-    // defaults
-    var $caching          = false;
-    var $config_overwrite = false;
-    var $use_sub_dirs     = false;
+    private $_page_type;
+    private $_tpl;
+    private $_errors;
+    private $_failure;
+    private $_jsonVars;
 
     // {{{ function PlatalPage()
 
-    function PlatalPage($tpl, $type = SKINNED)
+    public function __construct($tpl, $type = SKINNED)
     {
-        global $globals;
+        parent::Smarty();
 
-        $this->Smarty();
+        global $globals;
 
+        $this->caching       = false;
+        $this->config_overwrite = false;
+        $this->use_sub_dirs  = false;
         $this->template_dir  = $globals->spoolroot."/templates/";
         $this->compile_dir   = $globals->spoolroot."/spool/templates_c/";
         array_unshift($this->plugins_dir, $globals->spoolroot."/plugins/");
@@ -48,40 +47,62 @@ class PlatalPage extends Smarty
 
         $this->compile_check = !empty($globals->debug);
 
-        $this->_page_type = $type;
-        $this->_tpl       = $tpl;
-        $this->_errors    = array();
+        $this->changeTpl($tpl, $type);
+        $this->_errors    = array('errors' => array());
+        $this->_jsonVars  = array();
         $this->_failure   = false;
 
+        if ($globals->mode != 'rw') {
+            $this->trigError("En raison d'une maintenance, une partie des fonctionnalités du site sont"
+                      . " actuellement désactivée, en particuliers aucune donnée ne sera sauvegardée");
+        }
         $this->register_prefilter('at_to_globals');
-        $this->register_prefilter('trimwhitespace');
-        $this->register_prefilter('form_force_encodings');
         $this->addJsLink('xorg.js');
+        $this->addJsLink('jquery.js');
     }
 
     // }}}
     // {{{ function changeTpl()
 
-    function changeTpl($tpl, $type = SKINNED)
+    public function changeTpl($tpl, $type = SKINNED)
+    {
+      $this->_tpl       = $tpl;
+      $this->_page_type = $type;
+      $this->assign('xorg_tpl', $tpl);
+    }
+
+    // }}}
+    // {{{ function raw()
+
+    public function raw()
     {
-       $this->_tpl       = $tpl;
-           $this->_page_type = $type;
-       $this->assign('xorg_tpl', $tpl);
+        global $globals;
+        $this->assign('globals', $globals);
+        return $this->fetch($this->_tpl);
     }
 
     // }}}
     // {{{ function _run()
 
-    function _run($skin)
+    protected function _run($skin)
     {
         global $globals, $TIME_BEGIN;
 
         session_write_close();
 
-        $this->assign('xorg_errors', $this->_errors);
+        $this->register_prefilter('trimwhitespace');
+        $this->register_prefilter('form_force_encodings');
+        $this->register_prefilter('wiki_include');
+        $this->register_prefilter('if_has_perms');
+        $this->assign('xorg_triggers', $this->_errors);
+        $this->assign('xorg_errors', $this->nb_errs());
         $this->assign('xorg_failure', $this->_failure);
         $this->assign('globals', $globals);
 
+        if (Env::has('json') && count($this->_jsonVars)) {
+            return $this->jsonDisplay();
+        }
+
         if (Env::v('display') == 'light') {
             $this->_page_type = SIMPLE;
         } elseif (Env::v('display') == 'raw') {
@@ -92,7 +113,9 @@ class PlatalPage extends Smarty
 
         switch ($this->_page_type) {
           case NO_SKIN:
-            error_reporting(0);
+            if (!($globals->debug & DEBUG_SMARTY)) {
+                error_reporting(0);
+            }
             $this->display($this->_tpl);
             exit;
 
@@ -100,12 +123,17 @@ class PlatalPage extends Smarty
             $this->assign('simple', true);
 
           case SKINNED:
-           $this->register_modifier('escape_html', 'escape_html');
-               $this->default_modifiers = Array('@escape_html');
+            $this->register_modifier('escape_html', 'escape_html');
+            $this->default_modifiers = Array('@escape_html');
+        }
+        if (S::i('auth') <= AUTH_PUBLIC) {
+            $this->register_outputfilter('hide_emails');
         }
-        $this->register_outputfilter('hide_emails');
         $this->addJsLink('wiki.js');
         header("Accept-Charset: utf-8");
+        if (Env::v('forceXml')) {
+            header("Content-Type: text/xml; charset=utf-8");
+        }
 
         if (!$globals->debug) {
             error_reporting(0);
@@ -113,18 +141,25 @@ class PlatalPage extends Smarty
             exit;
         }
 
-        if ($globals->debug & 1) {
+        $this->assign('validate', true);
+        if (!($globals->debug & DEBUG_SMARTY)) {
+            error_reporting(0);
+        }
+        $START_SMARTY = microtime(true);
+        $result = $this->fetch($skin);
+        $ttime  = sprintf('Temps total: %.02fs (Smarty %.02fs) - Mémoire totale : %dKo<br />',
+                          microtime(true) - $TIME_BEGIN, microtime(true) - $START_SMARTY,
+                          memory_get_peak_usage(true) / 1024);
+        if ($globals->debug & DEBUG_BT) {
             PlBacktrace::clean();
             $this->assign_by_ref('backtraces', PlBacktrace::$bt);
+            $result = str_replace('@@BACKTRACE@@', $this->fetch('skin/common.backtrace.tpl'), $result);
+        } else {
+            $result = str_replace('@@BACKTRACE@@', '', $result);
         }
 
-        $this->assign('validate', true);
-        error_reporting(0);
-        $result = $this->fetch($skin);
-        $ttime  = sprintf('Temps total: %.02fs<br />', microtime(true) - $TIME_BEGIN);
         $replc  = "<span class='erreur'>VALIDATION HTML INACTIVE</span><br />";
-
-        if ($globals->debug & 2) {
+        if ($globals->debug & DEBUG_VALID) {
             $fd = fopen($this->compile_dir."/valid.html","w");
             fwrite($fd, $result);
             fclose($fd);
@@ -146,31 +181,51 @@ class PlatalPage extends Smarty
         exit;
     }
 
+    abstract public function run();
+
     // }}}
     // {{{ function nb_errs()
 
-    function nb_errs()
+    public function nb_errs()
     {
-        return count($this->_errors);
+        return count($this->_errors['errors']);
     }
 
     // }}}
     // {{{ function trig()
 
-    function trig($msg)
+    private function trig($msg, $type = 'errors')
+    {
+        if (!isset($this->_errors[$type])) {
+            $this->_errors[$type] = array();
+        }
+        $this->_errors[$type][] = $msg;
+    }
+
+    public function trigError($msg)
     {
-        $this->_errors[] = $msg;
+        $this->trig($msg, 'errors');
+    }
+
+    public function trigWarning($msg)
+    {
+        $this->trig($msg, 'warnings');
+    }
+
+    public function trigSuccess($msg)
+    {
+        $this->trig($msg, 'success');
     }
 
     // }}}
     // {{{ function kill()
 
-    function kill($msg)
+    public function kill($msg)
     {
         global $platal;
 
         $this->assign('platal', $platal);
-        $this->trig($msg);
+        $this->trigError($msg);
         $this->_failure = true;
         $this->run();
     }
@@ -178,7 +233,7 @@ class PlatalPage extends Smarty
     // }}}
     // {{{ function addJsLink
 
-    function addJsLink($path)
+    public function addJsLink($path)
     {
         $this->append('xorg_js', $path);
     }
@@ -186,7 +241,7 @@ class PlatalPage extends Smarty
     // }}}
     // {{{ function addCssLink
 
-    function addCssLink($path)
+    public function addCssLink($path)
     {
         $this->append('xorg_css', $path);
     }
@@ -194,29 +249,65 @@ class PlatalPage extends Smarty
     // }}}
     // {{{ function addCssInline
 
-    function addCssInline($css)
+    public function addCssInline($css)
     {
         if (!empty($css)) {
             $this->append('xorg_inline_css', $css);
-        }    
+        }
     }
 
     // }}}
     // {{{ function setRssLink
 
-    function setRssLink($title, $path)
+    public function setRssLink($title, $path)
     {
         $this->assign('xorg_rss', array('title' => $title, 'href' => $path));
     }
 
     // }}}
+    // {{{ function jsonDisplay
+    protected function jsonDisplay()
+    {
+        header("Content-type: text/javascript; charset=utf-8");
+        array_walk_recursive($this->_jsonVars, "escape_xorgDB");
+        $jsonbegin = Env::v('jsonBegin');
+        $jsonend = Env::v('jsonEnd');
+        if (Env::has('jsonVar')) {
+            $jsonbegin = Env::v('jsonVar').' = ';
+            $jsonend = ';';
+        } elseif (Env::has('jsonFunc')) {
+            $jsonbegin = Env::v('jsonFunc').'(';
+            $jsonend = ');';
+        }
+        echo $jsonbegin, json_encode($this->_jsonVars), $jsonend;
+        exit;
+    }
+    // }}}
+    // {{{ function jsonAssign
+    public function jsonAssign($var, $value)
+    {
+        $this->_jsonVars[$var] = $value;
+    }
+
+    // }}}
+}
+
+function escape_xorgDB(&$item, $key)
+{
+    if (is_a($item, 'XOrgDBIterator')) {
+        $expanded = array();
+        while ($a = $item->next()) {
+            $expanded[] = $a;
+        }
+        $item = $expanded;
+    }
 }
 
 // {{{ function escape_html ()
 
 /**
  * default smarty plugin, used to auto-escape dangerous html.
- * 
+ *
  * < --> &lt;
  * > --> &gt;
  * " --> &quot;
@@ -225,10 +316,9 @@ class PlatalPage extends Smarty
 function escape_html($string)
 {
     if (is_string($string)) {
-       $transtbl = Array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;', '\'' => '&#39;');
-       return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};)/", "&amp;" , strtr($string, $transtbl));
+        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
     } else {
-       return $string;
+        return $string;
     }
 }
 
@@ -264,15 +354,38 @@ function at_to_globals($tpl_source, &$smarty)
 function trimwhitespace($source, &$smarty)
 {
     $tags = '(script|pre|textarea)';
-    preg_match_all("!<$tags.*?>.*?</$tags>!ius", $source, $tagsmatches);
-    $source = preg_replace("!<$tags.*?>.*?</$tags>!ius", "&&&tags&&&", $source);
+    preg_match_all("!<$tags.*?>.*?</(\\1)>!ius", $source, $tagsmatches);
+    $source = preg_replace("!<$tags.*?>.*?</(\\1)>!ius", "&&&tags&&&", $source);
 
     // remove all leading spaces, tabs and carriage returns NOT
     // preceeded by a php close tag.
     $source = preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source);
     $source = preg_replace("!&&&tags&&&!e",  'array_shift($tagsmatches[0])', $source);
 
-    return $source; 
+    return $source;
+}
+
+// }}}
+// {{{ function wiki_include
+
+function wiki_include($source, &$smarty)
+{
+    return preg_replace('/\{include( [^}]*)? wiki=([^} ]+)(.*?)\}/ui',
+                        '{include\1 file="../spool/wiki.d/cache_\2.tpl"\3 included=1}',
+                        $source);
+}
+
+// }}}
+//{{{ function hasPerm
+
+function if_has_perms($source, &$smarty)
+{
+    $source = preg_replace('/\{if([^}]*) (\!?)hasPerms\(([^)]+)\)([^}]*)\}/',
+                           '{if\1 \2$smarty.session.perms->hasFlagCombination(\3)\4}',
+                           $source);
+    return preg_replace('/\{if([^}]*) (\!?)hasPerm\(([^)]+)\)([^}]*)\}/',
+                        '{if\1 \2($smarty.session.perms && $smarty.session.perms->hasFlag(\3))\4}',
+                        $source);
 }
 
 // }}}
@@ -293,26 +406,30 @@ function _hide_email($source)
     $source = str_replace("\n", '', $source);
     return '<script type="text/javascript">//<![CDATA[' . "\n" .
            'Nix.decode("' . addslashes(str_rot13($source)) . '");' . "\n" .
-           '//]]></script>'; 
+           '//]]></script>';
 }
 
 function hide_emails($source, &$smarty)
 {
+    if (!strpos($source, '@')) {
+        return $source;
+    }
+
     //prevent email replacement in <script> and <textarea>
     $tags = '(script|textarea|select)';
-    preg_match_all("!<$tags.*?>.*?</$tags>!ius", $source, $tagsmatches);
-    $source = preg_replace("!<$tags.*?>.*?</$tags>!ius", "&&&tags&&&", $source);
+    preg_match_all("!<$tags.*?>.*?</(\\1)>!ius", $source, $tagsmatches);
+    $source = preg_replace("!<$tags.*?>.*?</(\\1)>!ius", "&&&tags&&&", $source);
 
     //catch all emails in <a href="mailto:...">
     preg_match_all("!<a[^>]+href=[\"'][^\"']*[-a-z0-9+_.]+@[-a-z0-9_.]+[^\"']*[\"'].*?>.*?</a>!ius", $source, $ahref);
     $source = preg_replace("!<a[^>]+href=[\"'][^\"']*[-a-z0-9+_.]+@[-a-z0-9_.]+[^\"']*[\"'].*?>.*?</a>!ius", '&&&ahref&&&', $source);
 
     //prevant replacement in tag attributes
-    preg_match_all("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!is", $source, $misc);
-    $source = preg_replace("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!is", '&&&misc&&&', $source);
+    preg_match_all("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!ius", $source, $misc);
+    $source = preg_replace("!<[^>]+[-a-z0-9_+.]+@[-a-z0-9_.]+.+?>!ius", '&&&misc&&&', $source);
 
     //catch !
-    $source = preg_replace('!([-a-z0-9_+.]+@[-a-z0-9_.]+)!ie', '_hide_email("\1")', $source); 
+    $source = preg_replace('!([-a-z0-9_+.]+@[-a-z0-9_.]+)!iue', '_hide_email("\1")', $source);
     $source = preg_replace('!&&&ahref&&&!e', '_hide_email(array_shift($ahref[0]))', $source);
 
     // restore data