diff options
| author | 2014-10-09 15:53:10 +0200 | |
|---|---|---|
| committer | 2014-10-09 15:53:10 +0200 | |
| commit | f97d4b3b6cca4a55636bbd50158f3c57666b0f08 (patch) | |
| tree | 3ca9dd42155228292f0842d65b9b6d90e9140639 /lib/Minz | |
| parent | e51ceb6812e3736aa9b9ce1f2d5181f5b4b6aaa3 (diff) | |
| parent | 444b1552364b39761c3278c7da5152fd3998f216 (diff) | |
Merge branch 'master' into hotfixes
Diffstat (limited to 'lib/Minz')
| -rw-r--r-- | lib/Minz/ActionController.php | 38 | ||||
| -rw-r--r-- | lib/Minz/ActionException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/BadConfigurationException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/Configuration.php | 375 | ||||
| -rw-r--r-- | lib/Minz/ControllerNotActionControllerException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/ControllerNotExistException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/CurrentPagePaginationException.php | 8 | ||||
| -rw-r--r-- | lib/Minz/Dispatcher.php | 117 | ||||
| -rw-r--r-- | lib/Minz/Error.php | 110 | ||||
| -rw-r--r-- | lib/Minz/Exception.php | 16 | ||||
| -rw-r--r-- | lib/Minz/FileNotExistException.php | 8 | ||||
| -rw-r--r-- | lib/Minz/FrontController.php | 117 | ||||
| -rw-r--r-- | lib/Minz/Helper.php | 33 | ||||
| -rw-r--r-- | lib/Minz/Log.php | 100 | ||||
| -rw-r--r-- | lib/Minz/Model.php | 12 | ||||
| -rw-r--r-- | lib/Minz/ModelArray.php | 81 | ||||
| -rw-r--r-- | lib/Minz/ModelPdo.php | 124 | ||||
| -rw-r--r-- | lib/Minz/PDOConnectionException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/Paginator.php | 196 | ||||
| -rw-r--r-- | lib/Minz/PermissionDeniedException.php | 8 | ||||
| -rw-r--r-- | lib/Minz/Request.php | 227 | ||||
| -rw-r--r-- | lib/Minz/Session.php | 93 | ||||
| -rw-r--r-- | lib/Minz/Translate.php | 79 | ||||
| -rw-r--r-- | lib/Minz/Url.php | 125 | ||||
| -rw-r--r-- | lib/Minz/View.php | 249 |
25 files changed, 2161 insertions, 0 deletions
diff --git a/lib/Minz/ActionController.php b/lib/Minz/ActionController.php new file mode 100644 index 000000000..b47c54554 --- /dev/null +++ b/lib/Minz/ActionController.php @@ -0,0 +1,38 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe ActionController représente le contrôleur de l'application + */ +class Minz_ActionController { + protected $view; + + /** + * Constructeur + */ + public function __construct () { + $this->view = new Minz_View (); + $this->view->attributeParams (); + } + + /** + * Getteur + */ + public function view () { + return $this->view; + } + + /** + * Méthodes à redéfinir (ou non) par héritage + * firstAction est la première méthode exécutée par le Dispatcher + * lastAction est la dernière + */ + public function init () { } + public function firstAction () { } + public function lastAction () { } +} + + diff --git a/lib/Minz/ActionException.php b/lib/Minz/ActionException.php new file mode 100644 index 000000000..c566a076f --- /dev/null +++ b/lib/Minz/ActionException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ActionException extends Minz_Exception { + public function __construct ($controller_name, $action_name, $code = self::ERROR) { + $message = '`' . $action_name . '` cannot be invoked on `' + . $controller_name . '`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/BadConfigurationException.php b/lib/Minz/BadConfigurationException.php new file mode 100644 index 000000000..a7b77d687 --- /dev/null +++ b/lib/Minz/BadConfigurationException.php @@ -0,0 +1,9 @@ +<?php +class Minz_BadConfigurationException extends Minz_Exception { + public function __construct ($part_missing, $code = self::ERROR) { + $message = '`' . $part_missing + . '` in the configuration file is missing or is misconfigured'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php new file mode 100644 index 000000000..4e9da58b4 --- /dev/null +++ b/lib/Minz/Configuration.php @@ -0,0 +1,375 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Configuration permet de gérer la configuration de l'application + */ +class Minz_Configuration { + const CONF_PATH_NAME = '/config.php'; + + /** + * VERSION est la version actuelle de MINZ + */ + const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS + + /** + * valeurs possibles pour l'"environment" + * SILENT rend l'application muette (pas de log) + * PRODUCTION est recommandée pour une appli en production + * (log les erreurs critiques) + * DEVELOPMENT log toutes les erreurs + */ + const SILENT = 0; + const PRODUCTION = 1; + const DEVELOPMENT = 2; + + /** + * définition des variables de configuration + * $salt une chaîne de caractères aléatoires (obligatoire) + * $environment gère le niveau d'affichage pour log et erreurs + * $base_url le chemin de base pour accéder à l'application + * $title le nom de l'application + * $language la langue par défaut de l'application + * $db paramètres pour la base de données (tableau) + * - host le serveur de la base + * - user nom d'utilisateur + * - password mot de passe de l'utilisateur + * - base le nom de la base de données + */ + private static $salt = ''; + private static $environment = Minz_Configuration::PRODUCTION; + private static $base_url = ''; + private static $title = ''; + private static $language = 'en'; + private static $default_user = ''; + private static $allow_anonymous = false; + private static $allow_anonymous_refresh = false; + private static $auth_type = 'none'; + private static $api_enabled = false; + private static $unsafe_autologin_enabled = false; + + private static $db = array ( + 'type' => 'mysql', + 'host' => '', + 'user' => '', + 'password' => '', + 'base' => '', + 'prefix' => '', + ); + + /* + * Getteurs + */ + public static function salt () { + return self::$salt; + } + public static function environment ($str = false) { + $env = self::$environment; + + if ($str) { + switch (self::$environment) { + case self::SILENT: + $env = 'silent'; + break; + case self::DEVELOPMENT: + $env = 'development'; + break; + case self::PRODUCTION: + default: + $env = 'production'; + } + } + + return $env; + } + public static function baseUrl () { + return self::$base_url; + } + public static function title () { + return self::$title; + } + public static function language () { + return self::$language; + } + public static function dataBase () { + return self::$db; + } + public static function defaultUser () { + return self::$default_user; + } + public static function isAdmin($currentUser) { + return $currentUser === self::$default_user; + } + public static function allowAnonymous() { + return self::$allow_anonymous; + } + public static function allowAnonymousRefresh() { + return self::$allow_anonymous_refresh; + } + public static function authType() { + return self::$auth_type; + } + public static function needsLogin() { + return self::$auth_type !== 'none'; + } + public static function canLogIn() { + return self::$auth_type === 'form' || self::$auth_type === 'persona'; + } + public static function apiEnabled() { + return self::$api_enabled; + } + public static function unsafeAutologinEnabled() { + return self::$unsafe_autologin_enabled; + } + + public static function _allowAnonymous($allow = false) { + self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); + } + public static function _allowAnonymousRefresh($allow = false) { + self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); + } + public static function _authType($value) { + $value = strtolower($value); + switch ($value) { + case 'form': + case 'http_auth': + case 'persona': + case 'none': + self::$auth_type = $value; + break; + } + self::_allowAnonymous(self::$allow_anonymous); + } + + public static function _enableApi($value = false) { + self::$api_enabled = (bool)$value; + } + public static function _enableAutologin($value = false) { + self::$unsafe_autologin_enabled = (bool)$value; + } + + /** + * Initialise les variables de configuration + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + */ + public static function init () { + try { + self::parseFile (); + self::setReporting (); + } catch (Minz_FileNotExistException $e) { + throw $e; + } catch (Minz_BadConfigurationException $e) { + throw $e; + } + } + + public static function writeFile() { + $ini_array = array( + 'general' => array( + 'environment' => self::environment(true), + 'salt' => self::$salt, + 'base_url' => self::$base_url, + 'title' => self::$title, + 'default_user' => self::$default_user, + 'allow_anonymous' => self::$allow_anonymous, + 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, + 'auth_type' => self::$auth_type, + 'api_enabled' => self::$api_enabled, + 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, + ), + 'db' => self::$db, + ); + @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); + $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "<?php\n return " . var_export($ini_array, true) . ';'); + if (function_exists('opcache_invalidate')) { + opcache_invalidate(DATA_PATH . self::CONF_PATH_NAME); //Clear PHP 5.5+ cache for include + } + return (bool)$result; + } + + /** + * Parse un fichier de configuration + * @exception Minz_PermissionDeniedException si le CONF_PATH_NAME n'est pas accessible + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + */ + private static function parseFile () { + $ini_array = include(DATA_PATH . self::CONF_PATH_NAME); + + if (!is_array($ini_array)) { + throw new Minz_PermissionDeniedException ( + DATA_PATH . self::CONF_PATH_NAME, + Minz_Exception::ERROR + ); + } + + // [general] est obligatoire + if (!isset ($ini_array['general'])) { + throw new Minz_BadConfigurationException ( + '[general]', + Minz_Exception::ERROR + ); + } + $general = $ini_array['general']; + + // salt est obligatoire + if (!isset ($general['salt'])) { + if (isset($general['sel_application'])) { //v0.6 + $general['salt'] = $general['sel_application']; + } else { + throw new Minz_BadConfigurationException ( + 'salt', + Minz_Exception::ERROR + ); + } + } + self::$salt = $general['salt']; + + if (isset ($general['environment'])) { + switch ($general['environment']) { + case 'silent': + self::$environment = Minz_Configuration::SILENT; + break; + case 'development': + self::$environment = Minz_Configuration::DEVELOPMENT; + break; + case 'production': + self::$environment = Minz_Configuration::PRODUCTION; + break; + default: + if ($general['environment'] >= 0 && + $general['environment'] <= 2) { + // fallback 0.7-beta + self::$environment = $general['environment']; + } else { + throw new Minz_BadConfigurationException ( + 'environment', + Minz_Exception::ERROR + ); + } + } + + } + if (isset ($general['base_url'])) { + self::$base_url = $general['base_url']; + } + + if (isset ($general['title'])) { + self::$title = $general['title']; + } + if (isset ($general['language'])) { + self::$language = $general['language']; + } + if (isset ($general['default_user'])) { + self::$default_user = $general['default_user']; + } + if (isset ($general['auth_type'])) { + self::_authType($general['auth_type']); + } + if (isset ($general['allow_anonymous'])) { + self::$allow_anonymous = ( + ((bool)($general['allow_anonymous'])) && + ($general['allow_anonymous'] !== 'no') + ); + } + if (isset ($general['allow_anonymous_refresh'])) { + self::$allow_anonymous_refresh = ( + ((bool)($general['allow_anonymous_refresh'])) && + ($general['allow_anonymous_refresh'] !== 'no') + ); + } + if (isset ($general['api_enabled'])) { + self::$api_enabled = ( + ((bool)($general['api_enabled'])) && + ($general['api_enabled'] !== 'no') + ); + } + if (isset ($general['unsafe_autologin_enabled'])) { + self::$unsafe_autologin_enabled = ( + ((bool)($general['unsafe_autologin_enabled'])) && + ($general['unsafe_autologin_enabled'] !== 'no') + ); + } + + // Base de données + if (isset ($ini_array['db'])) { + $db = $ini_array['db']; + if (empty($db['type'])) { + throw new Minz_BadConfigurationException ( + 'type', + Minz_Exception::ERROR + ); + } + switch ($db['type']) { + case 'mysql': + if (empty($db['host'])) { + throw new Minz_BadConfigurationException ( + 'host', + Minz_Exception::ERROR + ); + } + if (empty($db['user'])) { + throw new Minz_BadConfigurationException ( + 'user', + Minz_Exception::ERROR + ); + } + if (!isset($db['password'])) { + throw new Minz_BadConfigurationException ( + 'password', + Minz_Exception::ERROR + ); + } + if (empty($db['base'])) { + throw new Minz_BadConfigurationException ( + 'base', + Minz_Exception::ERROR + ); + } + self::$db['host'] = $db['host']; + self::$db['user'] = $db['user']; + self::$db['password'] = $db['password']; + self::$db['base'] = $db['base']; + if (isset($db['prefix'])) { + self::$db['prefix'] = $db['prefix']; + } + break; + case 'sqlite': + self::$db['host'] = ''; + self::$db['user'] = ''; + self::$db['password'] = ''; + self::$db['base'] = ''; + self::$db['prefix'] = ''; + break; + default: + throw new Minz_BadConfigurationException ( + 'type', + Minz_Exception::ERROR + ); + break; + } + self::$db['type'] = $db['type']; + } + } + + private static function setReporting() { + switch (self::$environment) { + case self::PRODUCTION: + error_reporting(E_ALL); + ini_set('display_errors','Off'); + ini_set('log_errors', 'On'); + break; + case self::DEVELOPMENT: + error_reporting(E_ALL); + ini_set('display_errors','On'); + ini_set('log_errors', 'On'); + break; + case self::SILENT: + error_reporting(0); + break; + } + } +} diff --git a/lib/Minz/ControllerNotActionControllerException.php b/lib/Minz/ControllerNotActionControllerException.php new file mode 100644 index 000000000..535a1377e --- /dev/null +++ b/lib/Minz/ControllerNotActionControllerException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ControllerNotActionControllerException extends Minz_Exception { + public function __construct ($controller_name, $code = self::ERROR) { + $message = 'Controller `' . $controller_name + . '` isn\'t instance of ActionController'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/ControllerNotExistException.php b/lib/Minz/ControllerNotExistException.php new file mode 100644 index 000000000..523867d11 --- /dev/null +++ b/lib/Minz/ControllerNotExistException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ControllerNotExistException extends Minz_Exception { + public function __construct ($controller_name, $code = self::ERROR) { + $message = 'Controller `' . $controller_name + . '` doesn\'t exist'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/CurrentPagePaginationException.php b/lib/Minz/CurrentPagePaginationException.php new file mode 100644 index 000000000..74214d879 --- /dev/null +++ b/lib/Minz/CurrentPagePaginationException.php @@ -0,0 +1,8 @@ +<?php +class Minz_CurrentPagePaginationException extends Minz_Exception { + public function __construct ($page) { + $message = 'Page number `' . $page . '` doesn\'t exist'; + + parent::__construct ($message, self::ERROR); + } +} diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php new file mode 100644 index 000000000..f62a92911 --- /dev/null +++ b/lib/Minz/Dispatcher.php @@ -0,0 +1,117 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * Le Dispatcher s'occupe d'initialiser le Controller et d'executer l'action + * déterminée dans la Request + * C'est un singleton + */ +class Minz_Dispatcher { + const CONTROLLERS_PATH_NAME = '/Controllers'; + + /* singleton */ + private static $instance = null; + private static $needsReset; + + private $controller; + + /** + * Récupère l'instance du Dispatcher + */ + public static function getInstance () { + if (self::$instance === null) { + self::$instance = new Minz_Dispatcher (); + } + return self::$instance; + } + + /** + * Lance le controller indiqué dans Request + * Remplit le body de Response à partir de la Vue + * @exception Minz_Exception + */ + public function run () { + do { + self::$needsReset = false; + + try { + $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); + $this->controller->init (); + $this->controller->firstAction (); + if (!self::$needsReset) { + $this->launchAction ( + Minz_Request::actionName () + . 'Action' + ); + } + $this->controller->lastAction (); + + if (!self::$needsReset) { + $this->controller->view ()->build (); + } + } catch (Minz_Exception $e) { + throw $e; + } + } while (self::$needsReset); + } + + /** + * Informe le contrôleur qu'il doit recommancer car la requête a été modifiée + */ + public static function reset() { + self::$needsReset = true; + } + + /** + * Instancie le Controller + * @param $controller_name le nom du controller à instancier + * @exception ControllerNotExistException le controller n'existe pas + * @exception ControllerNotActionControllerException controller n'est + * > pas une instance de ActionController + */ + private function createController ($controller_name) { + $filename = APP_PATH . self::CONTROLLERS_PATH_NAME . '/' + . $controller_name . '.php'; + + if (!class_exists ($controller_name)) { + throw new Minz_ControllerNotExistException ( + $controller_name, + Minz_Exception::ERROR + ); + } + $this->controller = new $controller_name (); + + if (! ($this->controller instanceof Minz_ActionController)) { + throw new Minz_ControllerNotActionControllerException ( + $controller_name, + Minz_Exception::ERROR + ); + } + } + + /** + * Lance l'action sur le controller du dispatcher + * @param $action_name le nom de l'action + * @exception ActionException si on ne peut pas exécuter l'action sur + * le controller + */ + private function launchAction ($action_name) { + if (!is_callable (array ( + $this->controller, + $action_name + ))) { + throw new Minz_ActionException ( + get_class ($this->controller), + $action_name, + Minz_Exception::ERROR + ); + } + call_user_func (array ( + $this->controller, + $action_name + )); + } +} diff --git a/lib/Minz/Error.php b/lib/Minz/Error.php new file mode 100644 index 000000000..c8222a430 --- /dev/null +++ b/lib/Minz/Error.php @@ -0,0 +1,110 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Error permet de lancer des erreurs HTTP + */ +class Minz_Error { + public function __construct () { } + + /** + * Permet de lancer une erreur + * @param $code le type de l'erreur, par défaut 404 (page not found) + * @param $logs logs d'erreurs découpés de la forme + * > $logs['error'] + * > $logs['warning'] + * > $logs['notice'] + * @param $redirect indique s'il faut forcer la redirection (les logs ne seront pas transmis) + */ + public static function error ($code = 404, $logs = array (), $redirect = false) { + $logs = self::processLogs ($logs); + $error_filename = APP_PATH . '/Controllers/errorController.php'; + + switch ($code) { + case 200 : + header('HTTP/1.1 200 OK'); + break; + case 403 : + header('HTTP/1.1 403 Forbidden'); + break; + case 404 : + header('HTTP/1.1 404 Not Found'); + break; + case 500 : + header('HTTP/1.1 500 Internal Server Error'); + break; + case 503 : + header('HTTP/1.1 503 Service Unavailable'); + break; + default : + header('HTTP/1.1 500 Internal Server Error'); + } + + if (file_exists ($error_filename)) { + $params = array ( + 'code' => $code, + 'logs' => $logs + ); + + if ($redirect) { + Minz_Request::forward (array ( + 'c' => 'error' + ), true); + } else { + Minz_Request::forward (array ( + 'c' => 'error', + 'params' => $params + ), false); + } + } else { + echo '<h1>An error occured</h1>' . "\n"; + + if (!empty ($logs)) { + echo '<ul>' . "\n"; + foreach ($logs as $log) { + echo '<li>' . $log . '</li>' . "\n"; + } + echo '</ul>' . "\n"; + } + + exit (); + } + } + + /** + * Permet de retourner les logs de façon à n'avoir que + * ceux que l'on veut réellement + * @param $logs les logs rangés par catégories (error, warning, notice) + * @return la liste des logs, sans catégorie, + * > en fonction de l'environment + */ + private static function processLogs ($logs) { + $env = Minz_Configuration::environment (); + $logs_ok = array (); + $error = array (); + $warning = array (); + $notice = array (); + + if (isset ($logs['error'])) { + $error = $logs['error']; + } + if (isset ($logs['warning'])) { + $warning = $logs['warning']; + } + if (isset ($logs['notice'])) { + $notice = $logs['notice']; + } + + if ($env == Minz_Configuration::PRODUCTION) { + $logs_ok = $error; + } + if ($env == Minz_Configuration::DEVELOPMENT) { + $logs_ok = array_merge ($error, $warning, $notice); + } + + return $logs_ok; + } +} diff --git a/lib/Minz/Exception.php b/lib/Minz/Exception.php new file mode 100644 index 000000000..b5e71e0d8 --- /dev/null +++ b/lib/Minz/Exception.php @@ -0,0 +1,16 @@ +<?php +class Minz_Exception extends Exception { + const ERROR = 0; + const WARNING = 10; + const NOTICE = 20; + + public function __construct ($message, $code = self::ERROR) { + if ($code != Minz_Exception::ERROR + && $code != Minz_Exception::WARNING + && $code != Minz_Exception::NOTICE) { + $code = Minz_Exception::ERROR; + } + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/FileNotExistException.php b/lib/Minz/FileNotExistException.php new file mode 100644 index 000000000..f8dfbdf66 --- /dev/null +++ b/lib/Minz/FileNotExistException.php @@ -0,0 +1,8 @@ +<?php +class Minz_FileNotExistException extends Minz_Exception { + public function __construct ($file_name, $code = self::ERROR) { + $message = 'File not found: `' . $file_name.'`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php new file mode 100644 index 000000000..f13882801 --- /dev/null +++ b/lib/Minz/FrontController.php @@ -0,0 +1,117 @@ +<?php +# ***** BEGIN LICENSE BLOCK ***** +# MINZ - a free PHP Framework like Zend Framework +# Copyright (C) 2011 Marien Fressinaud +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ***** END LICENSE BLOCK ***** + +/** + * La classe FrontController est le Dispatcher du framework, elle lance l'application + * Elle est appelée en général dans le fichier index.php à la racine du serveur + */ +class Minz_FrontController { + protected $dispatcher; + + /** + * Constructeur + * Initialise le dispatcher, met à jour la Request + */ + public function __construct () { + if (LOG_PATH === false) { + $this->killApp ('Path not found: LOG_PATH'); + } + + try { + Minz_Configuration::init (); + + Minz_Request::init (); + + $url = $this->buildUrl(); + $url['params'] = array_merge ( + $url['params'], + Minz_Request::fetchPOST () + ); + Minz_Request::forward ($url); + } catch (Minz_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + $this->killApp ($e->getMessage ()); + } + + $this->dispatcher = Minz_Dispatcher::getInstance(); + } + + /** + * Retourne un tableau représentant l'url passée par la barre d'adresses + * @return tableau représentant l'url + */ + private function buildUrl() { + $url = array (); + + $url['c'] = Minz_Request::fetchGET ( + 'c', + Minz_Request::defaultControllerName () + ); + $url['a'] = Minz_Request::fetchGET ( + 'a', + Minz_Request::defaultActionName () + ); + $url['params'] = Minz_Request::fetchGET (); + + // post-traitement + unset ($url['params']['c']); + unset ($url['params']['a']); + + return $url; + } + + /** + * Démarre l'application (lance le dispatcher et renvoie la réponse) + */ + public function run () { + try { + $this->dispatcher->run(); + } catch (Minz_Exception $e) { + try { + Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + } catch (Minz_PermissionDeniedException $e) { + $this->killApp ($e->getMessage ()); + } + + if ($e instanceof Minz_FileNotExistException || + $e instanceof Minz_ControllerNotExistException || + $e instanceof Minz_ControllerNotActionControllerException || + $e instanceof Minz_ActionException) { + Minz_Error::error ( + 404, + array ('error' => array ($e->getMessage ())), + true + ); + } else { + $this->killApp (); + } + } + } + + /** + * Permet d'arrêter le programme en urgence + */ + private function killApp ($txt = '') { + if ($txt == '') { + $txt = 'See logs files'; + } + exit ('### Application problem ###<br />'."\n".$txt); + } +} diff --git a/lib/Minz/Helper.php b/lib/Minz/Helper.php new file mode 100644 index 000000000..f4a547c4e --- /dev/null +++ b/lib/Minz/Helper.php @@ -0,0 +1,33 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Helper représente une aide pour des tâches récurrentes + */ +class Minz_Helper { + /** + * Annule les effets des magic_quotes pour une variable donnée + * @param $var variable à traiter (tableau ou simple variable) + */ + public static function stripslashes_r($var) { + if (is_array($var)){ + return array_map(array('Minz_Helper', 'stripslashes_r'), $var); + } else { + return stripslashes($var); + } + } + + /** + * Wrapper for htmlspecialchars. + * Force UTf-8 value and can be used on array too. + */ + public static function htmlspecialchars_utf8($var) { + if (is_array($var)) { + return array_map(array('Minz_Helper', 'htmlspecialchars_utf8'), $var); + } + return htmlspecialchars($var, ENT_COMPAT, 'UTF-8'); + } +} diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php new file mode 100644 index 000000000..d3eaec2ae --- /dev/null +++ b/lib/Minz/Log.php @@ -0,0 +1,100 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Log permet de logger des erreurs + */ +class Minz_Log { + /** + * Les différents niveau de log + * ERROR erreurs bloquantes de l'application + * WARNING erreurs pouvant géner le bon fonctionnement, mais non bloquantes + * NOTICE erreurs mineures ou messages d'informations + * DEBUG Informations affichées pour le déboggage + */ + const ERROR = 2; + const WARNING = 4; + const NOTICE = 8; + const DEBUG = 16; + + /** + * Enregistre un message dans un fichier de log spécifique + * Message non loggué si + * - environment = SILENT + * - level = WARNING et environment = PRODUCTION + * - level = NOTICE et environment = PRODUCTION + * @param $information message d'erreur / information à enregistrer + * @param $level niveau d'erreur + * @param $file_name fichier de log, par défaut LOG_PATH/application.log + */ + public static function record ($information, $level, $file_name = null) { + $env = Minz_Configuration::environment (); + + if (! ($env === Minz_Configuration::SILENT + || ($env === Minz_Configuration::PRODUCTION + && ($level >= Minz_Log::NOTICE)))) { + if ($file_name === null) { + $file_name = LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log'; + } + + switch ($level) { + case Minz_Log::ERROR : + $level_label = 'error'; + break; + case Minz_Log::WARNING : + $level_label = 'warning'; + break; + case Minz_Log::NOTICE : + $level_label = 'notice'; + break; + case Minz_Log::DEBUG : + $level_label = 'debug'; + break; + default : + $level_label = 'unknown'; + } + + $log = '[' . date('r') . ']' + . ' [' . $level_label . ']' + . ' --- ' . $information . "\n"; + + if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) { + throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR); + } + } + } + + /** + * Automatise le log des variables globales $_GET et $_POST + * Fait appel à la fonction record(...) + * Ne fonctionne qu'en environnement "development" + * @param $file_name fichier de log, par défaut LOG_PATH/application.log + */ + public static function recordRequest($file_name = null) { + $msg_get = str_replace("\n", '', '$_GET content : ' . print_r($_GET, true)); + $msg_post = str_replace("\n", '', '$_POST content : ' . print_r($_POST, true)); + + self::record($msg_get, Minz_Log::DEBUG, $file_name); + self::record($msg_post, Minz_Log::DEBUG, $file_name); + } + + /** + * Some helpers to Minz_Log::record() method + * Parameters are the same of those of the record() method. + */ + public static function debug($msg, $file_name = null) { + self::record($msg, Minz_Log::DEBUG, $file_name); + } + public static function notice($msg, $file_name = null) { + self::record($msg, Minz_Log::NOTICE, $file_name); + } + public static function warning($msg, $file_name = null) { + self::record($msg, Minz_Log::WARNING, $file_name); + } + public static function error($msg, $file_name = null) { + self::record($msg, Minz_Log::ERROR, $file_name); + } +} diff --git a/lib/Minz/Model.php b/lib/Minz/Model.php new file mode 100644 index 000000000..adbaba942 --- /dev/null +++ b/lib/Minz/Model.php @@ -0,0 +1,12 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Model représente un modèle de l'application (représentation MVC) + */ +class Minz_Model { + +} diff --git a/lib/Minz/ModelArray.php b/lib/Minz/ModelArray.php new file mode 100644 index 000000000..ff23dbc83 --- /dev/null +++ b/lib/Minz/ModelArray.php @@ -0,0 +1,81 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php + */ +class Minz_ModelArray { + /** + * $filename est le nom du fichier + */ + protected $filename; + + /** + * Ouvre le fichier indiqué, charge le tableau dans $array et le $filename + * @param $filename le nom du fichier à ouvrir contenant un tableau + * Remarque : $array sera obligatoirement un tableau + */ + public function __construct ($filename) { + $this->filename = $filename; + } + + protected function loadArray() { + if (!file_exists($this->filename)) { + throw new Minz_FileNotExistException($this->filename, Minz_Exception::WARNING); + } + elseif (($handle = $this->getLock()) === false) { + throw new Minz_PermissionDeniedException($this->filename); + } else { + $data = include($this->filename); + $this->releaseLock($handle); + + if ($data === false) { + throw new Minz_PermissionDeniedException($this->filename); + } elseif (!is_array($data)) { + $data = array(); + } + return $data; + } + } + + /** + * Sauve le tableau $array dans le fichier $filename + **/ + protected function writeArray($array) { + if (file_put_contents($this->filename, "<?php\n return " . var_export($array, true) . ';', LOCK_EX) === false) { + throw new Minz_PermissionDeniedException($this->filename); + } + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include + } + return true; + } + + private function getLock() { + $handle = fopen($this->filename, 'r'); + if ($handle === false) { + return false; + } + + $count = 50; + while (!flock($handle, LOCK_SH) && $count > 0) { + $count--; + usleep(1000); + } + + if ($count > 0) { + return $handle; + } else { + fclose($handle); + return false; + } + } + + private function releaseLock($handle) { + flock($handle, LOCK_UN); + fclose($handle); + } +} diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php new file mode 100644 index 000000000..b4bfca746 --- /dev/null +++ b/lib/Minz/ModelPdo.php @@ -0,0 +1,124 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Model_sql représente le modèle interragissant avec les bases de données + * Seul la connexion MySQL est prise en charge pour le moment + */ +class Minz_ModelPdo { + + /** + * Partage la connexion à la base de données entre toutes les instances. + */ + public static $useSharedBd = true; + private static $sharedBd = null; + private static $sharedPrefix; + protected static $sharedDbType; + + /** + * $bd variable représentant la base de données + */ + protected $bd; + + protected $prefix; + + public function dbType() { + return self::$sharedDbType; + } + + /** + * Créé la connexion à la base de données à l'aide des variables + * HOST, BASE, USER et PASS définies dans le fichier de configuration + */ + public function __construct($currentUser = null) { + if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) { + $this->bd = self::$sharedBd; + $this->prefix = self::$sharedPrefix; + return; + } + + $db = Minz_Configuration::dataBase(); + + if ($currentUser === null) { + $currentUser = Minz_Session::param('currentUser', '_'); + } + + try { + $type = $db['type']; + if ($type === 'mysql') { + $string = 'mysql:host=' . $db['host'] + . ';dbname=' . $db['base'] + . ';charset=utf8'; + $driver_options = array( + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', + ); + $this->prefix = $db['prefix'] . $currentUser . '_'; + } elseif ($type === 'sqlite') { + $string = 'sqlite:' . DATA_PATH . '/' . $currentUser . '.sqlite'; + $driver_options = array( + //PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + $this->prefix = ''; + } else { + throw new Minz_PDOConnectionException( + 'Invalid database type!', + $db['user'], Minz_Exception::ERROR + ); + } + self::$sharedDbType = $type; + self::$sharedPrefix = $this->prefix; + + $this->bd = new MinzPDO( + $string, + $db['user'], + $db['password'], + $driver_options + ); + if ($type === 'sqlite') { + $this->bd->exec('PRAGMA foreign_keys = ON;'); + } + self::$sharedBd = $this->bd; + } catch (Exception $e) { + throw new Minz_PDOConnectionException( + $string, + $db['user'], Minz_Exception::ERROR + ); + } + } + + public function beginTransaction() { + $this->bd->beginTransaction(); + } + public function commit() { + $this->bd->commit(); + } + public function rollBack() { + $this->bd->rollBack(); + } + + public static function clean() { + self::$sharedBd = null; + self::$sharedPrefix = ''; + } +} + +class MinzPDO extends PDO { + private static function check($statement) { + if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { + invalidateHttpCache(); + } + } + + public function prepare($statement, $driver_options = array()) { + MinzPDO::check($statement); + return parent::prepare($statement, $driver_options); + } + + public function exec($statement) { + MinzPDO::check($statement); + return parent::exec($statement); + } +} diff --git a/lib/Minz/PDOConnectionException.php b/lib/Minz/PDOConnectionException.php new file mode 100644 index 000000000..faf2e0fe9 --- /dev/null +++ b/lib/Minz/PDOConnectionException.php @@ -0,0 +1,9 @@ +<?php +class Minz_PDOConnectionException extends Minz_Exception { + public function __construct ($string_connection, $user, $code = self::ERROR) { + $message = 'Access to database is denied for `' . $user . '`' + . ' (`' . $string_connection . '`)'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/Paginator.php b/lib/Minz/Paginator.php new file mode 100644 index 000000000..5858e76a5 --- /dev/null +++ b/lib/Minz/Paginator.php @@ -0,0 +1,196 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe Paginator permet de gérer la pagination de l'application facilement + */ +class Minz_Paginator { + /** + * $items tableau des éléments à afficher/gérer + */ + private $items = array (); + + /** + * $nbItemsPerPage le nombre d'éléments par page + */ + private $nbItemsPerPage = 10; + + /** + * $currentPage page actuelle à gérer + */ + private $currentPage = 1; + + /** + * $nbPage le nombre de pages de pagination + */ + private $nbPage = 1; + + /** + * $nbItems le nombre d'éléments + */ + private $nbItems = 0; + + /** + * Constructeur + * @param $items les éléments à gérer + */ + public function __construct ($items) { + $this->_items ($items); + $this->_nbItems (count ($this->items (true))); + $this->_nbItemsPerPage ($this->nbItemsPerPage); + $this->_currentPage ($this->currentPage); + } + + /** + * Permet d'afficher la pagination + * @param $view nom du fichier de vue situé dans /app/views/helpers/ + * @param $getteur variable de type $_GET[] permettant de retrouver la page + */ + public function render ($view, $getteur) { + $view = APP_PATH . '/views/helpers/'.$view; + + if (file_exists ($view)) { + include ($view); + } + } + + /** + * Permet de retrouver la page d'un élément donné + * @param $item l'élément à retrouver + * @return la page à laquelle se trouve l'élément (false si non trouvé) + */ + public function pageByItem ($item) { + $page = false; + $i = 0; + + do { + if ($item == $this->items[$i]) { + $page = ceil (($i + 1) / $this->nbItemsPerPage); + } + + $i++; + } while (!$page && $i < $this->nbItems ()); + + return $page; + } + + /** + * Permet de retrouver la position d'un élément donné (à partir de 0) + * @param $item l'élément à retrouver + * @return la position à laquelle se trouve l'élément (false si non trouvé) + */ + public function positionByItem ($item) { + $find = false; + $i = 0; + + do { + if ($item == $this->items[$i]) { + $find = true; + } else { + $i++; + } + } while (!$find && $i < $this->nbItems ()); + + return $i; + } + + /** + * Permet de récupérer un item par sa position + * @param $pos la position de l'élément + * @return l'item situé à $pos (dernier item si $pos<0, 1er si $pos>=count($items)) + */ + public function itemByPosition ($pos) { + if ($pos < 0) { + $pos = $this->nbItems () - 1; + } + if ($pos >= count($this->items)) { + $pos = 0; + } + + return $this->items[$pos]; + } + + /** + * GETTEURS + */ + /** + * @param $all si à true, retourne tous les éléments sans prendre en compte la pagination + */ + public function items ($all = false) { + $array = array (); + $nbItems = $this->nbItems (); + + if ($nbItems <= $this->nbItemsPerPage || $all) { + $array = $this->items; + } else { + $begin = ($this->currentPage - 1) * $this->nbItemsPerPage; + $counter = 0; + $i = 0; + + foreach ($this->items as $key => $item) { + if ($i >= $begin) { + $array[$key] = $item; + $counter++; + } + if ($counter >= $this->nbItemsPerPage) { + break; + } + $i++; + } + } + + return $array; + } + public function nbItemsPerPage () { + return $this->nbItemsPerPage; + } + public function currentPage () { + return $this->currentPage; + } + public function nbPage () { + return $this->nbPage; + } + public function nbItems () { + return $this->nbItems; + } + + /** + * SETTEURS + */ + public function _items ($items) { + if (is_array ($items)) { + $this->items = $items; + } + + $this->_nbPage (); + } + public function _nbItemsPerPage ($nbItemsPerPage) { + if ($nbItemsPerPage > $this->nbItems ()) { + $nbItemsPerPage = $this->nbItems (); + } + if ($nbItemsPerPage < 0) { + $nbItemsPerPage = 0; + } + + $this->nbItemsPerPage = $nbItemsPerPage; + $this->_nbPage (); + } + public function _currentPage ($page) { + if($page < 1 || ($page > $this->nbPage && $this->nbPage > 0)) { + throw new CurrentPagePaginationException ($page); + } + + $this->currentPage = $page; + } + private function _nbPage () { + if ($this->nbItemsPerPage > 0) { + $this->nbPage = ceil ($this->nbItems () / $this->nbItemsPerPage); + } + } + public function _nbItems ($value) { + $this->nbItems = $value; + } +} diff --git a/lib/Minz/PermissionDeniedException.php b/lib/Minz/PermissionDeniedException.php new file mode 100644 index 000000000..61be530d3 --- /dev/null +++ b/lib/Minz/PermissionDeniedException.php @@ -0,0 +1,8 @@ +<?php +class Minz_PermissionDeniedException extends Minz_Exception { + public function __construct ($file_name, $code = self::ERROR) { + $message = 'Permission is denied for `' . $file_name.'`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php new file mode 100644 index 000000000..f7a24c026 --- /dev/null +++ b/lib/Minz/Request.php @@ -0,0 +1,227 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * Request représente la requête http + */ +class Minz_Request { + private static $controller_name = ''; + private static $action_name = ''; + private static $params = array(); + + private static $default_controller_name = 'index'; + private static $default_action_name = 'index'; + + /** + * Getteurs + */ + public static function controllerName() { + return self::$controller_name; + } + public static function actionName() { + return self::$action_name; + } + public static function params() { + return self::$params; + } + public static function param($key, $default = false, $specialchars = false) { + if (isset(self::$params[$key])) { + $p = self::$params[$key]; + if (is_object($p) || $specialchars) { + return $p; + } else { + return Minz_Helper::htmlspecialchars_utf8($p); + } + } else { + return $default; + } + } + public static function defaultControllerName() { + return self::$default_controller_name; + } + public static function defaultActionName() { + return self::$default_action_name; + } + + /** + * Setteurs + */ + public static function _controllerName($controller_name) { + self::$controller_name = $controller_name; + } + public static function _actionName($action_name) { + self::$action_name = $action_name; + } + public static function _params($params) { + if (!is_array($params)) { + $params = array($params); + } + + self::$params = $params; + } + public static function _param($key, $value = false) { + if ($value === false) { + unset(self::$params[$key]); + } else { + self::$params[$key] = $value; + } + } + + /** + * Initialise la Request + */ + public static function init() { + self::magicQuotesOff(); + } + + /** + * Retourn le nom de domaine du site + */ + public static function getDomainName() { + return $_SERVER['HTTP_HOST']; + } + + /** + * Détermine la base de l'url + * @return la base de l'url + */ + public static function getBaseUrl() { + $defaultBaseUrl = Minz_Configuration::baseUrl(); + if (!empty($defaultBaseUrl)) { + return $defaultBaseUrl; + } elseif (isset($_SERVER['REQUEST_URI'])) { + return dirname($_SERVER['REQUEST_URI']) . '/'; + } else { + return '/'; + } + } + + /** + * Récupère l'URI de la requête + * @return l'URI + */ + public static function getURI() { + if (isset($_SERVER['REQUEST_URI'])) { + $base_url = self::getBaseUrl(); + $uri = $_SERVER['REQUEST_URI']; + + $len_base_url = strlen($base_url); + $real_uri = substr($uri, $len_base_url); + } else { + $real_uri = ''; + } + + return $real_uri; + } + + /** + * Relance une requête + * @param $url l'url vers laquelle est relancée la requête + * @param $redirect si vrai, force la redirection http + * > sinon, le dispatcher recharge en interne + */ + public static function forward($url = array(), $redirect = false) { + if (!is_array($url)) { + header('Location: ' . $url); + exit(); + } + + $url = Minz_Url::checkUrl($url); + + if ($redirect) { + header('Location: ' . Minz_Url::display($url, 'php')); + exit(); + } else { + self::_controllerName($url['c']); + self::_actionName($url['a']); + self::_params(array_merge( + self::$params, + $url['params'] + )); + Minz_Dispatcher::reset(); + } + } + + + /** + * Wrappers good notifications + redirection + * @param $msg notification content + * @param $url url array to where we should be forwarded + */ + public static function good($msg, $url = array()) { + Minz_Session::_param('notification', array( + 'type' => 'good', + 'content' => $msg + )); + + Minz_Request::forward($url, true); + } + + public static function bad($msg, $url = array()) { + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => $msg + )); + + Minz_Request::forward($url, true); + } + + + /** + * Permet de récupérer une variable de type $_GET + * @param $param nom de la variable + * @param $default valeur par défaut à attribuer à la variable + * @return $_GET[$param] + * $_GET si $param = false + * $default si $_GET[$param] n'existe pas + */ + public static function fetchGET($param = false, $default = false) { + if ($param === false) { + return $_GET; + } elseif (isset($_GET[$param])) { + return $_GET[$param]; + } else { + return $default; + } + } + + /** + * Permet de récupérer une variable de type $_POST + * @param $param nom de la variable + * @param $default valeur par défaut à attribuer à la variable + * @return $_POST[$param] + * $_POST si $param = false + * $default si $_POST[$param] n'existe pas + */ + public static function fetchPOST($param = false, $default = false) { + if ($param === false) { + return $_POST; + } elseif (isset($_POST[$param])) { + return $_POST[$param]; + } else { + return $default; + } + } + + /** + * Méthode désactivant les magic_quotes pour les variables + * $_GET + * $_POST + * $_COOKIE + */ + private static function magicQuotesOff() { + if (get_magic_quotes_gpc()) { + $_GET = Minz_Helper::stripslashes_r($_GET); + $_POST = Minz_Helper::stripslashes_r($_POST); + $_COOKIE = Minz_Helper::stripslashes_r($_COOKIE); + } + } + + public static function isPost() { + return isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD'] === 'POST'; + } +} diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php new file mode 100644 index 000000000..af4de75bb --- /dev/null +++ b/lib/Minz/Session.php @@ -0,0 +1,93 @@ +<?php + +/** + * La classe Session gère la session utilisateur + */ +class Minz_Session { + /** + * Initialise la session, avec un nom + * Le nom de session est utilisé comme nom pour les cookies et les URLs(i.e. PHPSESSID). + * Il ne doit contenir que des caractères alphanumériques ; il doit être court et descriptif + */ + public static function init($name) { + $cookie = session_get_cookie_params(); + self::keepCookie($cookie['lifetime']); + + // démarre la session + session_name($name); + session_start(); + } + + + /** + * Permet de récupérer une variable de session + * @param $p le paramètre à récupérer + * @return la valeur de la variable de session, false si n'existe pas + */ + public static function param($p, $default = false) { + return isset($_SESSION[$p]) ? $_SESSION[$p] : $default; + } + + + /** + * Permet de créer ou mettre à jour une variable de session + * @param $p le paramètre à créer ou modifier + * @param $v la valeur à attribuer, false pour supprimer + */ + public static function _param($p, $v = false) { + if ($v === false) { + unset($_SESSION[$p]); + } else { + $_SESSION[$p] = $v; + } + } + + + /** + * Permet d'effacer une session + * @param $force si à false, n'efface pas le paramètre de langue + */ + public static function unset_session($force = false) { + $language = self::param('language'); + + session_destroy(); + $_SESSION = array(); + + if (!$force) { + self::_param('language', $language); + Minz_Translate::reset(); + } + } + + + /** + * Spécifie la durée de vie des cookies + * @param $l la durée de vie + */ + public static function keepCookie($l) { + $cookie_dir = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI']; + session_set_cookie_params($l, $cookie_dir, '', false, true); + } + + + /** + * Régénère un id de session. + * Utile pour appeler session_set_cookie_params après session_start() + */ + public static function regenerateID() { + session_regenerate_id(true); + } + + public static function deleteLongTermCookie($name) { + setcookie($name, '', 1, '', '', false, true); + } + + public static function setLongTermCookie($name, $value, $expire) { + setcookie($name, $value, $expire, '', '', false, true); + } + + public static function getLongTermCookie($name) { + return isset($_COOKIE[$name]) ? $_COOKIE[$name] : null; + } + +} diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php new file mode 100644 index 000000000..8c2f90041 --- /dev/null +++ b/lib/Minz/Translate.php @@ -0,0 +1,79 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> + */ + +/** + * La classe Translate se charge de la traduction + * Utilise les fichiers du répertoire /app/i18n/ + */ +class Minz_Translate { + /** + * $language est la langue à afficher + */ + private static $language; + + /** + * $translates est le tableau de correspondance + * $key => $traduction + */ + private static $translates = array(); + + /** + * Inclus le fichier de langue qui va bien + * l'enregistre dans $translates + */ + public static function init() { + $l = Minz_Configuration::language(); + self::$language = Minz_Session::param('language', $l); + + $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; + + if (file_exists($l_path)) { + self::$translates = include($l_path); + } + } + + /** + * Alias de init + */ + public static function reset() { + self::init(); + } + + /** + * Traduit une clé en sa valeur du tableau $translates + * @param $key la clé à traduire + * @return la valeur correspondante à la clé + * > si non présente dans le tableau, on retourne la clé elle-même + */ + public static function t($key) { + $translate = $key; + + if (isset(self::$translates[$key])) { + $translate = self::$translates[$key]; + } + + $args = func_get_args(); + unset($args[0]); + + return vsprintf($translate, $args); + } + + /** + * Retourne la langue utilisée actuellement + * @return la langue + */ + public static function language() { + return self::$language; + } +} + +function _t($key) { + $args = func_get_args(); + unset($args[0]); + array_unshift($args, $key); + + return call_user_func_array('Minz_Translate::t', $args); +} diff --git a/lib/Minz/Url.php b/lib/Minz/Url.php new file mode 100644 index 000000000..e9f9a69ba --- /dev/null +++ b/lib/Minz/Url.php @@ -0,0 +1,125 @@ +<?php + +/** + * La classe Url permet de gérer les URL à travers MINZ + */ +class Minz_Url { + /** + * Affiche une Url formatée + * @param $url l'url à formater définie comme un tableau : + * $url['c'] = controller + * $url['a'] = action + * $url['params'] = tableau des paramètres supplémentaires + * $url['protocol'] = protocole à utiliser (http par défaut) + * ou comme une chaîne de caractère + * @param $encodage pour indiquer comment encoder les & (& ou & pour html) + * @return l'url formatée + */ + public static function display ($url = array (), $encodage = 'html', $absolute = false) { + $isArray = is_array($url); + + if ($isArray) { + $url = self::checkUrl ($url); + } + + $url_string = ''; + + if ($absolute) { + if ($isArray && isset ($url['protocol'])) { + $protocol = $url['protocol']; + } elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { + $protocol = 'https:'; + } else { + $protocol = 'http:'; + } + $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl (); + } else { + $url_string = $isArray ? '.' : PUBLIC_RELATIVE; + } + + if ($isArray) { + $url_string .= self::printUri ($url, $encodage); + } else { + $url_string .= $url; + } + + return $url_string; + } + + /** + * Construit l'URI d'une URL + * @param l'url sous forme de tableau + * @param $encodage pour indiquer comment encoder les & (& ou & pour html) + * @return l'uri sous la forme ?key=value&key2=value2 + */ + private static function printUri ($url, $encodage) { + $uri = ''; + $separator = '?'; + + if($encodage == 'html') { + $and = '&'; + } else { + $and = '&'; + } + + if (isset ($url['c']) + && $url['c'] != Minz_Request::defaultControllerName ()) { + $uri .= $separator . 'c=' . $url['c']; + $separator = $and; + } + + if (isset ($url['a']) + && $url['a'] != Minz_Request::defaultActionName ()) { + $uri .= $separator . 'a=' . $url['a']; + $separator = $and; + } + + if (isset ($url['params'])) { + foreach ($url['params'] as $key => $param) { + $uri .= $separator . $key . '=' . $param; + $separator = $and; + } + } + + return $uri; + } + + /** + * Vérifie que les éléments du tableau représentant une url soit ok + * @param l'url sous forme de tableau (sinon renverra directement $url) + * @return l'url vérifié + */ + public static function checkUrl ($url) { + $url_checked = $url; + + if (is_array ($url)) { + if (!isset ($url['c'])) { + $url_checked['c'] = Minz_Request::defaultControllerName (); + } + if (!isset ($url['a'])) { + $url_checked['a'] = Minz_Request::defaultActionName (); + } + if (!isset ($url['params'])) { + $url_checked['params'] = array (); + } + } + + return $url_checked; + } +} + +function _url ($controller, $action) { + $nb_args = func_num_args (); + + if($nb_args < 2 || $nb_args % 2 != 0) { + return false; + } + + $args = func_get_args (); + $params = array (); + for($i = 2; $i < $nb_args; $i = $i + 2) { + $params[$args[$i]] = $args[$i + 1]; + } + + return Minz_Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); +} diff --git a/lib/Minz/View.php b/lib/Minz/View.php new file mode 100644 index 000000000..a0dec1824 --- /dev/null +++ b/lib/Minz/View.php @@ -0,0 +1,249 @@ +<?php +/** + * MINZ - Copyright 2011 Marien Fressinaud + * Sous licence AGPL3 <http://www.gnu.org/licenses/> +*/ + +/** + * La classe View représente la vue de l'application + */ +class Minz_View { + const VIEWS_PATH_NAME = '/views'; + const LAYOUT_PATH_NAME = '/layout'; + const LAYOUT_FILENAME = '/layout.phtml'; + + private $view_filename = ''; + private $use_layout = null; + + private static $title = ''; + private static $styles = array (); + private static $scripts = array (); + + private static $params = array (); + + /** + * Constructeur + * Détermine si on utilise un layout ou non + */ + public function __construct () { + $this->change_view(Minz_Request::controllerName(), + Minz_Request::actionName()); + self::$title = Minz_Configuration::title (); + } + + /** + * Change le fichier de vue en fonction d'un controller / action + */ + public function change_view($controller_name, $action_name) { + $this->view_filename = APP_PATH + . self::VIEWS_PATH_NAME . '/' + . $controller_name . '/' + . $action_name . '.phtml'; + } + + /** + * Construit la vue + */ + public function build () { + if ($this->use_layout === null) { //TODO: avoid file_exists and require views to be explicit + $this->use_layout = file_exists (APP_PATH . self::LAYOUT_PATH_NAME . self::LAYOUT_FILENAME); + } + if ($this->use_layout) { + $this->buildLayout (); + } else { + $this->render (); + } + } + + /** + * Construit le layout + */ + public function buildLayout () { + include ( + APP_PATH + . self::LAYOUT_PATH_NAME + . self::LAYOUT_FILENAME + ); + } + + /** + * Affiche la Vue en elle-même + */ + public function render () { + if ((include($this->view_filename)) === false) { + Minz_Log::record ('File not found: `' + . $this->view_filename . '`', + Minz_Log::NOTICE); + } + } + + /** + * Ajoute un élément du layout + * @param $part l'élément partial à ajouter + */ + public function partial ($part) { + $fic_partial = APP_PATH + . self::LAYOUT_PATH_NAME . '/' + . $part . '.phtml'; + + if ((include($fic_partial)) === false) { + Minz_Log::record ('File not found: `' + . $fic_partial . '`', + Minz_Log::WARNING); + } + } + + /** + * Affiche un élément graphique situé dans APP./views/helpers/ + * @param $helper l'élément à afficher + */ + public function renderHelper ($helper) { + $fic_helper = APP_PATH + . '/views/helpers/' + . $helper . '.phtml'; + + if ((include($fic_helper)) === false) {; + Minz_Log::record ('File not found: `' + . $fic_helper . '`', + Minz_Log::WARNING); + } + } + + /** + * Retourne renderHelper() dans une chaîne + * @param $helper l'élément à traîter + */ + public function helperToString($helper) { + ob_start(); + $this->renderHelper($helper); + return ob_get_clean(); + } + + /** + * Permet de choisir si on souhaite utiliser le layout + * @param $use true si on souhaite utiliser le layout, false sinon + */ + public function _useLayout ($use) { + $this->use_layout = $use; + } + + /** + * Gestion du titre + */ + public static function title () { + return self::$title; + } + public static function headTitle () { + return '<title>' . self::$title . '</title>' . "\n"; + } + public static function _title ($title) { + self::$title = $title; + } + public static function prependTitle ($title) { + self::$title = $title . self::$title; + } + public static function appendTitle ($title) { + self::$title = self::$title . $title; + } + + /** + * Gestion des feuilles de style + */ + public static function headStyle () { + $styles = ''; + + foreach(self::$styles as $style) { + $cond = $style['cond']; + if ($cond) { + $styles .= '<!--[if ' . $cond . ']>'; + } + + $styles .= '<link rel="stylesheet" ' . + ($style['media'] === 'all' ? '' : 'media="' . $style['media'] . '" ') . + 'href="' . $style['url'] . '" />'; + + if ($cond) { + $styles .= '<![endif]-->'; + } + + $styles .= "\n"; + } + + return $styles; + } + public static function prependStyle ($url, $media = 'all', $cond = false) { + array_unshift (self::$styles, array ( + 'url' => $url, + 'media' => $media, + 'cond' => $cond + )); + } + public static function appendStyle ($url, $media = 'all', $cond = false) { + self::$styles[] = array ( + 'url' => $url, + 'media' => $media, + 'cond' => $cond + ); + } + + /** + * Gestion des scripts JS + */ + public static function headScript () { + $scripts = ''; + + foreach (self::$scripts as $script) { + $cond = $script['cond']; + if ($cond) { + $scripts .= '<!--[if ' . $cond . ']>'; + } + + $scripts .= '<script src="' . $script['url'] . '"'; + if ($script['defer']) { + $scripts .= ' defer="defer"'; + } + if ($script['async']) { + $scripts .= ' async="async"'; + } + $scripts .= '></script>'; + + if ($cond) { + $scripts .= '<![endif]-->'; + } + + $scripts .= "\n"; + } + + return $scripts; + } + public static function prependScript ($url, $cond = false, $defer = true, $async = true) { + array_unshift(self::$scripts, array ( + 'url' => $url, + 'cond' => $cond, + 'defer' => $defer, + 'async' => $async, + )); + } + public static function appendScript ($url, $cond = false, $defer = true, $async = true) { + self::$scripts[] = array ( + 'url' => $url, + 'cond' => $cond, + 'defer' => $defer, + 'async' => $async, + ); + } + + /** + * Gestion des paramètres ajoutés à la vue + */ + public static function _param ($key, $value) { + self::$params[$key] = $value; + } + public function attributeParams () { + foreach (Minz_View::$params as $key => $value) { + $this->$key = $value; + } + } +} + + |
