+ parent::__construct($auth, $perms, $type);
+ }
+
+ protected function run(PlPage &$page, array $args)
+ {
+ return PL_WIKI;
+ }
+}
+
+class PlHookTree
+{
+ public $hook = null;
+ public $aliased = null;
+ public $children = array();
+
+ public function addChild(array $path, PlHook $hook)
+ {
+ global $platal;
+ $next = array_shift($path);
+ $alias = null;
+ if ($next && $next{0} == '%') {
+ $alias = $next;
+ $next = $platal->hook_map(substr($next, 1));
+ }
+ if (!$next) {
+ return;
+ }
+ @$child =& $this->children[$next];
+ if (!$child) {
+ $child = new PlHookTree();
+ $this->children[$next] =& $child;
+ $child->aliased = $alias;
+ }
+ if (empty($path)) {
+ $child->hook = $hook;
+ } else {
+ $child->addChild($path, $hook);
+ }
+ }
+
+ private function findChildAux(array $remain, array $matched, array $aliased)
+ {
+ $next = @$remain[0];
+ if ($this->aliased) {
+ $aliased = $matched;
+ }
+ if (!empty($next)) {
+ $child = @$this->children[$next];
+ if ($child) {
+ array_shift($remain);
+ $matched[] = $next;
+ return $child->findChildAux($remain, $matched, $aliased);
+ }
+ }
+ return array($this->hook, $matched, $remain, $aliased);
+ }
+
+ public function findChild(array $path)
+ {
+ return $this->findChildAux($path, array(), array());
+ }
+
+ private function findNearestChildAux(array $remain, array $matched, array $aliased)
+ {
+ $next = @$remain[0];
+ if ($this->aliased) {
+ $aliased = $matched;
+ }
+ if (!empty($next)) {
+ $child = @$this->children[$next];
+ if (!$child) {
+ $nearest_lev = 50;
+ $nearest_sdx = 50;
+ $match = null;
+ foreach ($this->children as $path=>$hook) {
+ $lev = levenshtein($next, $path);
+ if ($lev <= $nearest_lev
+ && ($lev < strlen($next) / 2 || strpos($next, $path) !== false
+ || strpos($path, $next) !== false)) {
+ $sdx = levenshtein(soundex($next), soundex($path));
+ if ($lev == $nearest_lev || $sdx < $nearest_sdx) {
+ $child = $hook;
+ $nearest_lev = $lev;
+ $nearest_sdx = $sdx;
+ $match = $path;
+ }
+ }
+ }
+ $next = $match;
+ }
+ if ($child) {
+ array_shift($remain);
+ $matched[] = $next;
+ return $child->findNearestChildAux($remain, $matched, $aliased);
+ }
+ if (($pos = strpos($next, '.php')) !== false) {
+ $remain[0] = substr($next, 0, $pos);
+ return $this->findNearestChildAux($remain, $matched, $aliased);
+ }
+ }
+ return array($this->hook, $matched, $remain, $aliased);
+ }
+
+ public function findNearestChild(array $path)
+ {
+ return $this->findNearestChildAux($path, array(), array());
+ }
+}
+
+abstract class Platal
+{
+ private $mods;
+ private $hooks;
+
+ protected $https;
+
+ public $ns;
+ public $path;
+ public $argv = array();
+
+ static private $_page = null;
+
+ public function __construct()
+ {
+ global $platal, $session, $globals;
+ $platal = $this;
+
+ /* Assign globals first, then call init: init must be used for operations
+ * that requires access to the content of $globals (e.g. XDB requires
+ * $globals to be assigned.
+ */
+ $globals = $this->buildGlobals();
+ $globals->init();
+
+ /* Get the current session: assign first, then activate the session.
+ */
+ $session = $this->buildSession();
+ if (!$session->startAvailableAuth()) {
+ Platal::page()->trigError("Données d'authentification invalides.");
+ }
+