X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fplatal.php;h=c23fb5337a51be5d020d6e0efc0e7d4ab68250cc;hb=41e571e3c1546e3288eb386bdd1f2863bcbb95be;hp=31bbe83b375d5bb66c1851474a1797c93711328a;hpb=0d602b8f5fe4fc8cd42dc61a442d14f32bb19056;p=platal.git diff --git a/classes/platal.php b/classes/platal.php index 31bbe83..c23fb53 100644 --- a/classes/platal.php +++ b/classes/platal.php @@ -1,6 +1,6 @@ auth = $auth; + $this->perms = $perms; + $this->type = $type; + } - function Platal() + public function needAuth() { - $modules = func_get_args(); - $this->path = trim(Get::_get('n', null), '/'); + return $this->auth > S::i('auth', AUTH_PUBLIC); + } - $this->__mods = array(); - $this->__hooks = array(); + public function checkPerms() + { + if (!$this->perms || $this->auth == AUTH_PUBLIC) { // No perms, no check + return true; + } + $s_perms = S::v('perms'); + return $s_perms->hasFlagCombination($this->perms); + } - array_unshift($modules, 'core'); - foreach ($modules as $module) { - $this->__mods[$module] = $m = PLModule::factory($module); - $this->__hooks += $m->handlers(); + public function hasType($type) + { + return ($this->type & $type) == $type; + } + + abstract protected function run(PlPage &$page, array $args); + + public function call(PlPage &$page, array $args) + { + global $globals, $session, $platal; + if ($this->needAuth()) { + if ($this->hasType(DO_AUTH)) { + if (!$session->start($this->auth)) { + $platal->force_login($page); + } + } else { + return PL_FORBIDDEN; + } + } + if (!$this->checkPerms()) { + if (!Platal::notAllowed()) { + return PL_FORBIDDEN; + } } + return $this->run($page, $args); } +} - function pl_self($n = null) +class PlStdHook extends PlHook +{ + private $hook; + + public function __construct($callback, $auth = AUTH_PUBLIC, $perms = 'user', $type = DO_AUTH) { - if (is_null($n)) - return $this->path; + parent::__construct($auth, $perms, $type); + $this->hook = $callback; + } - if ($n >= 0) - return join('/', array_slice($this->argv, 0, $n + 1)); + protected function run(PlPage &$page, array $args) + { + global $session, $platal; - if ($n <= -count($this->argv)) - return $this->argv[0]; + $args[0] = $page; + $val = call_user_func_array($this->hook, $args); + if ($val == PL_DO_AUTH) { + if (!$session->start($session->loggedLevel())) { + $platal->force_login($page); + } + $val = call_user_func_array($this->hook, $args); + } + return $val; + } +} - return join('/', array_slice($this->argv, 0, $n)); +class PlWikiHook extends PlHook +{ + public function __construct($auth = AUTH_PUBLIC, $perms = 'user', $type = DO_AUTH) + { + parent::__construct($auth, $perms, $type); } - function find_hook() + protected function run(PlPage &$page, array $args) { - $p = $this->path; + return PL_WIKI; + } +} - while ($p) { - if (array_key_exists($p, $this->__hooks)) - break; +class PlHookTree +{ + public $hook = null; + public $aliased = null; + public $children = array(); - $p = substr($p, 0, strrpos($p, '/')); + 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); + } + } - if (empty($this->__hooks[$p])) { - return null; + 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); + } - $hook = $this->__hooks[$p]; + public function findChild(array $path) + { + return $this->findChildAux($path, array(), array()); + } - if (!is_callable($hook['hook'])) { - return null; + 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); + } - $this->argv = explode('/', substr($this->path, strlen($p))); - $this->argv[0] = $p; - - return $hook; + 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; - function find_nearest_key($key, &$array) + static private $_page = null; + + public function __construct() { - $keys = array_keys($array); - if (in_array($key, $keys)) { - return $key; + 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."); } - $has_end = in_array("#final#", $keys); - if (strlen($key) > 24 && $has_end) { - return "#final#"; + $modules = func_get_args(); + if (isset($modules[0]) && is_array($modules[0])) { + $modules = $modules[0]; } + $this->path = trim(Get::_get('n', null), '/'); - foreach ($keys as $k) { - if ($k == "#final#") { - continue; - } - $lev = levenshtein($key, $k); - if ((!isset($val) || $lev < $val) && $lev <= (strlen($k)*2)/3) { - $val = $lev; - $best = $k; + $this->mods = array(); + $this->hooks = new PlHookTree(); + + array_unshift($modules, 'core'); + foreach ($modules as $module) { + $module = strtolower($module); + $this->mods[$module] = $m = PLModule::factory($module); + $hooks = $m->handlers(); + foreach ($hooks as $path=>$hook) { + $this->hooks->addChild(split('/', $path), $hook); } } - if (!isset($best) && $has_end) { - return "#final#"; - } else { - return $best; + + if ($globals->mode == '') { + pl_redirect('index.html'); } + } + + public function pl_self($n = null) + { + if (is_null($n)) + return $this->path; + + if ($n >= 0) + return join('/', array_slice($this->argv, 0, $n + 1)); + + if ($n <= -count($this->argv)) + return $this->argv[0]; + + return join('/', array_slice($this->argv, 0, $n)); + } + + public static function wiki_hook($auth = AUTH_PUBLIC, $perms = 'user', $type = DO_AUTH) + { + return new PlWikiHook($auth, $perms, $type); + } + + public function hook_map($name) + { return null; } - function near_hook() + protected function find_hook() { - $hooks = array(); - foreach ($this->__hooks as $hook=>$handler) { - if (!empty($handler['perms']) && $handler['perms'] != S::v('perms')) { - continue; - } - $parts = split('/', $hook); - $place =& $hooks; - foreach ($parts as $part) { - if (!isset($place[$part])) { - $place[$part] = array(); - } - $place =& $place[$part]; - } - $place["#final#"] = array(); + $p = split('/', $this->path); + list($hook, $matched, $remain, $aliased) = $this->hooks->findChild($p); + if (empty($hook)) { + return null; + } + $this->argv = $remain; + array_unshift($this->argv, implode('/', $matched)); + if (!empty($aliased)) { + $this->ns = implode('/', $aliased) . '/'; } + $this->https = !$hook->hasType(NO_HTTPS); + return $hook; + } + public function near_hook() + { $p = split('/', $this->path); - $place =& $hooks; - $link = ''; - foreach ($p as $k) { - if (!isset($ended)) { - $key = $this->find_nearest_key($k, $place); - } else { - $key = $k; - } - if ($key == "#final#") { - if (!array_key_exists($link, $this->__hooks)) { - return null; - } - $key = $k; - $ended = true; - } - if (!is_null($key)) { - if (!empty($link)) { - $link .= '/'; - } - $link .= $key; - $place =& $place[$key]; - } else { - return null; - } + list($hook, $matched, $remain, $aliased) = $this->hooks->findNearestChild($p); + if (empty($hook)) { + return null; + } + $url = implode('/', $matched); + if (!empty($remain)) { + $url .= '/' . implode('/', $remain); + } + if ($url == $this->path || levenshtein($url, $this->path) > strlen($url) / 3 + || !$hook->checkPerms()) { + return null; } - return $link; + return $url; } - function call_hook(&$page) + private function call_hook(PlPage &$page) { $hook = $this->find_hook(); if (empty($hook)) { return PL_NOT_FOUND; } - - $args = $this->argv; - $args[0] = &$page; - - if (!empty($hook['perms']) && $hook['perms'] != S::v('perms')) { - return PL_FORBIDDEN; + global $globals, $session; + if ($this->https && !@$_SERVER['HTTPS'] && $globals->core->secure_domain) { + http_redirect('https://' . $globals->core->secure_domain . $_SERVER['REQUEST_URI']); } - if ($hook['auth'] > S::v('auth', AUTH_PUBLIC)) { - if ($hook['type'] == DO_AUTH) { - global $globals; - - if (!call_user_func(array($globals->session, 'doAuth'))) { - $this->force_login($page); - } - } else { - return PL_FORBIDDEN; - } - } - - return call_user_func_array($hook['hook'], $args); + return $hook->call($page, $this->argv); } - function force_login(&$page) - { - if (S::logged()) { - $page->changeTpl('password_prompt_logged.tpl'); - $page->addJsLink('do_challenge_response_logged.js'); - } else { - $page->changeTpl('password_prompt.tpl'); - $page->addJsLink('do_challenge_response.js'); - } - $page->run(); - } + /** Show the authentication form. + */ + abstract public function force_login(PlPage& $page); - function run() + public function run() { - global $page; - - new_skinned_page('index.tpl'); + $page =& self::page(); if (empty($this->path)) { $this->path = 'index'; @@ -218,27 +362,132 @@ class Platal $page->assign('platal', $this); switch ($this->call_hook($page)) { case PL_FORBIDDEN: - $this->__mods['core']->handler_403($page); + $this->mods['core']->handler_403($page); break; case PL_NOT_FOUND: - $this->__mods['core']->handler_404($page); + $this->mods['core']->handler_404($page); break; + + case PL_WIKI: + return PL_WIKI; } $page->assign('platal', $this); $page->run(); } - function on_subscribe($forlife, $uid, $promo, $pass) + public function error403() { - $args = func_get_args(); - foreach ($this->__mods as $mod) { - if (!is_callable($mod, 'on_subscribe')) - continue; - call_user_func_array(array($mod, 'on_subscribe'), $args); + $page =& self::page(); + + $this->mods['core']->handler_403($page); + $page->assign('platal', $this); + $page->run(); + } + + public function error404() + { + $page =& self::page(); + + $this->mods['core']->handler_404($page); + $page->assign('platal', $this); + $page->run(); + } + + public static function notAllowed() + { + if (S::admin()) { + self::page()->trigWarning('Tu accèdes à cette page car tu es administrateur du site.'); + return false; + } else { + return true; + } + } + + public static function load($modname, $include = null) + { + global $platal; + $modname = strtolower($modname); + if (isset($platal->mods[$modname])) { + if (is_null($include)) { + return; + } + $platal->mods[$modname]->load($include); + } else { + if (is_null($include)) { + require_once PLModule::path($modname) . '.php'; + } else { + require_once PLModule::path($modname) . '/' . $include; + } + } + } + + public static function assert($cond, $error, $userfriendly) + { + global $globals; + if ($cond === false) { + header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error'); + $file = fopen($globals->spoolroot . '/spool/tmp/assert_erros', 'a'); + fwrite($file, '
' . pl_entities($error) . '
\n'); + fclose($file); + + Platal::page()->kill($userfriendly); + } + } + + public function &buildLogger($uid, $suid = 0) + { + if (defined('PL_LOGGER_CLASS')) { + $class = PL_LOGGER_CLASS; + return new $class($uid, $suid); + } else { + return PlLogger::dummy($uid, $suid); + } + } + + protected function &buildPage() + { + $pageclass = PL_PAGE_CLASS; + $page = new $pageclass(); + return $page; + } + + static public function &page() + { + if (is_null(self::$_page)) { + global $platal; + self::$_page = $platal->buildPage(); } + return self::$_page; + } + + protected function &buildSession() + { + $sessionclass = PL_SESSION_CLASS; + $session = new $sessionclass(); + return $session; + } + + static public function &session() + { + global $session; + return $session; + } + + protected function &buildGlobals() + { + $globalclass = PL_GLOBALS_CLASS; + $globals = new $globalclass(); + return $globals; + } + + static public function &globals() + { + global $globals; + return $globals; } } +// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: ?>