From c96225df6d6ba3aca0c6786c7f091f02c11d6e8d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 12 May 2013 16:51:45 +0200 Subject: Fix issue #84 : affichage erreur si fichier OPML invalide --- lib/lib_rss.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index c574cd3fd..77d3ac2db 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -65,7 +65,7 @@ function opml_import ($xml) { $opml = @simplexml_load_string ($xml); if (!$opml) { - return array (array (), array ()); + throw new OpmlException (); } $categories = array (); -- cgit v1.2.3 From fb5e5594bea149ca730bc6424dc547dab3347747 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 14 Jun 2013 20:53:12 +0200 Subject: Fix issue #82 : ajout direct de Minz sans devoir faire appel au script ./build.sh --- .gitignore | 1 - build.sh | 50 ------- lib/minz/ActionController.php | 42 ++++++ lib/minz/Cache.php | 116 ++++++++++++++++ lib/minz/Configuration.php | 240 ++++++++++++++++++++++++++++++++++ lib/minz/Dispatcher.php | 152 +++++++++++++++++++++ lib/minz/Error.php | 94 +++++++++++++ lib/minz/FrontController.php | 123 +++++++++++++++++ lib/minz/Helper.php | 22 ++++ lib/minz/Log.php | 92 +++++++++++++ lib/minz/Model.php | 12 ++ lib/minz/Paginator.php | 196 +++++++++++++++++++++++++++ lib/minz/Request.php | 189 ++++++++++++++++++++++++++ lib/minz/Response.php | 60 +++++++++ lib/minz/Router.php | 209 +++++++++++++++++++++++++++++ lib/minz/Session.php | 78 +++++++++++ lib/minz/Translate.php | 71 ++++++++++ lib/minz/Url.php | 130 ++++++++++++++++++ lib/minz/View.php | 232 ++++++++++++++++++++++++++++++++ lib/minz/dao/Model_array.php | 122 +++++++++++++++++ lib/minz/dao/Model_pdo.php | 39 ++++++ lib/minz/dao/Model_txt.php | 77 +++++++++++ lib/minz/exceptions/MinzException.php | 94 +++++++++++++ 23 files changed, 2390 insertions(+), 51 deletions(-) delete mode 100755 build.sh create mode 100755 lib/minz/ActionController.php create mode 100644 lib/minz/Cache.php create mode 100755 lib/minz/Configuration.php create mode 100644 lib/minz/Dispatcher.php create mode 100755 lib/minz/Error.php create mode 100755 lib/minz/FrontController.php create mode 100755 lib/minz/Helper.php create mode 100755 lib/minz/Log.php create mode 100755 lib/minz/Model.php create mode 100755 lib/minz/Paginator.php create mode 100644 lib/minz/Request.php create mode 100644 lib/minz/Response.php create mode 100755 lib/minz/Router.php create mode 100755 lib/minz/Session.php create mode 100644 lib/minz/Translate.php create mode 100755 lib/minz/Url.php create mode 100755 lib/minz/View.php create mode 100755 lib/minz/dao/Model_array.php create mode 100755 lib/minz/dao/Model_pdo.php create mode 100755 lib/minz/dao/Model_txt.php create mode 100644 lib/minz/exceptions/MinzException.php (limited to 'lib') diff --git a/.gitignore b/.gitignore index c9c8cacf4..e69de29bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +0,0 @@ -lib/minz diff --git a/build.sh b/build.sh deleted file mode 100755 index e6c563b83..000000000 --- a/build.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -MINZ_REPO_URL="https://github.com/marienfressinaud/MINZ.git" -MINZ_CLONE_PATH="./minz_tmp" -LIB_MINZ_PATH="./minz_tmp/lib/*" -LIB_PATH="./lib/minz" -LOG_PATH="./log" -CACHE_PATH="./cache" - -git_check() { - printf "Vérification de la présence de git... " - - EXE_PATH=$(which "git" 2>/dev/null) - if [ $? -ne 0 ]; then - printf "git n'est pas présent sur votre système. Veuillez l'installer avant de continuer\n"; - exit 1 - else - printf "git a été trouvé\n" - fi -} - -dir_check() { - test -d $LOG_PATH - if [ $? -ne 0 ]; then - mkdir $LOG_PATH - fi - - test -d $CACHE_PATH - if [ $? -ne 0 ]; then - mkdir $CACHE_PATH - fi -} - -clone_minz() { - printf "Récupération de Minz...\n" - - git clone $MINZ_REPO_URL $MINZ_CLONE_PATH - test -d $LIB_PATH - if [ $? -ne 0 ]; then - mkdir -p $LIB_PATH - fi - mv $LIB_MINZ_PATH $LIB_PATH - rm -rf $MINZ_CLONE_PATH - - printf "Récupération de Minz terminée...\n" -} - -git_check -dir_check -clone_minz diff --git a/lib/minz/ActionController.php b/lib/minz/ActionController.php new file mode 100755 index 000000000..ab9389dbd --- /dev/null +++ b/lib/minz/ActionController.php @@ -0,0 +1,42 @@ + +*/ + +/** + * La classe ActionController représente le contrôleur de l'application + */ +class ActionController { + protected $router; + protected $view; + + /** + * Constructeur + * @param $controller nom du controller + * @param $action nom de l'action à lancer + */ + public function __construct ($router) { + $this->router = $router; + $this->view = new 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/Cache.php b/lib/minz/Cache.php new file mode 100644 index 000000000..69143a70c --- /dev/null +++ b/lib/minz/Cache.php @@ -0,0 +1,116 @@ + +*/ + +/** + * La classe Cache permet de gérer facilement les pages en cache + */ +class Cache { + /** + * $expire timestamp auquel expire le cache de $url + */ + private $expire = 0; + + /** + * $file est le nom du fichier de cache + */ + private $file = ''; + + /** + * $enabled permet de déterminer si le cache est activé + */ + private static $enabled = true; + + /** + * Constructeur + */ + public function __construct () { + $this->_fileName (); + $this->_expire (); + } + + /** + * Setteurs + */ + public function _fileName () { + $file = md5 (Request::getURI ()); + + $this->file = CACHE_PATH . '/'.$file; + } + + public function _expire () { + if ($this->exist ()) { + $this->expire = filemtime ($this->file) + + Configuration::delayCache (); + } + } + + /** + * Permet de savoir si le cache est activé + * @return true si activé, false sinon + */ + public static function isEnabled () { + return Configuration::cacheEnabled () && self::$enabled; + } + + /** + * Active / désactive le cache + */ + public static function switchOn () { + self::$enabled = true; + } + public static function switchOff () { + self::$enabled = false; + } + + /** + * Détermine si le cache de $url a expiré ou non + * @return true si il a expiré, false sinon + */ + public function expired () { + return time () > $this->expire; + } + + /** + * Affiche le contenu du cache + * @print le code html du cache + */ + public function render () { + if ($this->exist ()) { + include ($this->file); + } + } + + /** + * Enregistre $html en cache + * @param $html le html à mettre en cache + */ + public function cache ($html) { + file_put_contents ($this->file, $html); + } + + /** + * Permet de savoir si le cache existe + * @return true si il existe, false sinon + */ + public function exist () { + return file_exists ($this->file); + } + + /** + * Nettoie le cache en supprimant tous les fichiers + */ + public static function clean () { + $files = opendir (CACHE_PATH); + + while ($fic = readdir ($files)) { + if ($fic != '.' && $fic != '..') { + unlink (CACHE_PATH.'/'.$fic); + } + } + + closedir ($files); + } +} diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php new file mode 100755 index 000000000..7cb7ea207 --- /dev/null +++ b/lib/minz/Configuration.php @@ -0,0 +1,240 @@ + +*/ + +/** + * La classe Configuration permet de gérer la configuration de l'application + */ +class Configuration { + const CONF_PATH_NAME = '/configuration/application.ini'; + + /** + * VERSION est la version actuelle de MINZ + */ + const VERSION = '1.3.1'; + + /** + * 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 + * $sel_application une chaîne de caractères aléatoires (obligatoire) + * $environment gère le niveau d'affichage pour log et erreurs + * $use_url_rewriting indique si on utilise l'url_rewriting + * $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 + * $cacheEnabled permet de savoir si le cache doit être activé + * $delayCache la limite de cache + * $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 $sel_application = ''; + private static $environment = Configuration::PRODUCTION; + private static $base_url = ''; + private static $use_url_rewriting = false; + private static $title = ''; + private static $language = 'en'; + private static $cache_enabled = false; + private static $delay_cache = 3600; + + private static $db = array ( + 'host' => false, + 'user' => false, + 'password' => false, + 'base' => false + ); + + /* + * Getteurs + */ + public static function selApplication () { + return self::$sel_application; + } + public static function environment () { + return self::$environment; + } + public static function baseUrl () { + return self::$base_url; + } + public static function useUrlRewriting () { + return self::$use_url_rewriting; + } + public static function title () { + return self::$title; + } + public static function language () { + return self::$language; + } + public static function cacheEnabled () { + return self::$cache_enabled; + } + public static function delayCache () { + return self::$delay_cache; + } + public static function dataBase () { + return self::$db; + } + + /** + * Initialise les variables de configuration + * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + */ + public static function init () { + try { + self::parseFile (); + self::setReporting (); + } catch (BadConfigurationException $e) { + throw $e; + } catch (FileNotExistException $e) { + throw $e; + } + } + + /** + * Parse un fichier de configuration de type ".ini" + * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + */ + private static function parseFile () { + if (!file_exists (APP_PATH . self::CONF_PATH_NAME)) { + throw new FileNotExistException ( + APP_PATH . self::CONF_PATH_NAME, + MinzException::ERROR + ); + } + $ini_array = parse_ini_file ( + APP_PATH . self::CONF_PATH_NAME, + true + ); + + // [general] est obligatoire + if (!isset ($ini_array['general'])) { + throw new BadConfigurationException ( + '[general]', + MinzException::ERROR + ); + } + $general = $ini_array['general']; + + + // sel_application est obligatoire + if (!isset ($general['sel_application'])) { + throw new BadConfigurationException ( + 'sel_application', + MinzException::ERROR + ); + } + self::$sel_application = $general['sel_application']; + + if (isset ($general['environment'])) { + switch ($general['environment']) { + case 'silent': + self::$environment = Configuration::SILENT; + break; + case 'development': + self::$environment = Configuration::DEVELOPMENT; + break; + case 'production': + self::$environment = Configuration::PRODUCTION; + break; + default: + throw new BadConfigurationException ( + 'environment', + MinzException::ERROR + ); + } + + } + if (isset ($general['base_url'])) { + self::$base_url = $general['base_url']; + } + if (isset ($general['use_url_rewriting'])) { + self::$use_url_rewriting = $general['use_url_rewriting']; + } + + if (isset ($general['title'])) { + self::$title = $general['title']; + } + if (isset ($general['language'])) { + self::$language = $general['language']; + } + if (isset ($general['cache_enabled'])) { + self::$cache_enabled = $general['cache_enabled']; + if (CACHE_PATH === false && self::$cache_enabled) { + throw new FileNotExistException ( + 'CACHE_PATH', + MinzException::ERROR + ); + } + } + if (isset ($general['delay_cache'])) { + self::$delay_cache = $general['delay_cache']; + } + + // Base de données + $db = false; + if (isset ($ini_array['db'])) { + $db = $ini_array['db']; + } + if ($db) { + if (!isset ($db['host'])) { + throw new BadConfigurationException ( + 'host', + MinzException::ERROR + ); + } + if (!isset ($db['user'])) { + throw new BadConfigurationException ( + 'user', + MinzException::ERROR + ); + } + if (!isset ($db['password'])) { + throw new BadConfigurationException ( + 'password', + MinzException::ERROR + ); + } + if (!isset ($db['base'])) { + throw new BadConfigurationException ( + 'base', + MinzException::ERROR + ); + } + + self::$db['host'] = $db['host']; + self::$db['user'] = $db['user']; + self::$db['password'] = $db['password']; + self::$db['base'] = $db['base']; + } + } + + private static function setReporting () { + if (self::environment () == self::DEVELOPMENT) { + error_reporting (E_ALL); + ini_set ('display_errors','On'); + ini_set('log_errors', 'On'); + } elseif (self::environment () == self::PRODUCTION) { + error_reporting(E_ALL); + ini_set('display_errors','Off'); + ini_set('log_errors', 'On'); + } else { + error_reporting(0); + } + } +} diff --git a/lib/minz/Dispatcher.php b/lib/minz/Dispatcher.php new file mode 100644 index 000000000..9d08c142b --- /dev/null +++ b/lib/minz/Dispatcher.php @@ -0,0 +1,152 @@ + +*/ + +/** + * Le Dispatcher s'occupe d'initialiser le Controller et d'executer l'action + * déterminée dans la Request + * C'est un singleton + */ +class Dispatcher { + const CONTROLLERS_PATH_NAME = '/controllers'; + + /* singleton */ + private static $instance = null; + + private $router; + private $controller; + + /** + * Récupère l'instance du Dispatcher + */ + public static function getInstance ($router) { + if (is_null (self::$instance)) { + self::$instance = new Dispatcher ($router); + } + return self::$instance; + } + + /** + * Constructeur + */ + private function __construct ($router) { + $this->router = $router; + } + + /** + * Lance le controller indiqué dans Request + * Remplit le body de Response à partir de la Vue + * @exception MinzException + */ + public function run () { + $cache = new Cache(); + // Le ob_start est dupliqué : sans ça il y a un bug sous Firefox + // ici on l'appelle avec 'ob_gzhandler', après sans. + // Vraisemblablement la compression fonctionne mais c'est sale + // J'ignore les effets de bord :( + ob_start ('ob_gzhandler'); + + if (Cache::isEnabled () && !$cache->expired ()) { + ob_start (); + $cache->render (); + $text = ob_get_clean(); + } else { + while (Request::$reseted) { + Request::$reseted = false; + + try { + $this->createController ( + Request::controllerName () + . 'Controller' + ); + + $this->controller->init (); + $this->controller->firstAction (); + $this->launchAction ( + Request::actionName () + . 'Action' + ); + $this->controller->lastAction (); + + if (!Request::$reseted) { + ob_start (); + $this->controller->view ()->build (); + $text = ob_get_clean(); + } + } catch (MinzException $e) { + throw $e; + } + } + + if (Cache::isEnabled ()) { + $cache->cache ($text); + } + } + + Response::setBody ($text); + } + + /** + * Instancie le Controller + * @param $controller_name le nom du controller à instancier + * @exception FileNotExistException le fichier correspondant au + * > controller n'existe pas + * @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 (!file_exists ($filename)) { + throw new FileNotExistException ( + $filename, + MinzException::ERROR + ); + } + require_once ($filename); + + if (!class_exists ($controller_name)) { + throw new ControllerNotExistException ( + $controller_name, + MinzException::ERROR + ); + } + $this->controller = new $controller_name ($this->router); + + if (! ($this->controller instanceof ActionController)) { + throw new ControllerNotActionControllerException ( + $controller_name, + MinzException::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 (!Request::$reseted) { + if (!is_callable (array ( + $this->controller, + $action_name + ))) { + throw new ActionException ( + get_class ($this->controller), + $action_name, + MinzException::ERROR + ); + } + call_user_func (array ( + $this->controller, + $action_name + )); + } + } +} diff --git a/lib/minz/Error.php b/lib/minz/Error.php new file mode 100755 index 000000000..0e8c2f60b --- /dev/null +++ b/lib/minz/Error.php @@ -0,0 +1,94 @@ + +*/ + +/** + * La classe Error permet de lancer des erreurs HTTP + */ +class 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'; + + if (file_exists ($error_filename)) { + $params = array ( + 'code' => $code, + 'logs' => $logs + ); + + Response::setHeader ($code); + if ($redirect) { + Request::forward (array ( + 'c' => 'error' + ), true); + } else { + Request::forward (array ( + 'c' => 'error', + 'params' => $params + ), false); + } + } else { + $text = '

An error occured

'."\n"; + + if (!empty ($logs)) { + $text .= ''."\n"; + } + + Response::setHeader ($code); + Response::setBody ($text); + Response::send (); + 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 = 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 == Configuration::PRODUCTION) { + $logs_ok = $error; + } + if ($env == Configuration::DEVELOPMENT) { + $logs_ok = array_merge ($error, $warning, $notice); + } + + return $logs_ok; + } +} diff --git a/lib/minz/FrontController.php b/lib/minz/FrontController.php new file mode 100755 index 000000000..ab951263d --- /dev/null +++ b/lib/minz/FrontController.php @@ -0,0 +1,123 @@ +. +# +# ***** END LICENSE BLOCK ***** + +/** + * La classe FrontController est le noyau du framework, elle lance l'application + * Elle est appelée en général dans le fichier index.php à la racine du serveur + */ +class FrontController { + protected $dispatcher; + protected $router; + + /** + * Constructeur + * Initialise le router et le dispatcher + */ + public function __construct () { + $this->loadLib (); + + if (LOG_PATH === false) { + $this->killApp ('Path doesn\'t exist : LOG_PATH'); + } + + try { + Configuration::init (); + + Request::init (); + + $this->router = new Router (); + $this->router->init (); + } catch (RouteNotFoundException $e) { + Log::record ($e->getMessage (), Log::ERROR); + Error::error ( + 404, + array ('error' => array ($e->getMessage ())) + ); + } catch (MinzException $e) { + Log::record ($e->getMessage (), Log::ERROR); + $this->killApp (); + } + + $this->dispatcher = Dispatcher::getInstance ($this->router); + } + + /** + * Inclue les fichiers de la librairie + */ + private function loadLib () { + require ('ActionController.php'); + require ('Cache.php'); + require ('Configuration.php'); + require ('Dispatcher.php'); + require ('Error.php'); + require ('Helper.php'); + require ('Log.php'); + require ('Model.php'); + require ('Paginator.php'); + require ('Request.php'); + require ('Response.php'); + require ('Router.php'); + require ('Session.php'); + require ('Translate.php'); + require ('Url.php'); + require ('View.php'); + + require ('dao/Model_pdo.php'); + require ('dao/Model_txt.php'); + require ('dao/Model_array.php'); + + require ('exceptions/MinzException.php'); + } + + /** + * Démarre l'application (lance le dispatcher et renvoie la réponse + */ + public function run () { + try { + $this->dispatcher->run (); + Response::send (); + } catch (MinzException $e) { + Log::record ($e->getMessage (), Log::ERROR); + + if ($e instanceof FileNotExistException || + $e instanceof ControllerNotExistException || + $e instanceof ControllerNotActionControllerException || + $e instanceof ActionException) { + 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 ###'."\n".$txt); + } +} diff --git a/lib/minz/Helper.php b/lib/minz/Helper.php new file mode 100755 index 000000000..4f64ba218 --- /dev/null +++ b/lib/minz/Helper.php @@ -0,0 +1,22 @@ + +*/ + +/** + * La classe Helper représente une aide pour des tâches récurrentes + */ +class 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 ('Helper', 'stripslashes_r'), $var); + } else { + return stripslashes($var); + } + } +} diff --git a/lib/minz/Log.php b/lib/minz/Log.php new file mode 100755 index 000000000..30e4eb6a4 --- /dev/null +++ b/lib/minz/Log.php @@ -0,0 +1,92 @@ + +*/ + +/** + * La classe Log permet de logger des erreurs + */ +class 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 messages d'informations, affichés pour le déboggage + */ + const ERROR = 0; + const WARNING = 10; + const NOTICE = 20; + + /** + * 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 = Configuration::environment (); + + if (! ($env == Configuration::SILENT + || ($env == Configuration::PRODUCTION + && ($level == Log::WARNING || $level == Log::NOTICE)))) { + if (is_null ($file_name)) { + $file_name = LOG_PATH . '/application.log'; + } + + switch ($level) { + case Log::ERROR : + $level_label = 'error'; + break; + case Log::WARNING : + $level_label = 'warning'; + break; + case Log::NOTICE : + $level_label = 'notice'; + break; + default : + $level_label = 'unknown'; + } + + if ($env == Configuration::PRODUCTION) { + $file = @fopen ($file_name, 'a'); + } else { + $file = fopen ($file_name, 'a'); + } + + if ($file !== false) { + $log = '[' . date('r') . ']'; + $log .= ' [' . $level_label . ']'; + $log .= ' --- ' . $information . "\n"; + fwrite ($file, $log); + fclose ($file); + } else { + Error::error ( + 500, + array ('error' => array ( + 'Permission is denied for `' + . $file_name . '`') + ) + ); + } + } + } + + /** + * 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, Log::NOTICE, $file_name); + self::record($msg_post, Log::NOTICE, $file_name); + } +} diff --git a/lib/minz/Model.php b/lib/minz/Model.php new file mode 100755 index 000000000..37fc19ed1 --- /dev/null +++ b/lib/minz/Model.php @@ -0,0 +1,12 @@ + +*/ + +/** + * La classe Model représente un modèle de l'application (représentation MVC) + */ +class Model { + +} diff --git a/lib/minz/Paginator.php b/lib/minz/Paginator.php new file mode 100755 index 000000000..1a8376e75 --- /dev/null +++ b/lib/minz/Paginator.php @@ -0,0 +1,196 @@ + +*/ + +/** + * La classe Paginator permet de gérer la pagination de l'application facilement + */ +class 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/Request.php b/lib/minz/Request.php new file mode 100644 index 000000000..507630b84 --- /dev/null +++ b/lib/minz/Request.php @@ -0,0 +1,189 @@ + +*/ + +/** + * Request représente la requête http + */ +class 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'; + + public static $reseted = true; + + /** + * 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) { + if (isset (self::$params[$key])) { + return self::$params[$key]; + } 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 () { + return Configuration::baseUrl (); + } + + /** + * 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) { + $url = Url::checkUrl ($url); + + if ($redirect) { + header ('Location: ' . Url::display ($url, 'php')); + exit (); + } else { + self::$reseted = true; + + self::_controllerName ($url['c']); + self::_actionName ($url['a']); + self::_params (array_merge ( + self::$params, + $url['params'] + )); + } + } + + /** + * 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 = Helper::stripslashes_r ($_GET); + $_POST = Helper::stripslashes_r ($_POST); + $_COOKIE = Helper::stripslashes_r ($_COOKIE); + } + } + + public static function isPost () { + return !empty ($_POST) || !empty ($_FILES); + } +} + + diff --git a/lib/minz/Response.php b/lib/minz/Response.php new file mode 100644 index 000000000..fcf53c5b1 --- /dev/null +++ b/lib/minz/Response.php @@ -0,0 +1,60 @@ + +*/ + +/** + * Response représente la requête http renvoyée à l'utilisateur + */ +class Response { + private static $header = 'HTTP/1.0 200 OK'; + private static $body = ''; + + /** + * Mets à jour le body de la Response + * @param $text le texte à incorporer dans le body + */ + public static function setBody ($text) { + self::$body = $text; + } + + /** + * Mets à jour le header de la Response + * @param $code le code HTTP, valeurs possibles + * - 200 (OK) + * - 403 (Forbidden) + * - 404 (Forbidden) + * - 500 (Forbidden) -> par défaut si $code erroné + * - 503 (Forbidden) + */ + public static function setHeader ($code) { + switch ($code) { + case 200 : + self::$header = 'HTTP/1.0 200 OK'; + break; + case 403 : + self::$header = 'HTTP/1.0 403 Forbidden'; + break; + case 404 : + self::$header = 'HTTP/1.0 404 Not Found'; + break; + case 500 : + self::$header = 'HTTP/1.0 500 Internal Server Error'; + break; + case 503 : + self::$header = 'HTTP/1.0 503 Service Unavailable'; + break; + default : + self::$header = 'HTTP/1.0 500 Internal Server Error'; + } + } + + /** + * Envoie la Response à l'utilisateur + */ + public static function send () { + header (self::$header); + echo self::$body; + } +} diff --git a/lib/minz/Router.php b/lib/minz/Router.php new file mode 100755 index 000000000..c5d6f5baa --- /dev/null +++ b/lib/minz/Router.php @@ -0,0 +1,209 @@ + +*/ + +/** + * La classe Router gère le routage de l'application + * Les routes sont définies dans APP_PATH.'/configuration/routes.php' + */ +class Router { + const ROUTES_PATH_NAME = '/configuration/routes.php'; + + private $routes = array (); + + /** + * Constructeur + * @exception FileNotExistException si ROUTES_PATH_NAME n'existe pas + * et que l'on utilise l'url rewriting + */ + public function __construct () { + if (Configuration::useUrlRewriting ()) { + if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) { + $routes = include ( + APP_PATH . self::ROUTES_PATH_NAME + ); + + if (!is_array ($routes)) { + $routes = array (); + } + + $this->routes = array_map ( + array ('Url', 'checkUrl'), + $routes + ); + } else { + throw new FileNotExistException ( + self::ROUTES_PATH_NAME, + MinzException::ERROR + ); + } + } + } + + /** + * Initialise le Router en déterminant le couple Controller / Action + * Mets à jour la Request + * @exception RouteNotFoundException si l'uri n'est pas présente dans + * > la table de routage + */ + public function init () { + $url = array (); + + if (Configuration::useUrlRewriting ()) { + try { + $url = $this->buildWithRewriting (); + } catch (RouteNotFoundException $e) { + throw $e; + } + } else { + $url = $this->buildWithoutRewriting (); + } + + $url['params'] = array_merge ( + $url['params'], + Request::fetchPOST () + ); + + Request::forward ($url); + } + + /** + * Retourne un tableau représentant l'url passée par la barre d'adresses + * Ne se base PAS sur la table de routage + * @return tableau représentant l'url + */ + public function buildWithoutRewriting () { + $url = array (); + + $url['c'] = Request::fetchGET ( + 'c', + Request::defaultControllerName () + ); + $url['a'] = Request::fetchGET ( + 'a', + Request::defaultActionName () + ); + $url['params'] = Request::fetchGET (); + + // post-traitement + unset ($url['params']['c']); + unset ($url['params']['a']); + + return $url; + } + + /** + * Retourne un tableau représentant l'url passée par la barre d'adresses + * Se base sur la table de routage + * @return tableau représentant l'url + * @exception RouteNotFoundException si l'uri n'est pas présente dans + * > la table de routage + */ + public function buildWithRewriting () { + $url = array (); + $uri = Request::getURI (); + $find = false; + + foreach ($this->routes as $route) { + $regex = '*^' . $route['route'] . '$*'; + if (preg_match ($regex, $uri, $matches)) { + $url['c'] = $route['controller']; + $url['a'] = $route['action']; + $url['params'] = $this->getParams ( + $route['params'], + $matches + ); + $find = true; + break; + } + } + + if (!$find && $uri != '/') { + throw new RouteNotFoundException ( + $uri, + MinzException::ERROR + ); + } + + // post-traitement + $url = Url::checkUrl ($url); + + return $url; + } + + /** + * Retourne l'uri d'une url en se basant sur la table de routage + * @param l'url sous forme de tableau + * @return l'uri formatée (string) selon une route trouvée + */ + public function printUriRewrited ($url) { + $route = $this->searchRoute ($url); + + if ($route !== false) { + return $this->replaceParams ($route, $url['params']); + } + + return ''; + } + + /** + * Recherche la route correspondante à une url + * @param l'url sous forme de tableau + * @return la route telle que spécifiée dans la table de routage, + * false si pas trouvée + */ + public function searchRoute ($url) { + foreach ($this->routes as $route) { + if ($route['controller'] == $url['c'] + && $route['action'] == $url['a']) { + // calcule la différence des tableaux de params + $params = array_flip ($route['params']); + $difference_params = array_diff_key ( + $params, + $url['params'] + ); + + // vérifie que pas de différence + // et le cas où $params est vide et pas $url['params'] + if (empty ($difference_params) + && (!empty ($params) || empty ($url['params']))) { + return $route; + } + } + } + + return false; + } + + /** + * Récupère un tableau dont + * - les clés sont définies dans $params_route + * - les valeurs sont situées dans $matches + * Le tableau $matches est décalé de +1 par rapport à $params_route + */ + private function getParams($params_route, $matches) { + $params = array (); + + for ($i = 0; $i < count ($params_route); $i++) { + $param = $params_route[$i]; + $params[$param] = $matches[$i + 1]; + } + + return $params; + } + + /** + * Remplace les éléments de la route par les valeurs contenues dans $params + */ + private function replaceParams ($route, $params_replace) { + $uri = $route['route']; + $params = array(); + foreach($route['params'] as $param) { + $uri = preg_replace('#\((.+)\)#U', $params_replace[$param], $uri, 1); + } + + return stripslashes($uri); + } +} diff --git a/lib/minz/Session.php b/lib/minz/Session.php new file mode 100755 index 000000000..f9c9c6754 --- /dev/null +++ b/lib/minz/Session.php @@ -0,0 +1,78 @@ + + */ + +/** + * La classe Translate se charge de la traduction + * Utilise les fichiers du répertoire /app/i18n/ + */ +class 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 = Configuration::language (); + self::$language = 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; + } +} diff --git a/lib/minz/Url.php b/lib/minz/Url.php new file mode 100755 index 000000000..c1c3e9a0f --- /dev/null +++ b/lib/minz/Url.php @@ -0,0 +1,130 @@ +printUriRewrited ($url); + } else { + $url_string .= self::printUri ($url, $encodage); + } + } else { + $url_string .= $url; + } + + return $url_string; + } + + /** + * Construit l'URI d'une URL sans url rewriting + * @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'] != Request::defaultControllerName ()) { + $uri .= $separator . 'c=' . $url['c']; + $separator = $and; + } + + if (isset ($url['a']) + && $url['a'] != 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'] = Request::defaultControllerName (); + } + if (!isset ($url['a'])) { + $url_checked['a'] = 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 Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); +} diff --git a/lib/minz/View.php b/lib/minz/View.php new file mode 100755 index 000000000..5c329c159 --- /dev/null +++ b/lib/minz/View.php @@ -0,0 +1,232 @@ + +*/ + +/** + * La classe View représente la vue de l'application + */ +class View { + const VIEWS_PATH_NAME = '/views'; + const LAYOUT_PATH_NAME = '/layout'; + const LAYOUT_FILENAME = '/layout.phtml'; + + private $view_filename = ''; + private $use_layout = false; + + 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->view_filename = APP_PATH + . self::VIEWS_PATH_NAME . '/' + . Request::controllerName () . '/' + . Request::actionName () . '.phtml'; + + if (file_exists (APP_PATH + . self::LAYOUT_PATH_NAME + . self::LAYOUT_FILENAME)) { + $this->use_layout = true; + } + + self::$title = Configuration::title (); + } + + /** + * Construit la vue + */ + public function build () { + 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 (file_exists ($this->view_filename)) { + include ($this->view_filename); + } else { + Log::record ('File doesn\'t exist : `' + . $this->view_filename . '`', + Log::WARNING); + } + } + + /** + * 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 (file_exists ($fic_partial)) { + include ($fic_partial); + } else { + Log::record ('File doesn\'t exist : `' + . $fic_partial . '`', + 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 (file_exists ($fic_helper)) { + include ($fic_helper); + } else { + Log::record ('File doesn\'t exist : `' + . $fic_helper . '`', + Log::WARNING); + } + } + + /** + * 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 '' . self::$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 .= ''; + } + + $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 .= ''; + } + + $scripts .= "\n"; + } + + return $scripts; + } + public static function prependScript ($url, $cond = false) { + array_unshift(self::$scripts, array ( + 'url' => $url, + 'cond' => $cond + )); + } + public static function appendScript ($url, $cond = false) { + self::$scripts[] = array ( + 'url' => $url, + 'cond' => $cond + ); + } + + /** + * Gestion des paramètres ajoutés à la vue + */ + public static function _param ($key, $value) { + self::$params[$key] = $value; + } + public function attributeParams () { + foreach (View::$params as $key => $value) { + $this->$key = $value; + } + } +} + + diff --git a/lib/minz/dao/Model_array.php b/lib/minz/dao/Model_array.php new file mode 100755 index 000000000..0b9ccf071 --- /dev/null +++ b/lib/minz/dao/Model_array.php @@ -0,0 +1,122 @@ + +*/ + +/** + * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php + */ +class Model_array extends Model_txt { + /** + * $array Le tableau php contenu dans le fichier $nameFile + */ + protected $array = array (); + + /** + * Ouvre le fichier indiqué, charge le tableau dans $array et le $nameFile + * @param $nameFile le nom du fichier à ouvrir contenant un tableau + * Remarque : $array sera obligatoirement un tableau + */ + public function __construct ($nameFile) { + parent::__construct ($nameFile); + + if (!$this->getLock ('read')) { + throw new PermissionDeniedException ($this->filename); + } else { + $this->array = include ($this->filename); + $this->releaseLock (); + + if (!is_array ($this->array)) { + $this->array = array (); + } + + $this->array = $this->decodeArray ($this->array); + } + } + + /** + * Écrit un tableau dans le fichier $nameFile + * @param $array le tableau php à enregistrer + **/ + public function writeFile ($array) { + if (!$this->getLock ('write')) { + throw new PermissionDeniedException ($this->namefile); + } else { + $this->erase (); + + $this->writeLine ('writeLine ('return ', false); + $this->writeArray ($array); + $this->writeLine (';'); + + $this->releaseLock (); + } + } + + private function writeArray ($array, $profondeur = 0) { + $tab = ''; + for ($i = 0; $i < $profondeur; $i++) { + $tab .= "\t"; + } + $this->writeLine ('array ('); + + foreach ($array as $key => $value) { + if (is_int ($key)) { + $this->writeLine ($tab . "\t" . $key . ' => ', false); + } else { + $this->writeLine ($tab . "\t" . '\'' . $key . '\'' . ' => ', false); + } + + if (is_array ($value)) { + $this->writeArray ($value, $profondeur + 1); + $this->writeLine (','); + } else { + if (is_numeric ($value)) { + $this->writeLine ($value . ','); + } else { + $this->writeLine ('\'' . addslashes ($value) . '\','); + } + } + } + + $this->writeLine ($tab . ')', false); + } + + private function decodeArray ($array) { + $new_array = array (); + + foreach ($array as $key => $value) { + if (is_array ($value)) { + $new_array[$key] = $this->decodeArray ($value); + } else { + $new_array[$key] = stripslashes ($value); + } + } + + return $new_array; + } + + private function getLock ($type) { + if ($type == 'write') { + $lock = LOCK_EX; + } else { + $lock = LOCK_SH; + } + + $count = 1; + while (!flock ($this->file, $lock) && $count <= 50) { + $count++; + } + + if ($count >= 50) { + return false; + } else { + return true; + } + } + + private function releaseLock () { + flock ($this->file, LOCK_UN); + } +} diff --git a/lib/minz/dao/Model_pdo.php b/lib/minz/dao/Model_pdo.php new file mode 100755 index 000000000..6114de127 --- /dev/null +++ b/lib/minz/dao/Model_pdo.php @@ -0,0 +1,39 @@ + +*/ + +/** + * 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 Model_pdo { + /** + * $bd variable représentant la base de données + */ + protected $bd; + + /** + * 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 ($type = 'mysql') { + $db = Configuration::dataBase (); + try { + $string = $type + . ':host=' . $db['host'] + . ';dbname=' . $db['base']; + $this->bd = new PDO ( + $string, + $db['user'], + $db['password'] + ); + } catch (Exception $e) { + throw new PDOConnectionException ( + $string, + $db['user'], MinzException::WARNING + ); + } + } +} diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php new file mode 100755 index 000000000..ad15c8b36 --- /dev/null +++ b/lib/minz/dao/Model_txt.php @@ -0,0 +1,77 @@ + +*/ + +/** + * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte + */ +class Model_txt { + /** + * $file représente le fichier à ouvrir + */ + protected $file; + + /** + * $filename est le nom du fichier + */ + protected $filename; + + /** + * Ouvre un fichier dans $file + * @param $nameFile nom du fichier à ouvrir + * @param $mode mode d'ouverture du fichier ('a+' par défaut) + * @exception FileNotExistException si le fichier n'existe pas + * > ou ne peux pas être ouvert + */ + public function __construct ($nameFile, $mode = 'a+') { + $this->filename = $nameFile; + $this->file = fopen ($this->filename, $mode); + + if (!$this->file) { + throw new FileNotExistException ( + $this->filename, + MinzException::WARNING + ); + } + } + + /** + * Lit une ligne de $file + * @return une ligne du fichier + */ + public function readLine () { + return fgets ($this->file); + } + + /** + * Écrit une ligne dans $file + * @param $line la ligne à écrire + */ + public function writeLine ($line, $newLine = true) { + $char = ''; + if ($newLine) { + $char = "\n"; + } + + fwrite ($this->file, $line . $char); + } + + /** + * Efface le fichier $file + * @return true en cas de succès, false sinon + */ + public function erase () { + return ftruncate ($this->file, 0); + } + + /** + * Ferme $file + */ + public function __destruct () { + if (isset ($this->file)) { + fclose ($this->file); + } + } +} diff --git a/lib/minz/exceptions/MinzException.php b/lib/minz/exceptions/MinzException.php new file mode 100644 index 000000000..8fca5ec16 --- /dev/null +++ b/lib/minz/exceptions/MinzException.php @@ -0,0 +1,94 @@ +route = $route; + + $message = 'Route `' . $route . '` not found'; + + parent::__construct ($message, $code); + } + + public function route () { + return $this->route; + } +} +class PDOConnectionException extends MinzException { + public function __construct ($string_connection, $user, $code = self::ERROR) { + $message = 'Access to database is denied for `' . $user . '`' + . ' (`' . $string_connection . '`)'; + + parent::__construct ($message, $code); + } +} +class CurrentPagePaginationException extends MinzException { + public function __construct ($page) { + $message = 'Page number `' . $page . '` doesn\'t exist'; + + parent::__construct ($message, self::ERROR); + } +} -- cgit v1.2.3 From e5637cb1ed2ff0e284eea0bae32f2e7135c89716 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Jun 2013 13:10:39 +0200 Subject: Fix issue #88 : possibilité d'importer (OPML) des flux sans catégorie MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/lib_rss.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 77d3ac2db..772003089 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -68,6 +68,9 @@ function opml_import ($xml) { throw new OpmlException (); } + $catDAO = new CategoryDAO(); + $defCat = $catDAO->getDefault(); + $categories = array (); $feeds = array (); @@ -99,8 +102,8 @@ function opml_import ($xml) { $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ())); } } else { - // Flux rss - $feeds[] = getFeed ($outline, ''); + // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut + $feeds[] = getFeed ($outline, $defCat->id()); } } -- cgit v1.2.3 From 6d184ad1b8b84ab31e342f539844e0dc5738423b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Jun 2013 14:46:37 +0200 Subject: Fix issue #89 : meilleure vérification des champs de formulaires (géré par Minz) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/RSSConfiguration.php | 4 ++-- lib/minz/Request.php | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/app/models/RSSConfiguration.php b/app/models/RSSConfiguration.php index 50dbd2555..6ebc30e8e 100755 --- a/app/models/RSSConfiguration.php +++ b/app/models/RSSConfiguration.php @@ -85,7 +85,7 @@ class RSSConfiguration extends Model { $this->language = $value; } public function _postsPerPage ($value) { - if (is_int (intval ($value))) { + if (is_int (intval ($value)) && $value > 0) { $this->posts_per_page = $value; } else { $this->posts_per_page = 10; @@ -120,7 +120,7 @@ class RSSConfiguration extends Model { } } public function _oldEntries ($value) { - if (is_int (intval ($value))) { + if (is_int (intval ($value)) && $value > 0) { $this->old_entries = $value; } else { $this->old_entries = 3; diff --git a/lib/minz/Request.php b/lib/minz/Request.php index 507630b84..3463686bc 100644 --- a/lib/minz/Request.php +++ b/lib/minz/Request.php @@ -31,7 +31,12 @@ class Request { } public static function param ($key, $default = false) { if (isset (self::$params[$key])) { - return self::$params[$key]; + $p = self::$params[$key]; + if(is_array($p)) { + return array_map(htmlspecialchars, $p); + } else { + return htmlspecialchars($p); + } } else { return $default; } -- cgit v1.2.3 From 1863153b966af00078869b6634df1daa22cdcbfe Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Jun 2013 15:55:44 +0200 Subject: Fix issue #71 : remise en place du mode endless + correction bug à l'importation OPML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/feedController.php | 4 ++-- app/controllers/indexController.php | 1 + app/views/helpers/pagination.phtml | 2 +- lib/minz/Request.php | 8 +++++--- public/scripts/endless_mode.js | 31 +++++++++++++++++++++++++++++++ public/theme/freshrss.css | 4 ++++ public/theme/loader.gif | Bin 0 -> 4167 bytes 7 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 public/scripts/endless_mode.js create mode 100644 public/theme/loader.gif (limited to 'lib') diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index a41d7a33f..76da41c58 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -219,8 +219,8 @@ class feedController extends ActionController { $entryDAO = new EntryDAO (); $feedDAO = new FeedDAO (); - $categories = Request::param ('categories', array ()); - $feeds = Request::param ('feeds', array ()); + $categories = Request::param ('categories', array (), true); + $feeds = Request::param ('feeds', array (), true); // on ajoute les catégories en masse dans une fonction à part $this->addCategories ($categories); diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index f4f0b98b3..5403b82ed 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -12,6 +12,7 @@ class indexController extends ActionController { View::appendScript (Url::display ('/scripts/shortcut.js')); View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'main'))); View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'actualize'))); + View::appendScript (Url::display ('/scripts/endless_mode.js')); } $entryDAO = new EntryDAO (); diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index f029f281a..80c0976ad 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -8,7 +8,7 @@
  • next != '') { ?> next; ?> - + diff --git a/lib/minz/Request.php b/lib/minz/Request.php index 3463686bc..bd5fcb95e 100644 --- a/lib/minz/Request.php +++ b/lib/minz/Request.php @@ -29,11 +29,13 @@ class Request { public static function params () { return self::$params; } - public static function param ($key, $default = false) { + public static function param ($key, $default = false, $specialchars = false) { if (isset (self::$params[$key])) { $p = self::$params[$key]; - if(is_array($p)) { - return array_map(htmlspecialchars, $p); + if(is_object($p) || $specialchars) { + return $p; + } elseif(is_array($p)) { + return array_map('htmlspecialchars', $p); } else { return htmlspecialchars($p); } diff --git a/public/scripts/endless_mode.js b/public/scripts/endless_mode.js new file mode 100644 index 000000000..489b69f30 --- /dev/null +++ b/public/scripts/endless_mode.js @@ -0,0 +1,31 @@ +var url_load_more = ""; +var load = false; + +function init_load_more() { + url_load_more = $("a#load_more").attr("href"); + + $("#load_more").click (function () { + load_more_posts (); + + return false; + }); +} + +function load_more_posts () { + load = true; + $("#load_more").addClass("loading"); + $.get (url_load_more, function (data) { + $("#stream .flux:last").after($("#stream .flux", data)); + $(".pagination").html($(".pagination", data).html()); + + init_load_more(); + init_posts(); + + $("#load_more").removeClass("loading"); + load = false; + }); +} + +$(document).ready (function () { + init_load_more(); +}); \ No newline at end of file diff --git a/public/theme/freshrss.css b/public/theme/freshrss.css index 2a8f24ea7..f5d4f6a83 100644 --- a/public/theme/freshrss.css +++ b/public/theme/freshrss.css @@ -357,6 +357,10 @@ color: #333; font-style: italic; } +.loading { + background: url("loader.gif") center center no-repeat; + font-size: 0; +} /*** NOTIFICATION ***/ .notification { diff --git a/public/theme/loader.gif b/public/theme/loader.gif new file mode 100644 index 000000000..5ff26f0e3 Binary files /dev/null and b/public/theme/loader.gif differ -- cgit v1.2.3 From fafddf2a20748cdbda1f974338528c8e488f4b11 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Jun 2013 16:42:50 +0200 Subject: Fix issue #73 : ajout d'une page pour visualiser les logs --- app/App_FrontController.php | 1 + app/controllers/indexController.php | 26 ++++++++++++++++++ app/i18n/en.php | 3 +++ app/i18n/fr.php | 3 +++ app/layout/header.phtml | 1 + app/models/Log.php | 47 +++++++++++++++++++++++++++++++++ app/views/helpers/logs_pagination.phtml | 47 +++++++++++++++++++++++++++++++++ app/views/index/logs.phtml | 21 +++++++++++++++ lib/minz/View.php | 2 +- lib/minz/dao/Model_txt.php | 2 +- public/theme/freshrss.css | 44 +++++++++++++++++++++++++++++- 11 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 app/models/Log.php create mode 100755 app/views/helpers/logs_pagination.phtml create mode 100644 app/views/index/logs.phtml (limited to 'lib') diff --git a/app/App_FrontController.php b/app/App_FrontController.php index 5729a115d..637d61206 100644 --- a/app/App_FrontController.php +++ b/app/App_FrontController.php @@ -36,6 +36,7 @@ class App_FrontController extends FrontController { include (APP_PATH . '/models/Entry.php'); include (APP_PATH . '/models/EntriesGetter.php'); include (APP_PATH . '/models/RSSPaginator.php'); + include (APP_PATH . '/models/Log.php'); } private function loadParamsView () { diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index 5403b82ed..3f10720c2 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -139,6 +139,32 @@ class indexController extends ActionController { View::prependTitle (Translate::t ('about') . ' - '); } + public function logsAction () { + if (login_is_conf ($this->view->conf) && !is_logged ()) { + Error::error ( + 403, + array ('error' => array (Translate::t ('access_denied'))) + ); + } + + View::prependTitle (Translate::t ('see_logs') . ' - '); + + $logs = array(); + try { + $logDAO = new LogDAO (); + $logs = $logDAO->lister (); + $logs = array_reverse ($logs); + } catch(FileNotExistException $e) { + + } + + //gestion pagination + $page = Request::param ('page', 1); + $this->view->logsPaginator = new Paginator ($logs); + $this->view->logsPaginator->_nbItemsPerPage (50); + $this->view->logsPaginator->_currentPage ($page); + } + public function loginAction () { $this->view->_useLayout (false); diff --git a/app/i18n/en.php b/app/i18n/en.php index 0d0ab5269..dbb6b1bfe 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -186,6 +186,9 @@ return array ( 'credits' => 'Credits', 'credits_content' => 'Some design elements come from Bootstrap although FreshRSS doesn\'t use this framework. Icons come from GNOME project. Open Sans font police used has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', + 'logs' => 'Logs', + 'logs_empty' => 'Log file is empty', + // DATE 'january' => 'january', 'february' => 'february', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 97e36f923..75a76cc7a 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -186,6 +186,9 @@ return array ( 'credits' => 'Crédits', 'credits_content' => 'Des éléments de design sont issus du projet Bootstrap bien que FreshRSS n\'utilise pas ce framework. Les icônes sont issues du projet GNOME. La police Open Sans utilisée a été créée par Steve Matteson. Les favicons sont récupérés grâce au site getFavicon. FreshRSS repose sur Minz, un framework PHP.', + 'logs' => 'Logs', + 'logs_empty' => 'Les logs sont vides', + // DATE 'january' => 'janvier', 'february' => 'février', diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 2e84f7f4d..4131f8687 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -54,6 +54,7 @@
  • +
  • diff --git a/app/models/Log.php b/app/models/Log.php new file mode 100644 index 000000000..5c280fa7a --- /dev/null +++ b/app/models/Log.php @@ -0,0 +1,47 @@ +date; + } + public function level () { + return $this->level; + } + public function info () { + return $this->information; + } + public function _date ($date) { + $this->date = $date; + } + public function _level ($level) { + $this->level = $level; + } + public function _info ($information) { + $this->information = $information; + } +} + +class LogDAO extends Model_txt { + public function __construct () { + parent::__construct (LOG_PATH . '/application.log', 'r+'); + } + + public function lister () { + $logs = array (); + + $i = 0; + while (($line = $this->readLine ()) !== false) { + $logs[$i] = new Log_Model (); + $logs[$i]->_date (preg_replace ("'\[(.*?)\] \[(.*?)\] --- (.*?)'U", "\\1", $line)); + $logs[$i]->_level (preg_replace ("'\[(.*?)\] \[(.*?)\] --- (.*?)'U", "\\2", $line)); + $logs[$i]->_info (preg_replace ("'\[(.*?)\] \[(.*?)\] --- (.*?)'U", "\\3", $line)); + $i++; + } + + return $logs; + } +} \ No newline at end of file diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml new file mode 100755 index 000000000..0088dabc6 --- /dev/null +++ b/app/views/helpers/logs_pagination.phtml @@ -0,0 +1,47 @@ + + +nbPage > 1) { ?> +
      + +
    • + currentPage > 1) { ?> + « Début + +
    • + + currentPage - 1; ?> +
    • + currentPage > 1) { ?> + ‹ Précédent + +
    • + + currentPage - 2; $i <= $this->currentPage + 2; $i++) { ?> + 0 && $i <= $this->nbPage) { ?> + currentPage) { ?> + +
    • + +
    • + + + + + currentPage + 1; ?> +
    • + currentPage < $this->nbPage) { ?> + Suivant › + +
    • + nbPage; ?> +
    • + currentPage < $this->nbPage) { ?> + Fin » + +
    • +
    + diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml new file mode 100644 index 000000000..c72a84c86 --- /dev/null +++ b/app/views/index/logs.phtml @@ -0,0 +1,21 @@ +
    + + +

    + + logsPaginator->items (); ?> + + +
    + logsPaginator->render ('logs_pagination.phtml', 'page'); ?> + + +
    date ())); ?>info (); ?>
    + + + logsPaginator->render ('logs_pagination.phtml','page'); ?> +
    + +

    + +
    \ No newline at end of file diff --git a/lib/minz/View.php b/lib/minz/View.php index 5c329c159..2bb747aa9 100755 --- a/lib/minz/View.php +++ b/lib/minz/View.php @@ -71,7 +71,7 @@ class View { } else { Log::record ('File doesn\'t exist : `' . $this->view_filename . '`', - Log::WARNING); + Log::NOTICE); } } diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php index ad15c8b36..c9d5cfe77 100755 --- a/lib/minz/dao/Model_txt.php +++ b/lib/minz/dao/Model_txt.php @@ -27,7 +27,7 @@ class Model_txt { */ public function __construct ($nameFile, $mode = 'a+') { $this->filename = $nameFile; - $this->file = fopen ($this->filename, $mode); + $this->file = @fopen ($this->filename, $mode); if (!$this->file) { throw new FileNotExistException ( diff --git a/public/theme/freshrss.css b/public/theme/freshrss.css index f5d4f6a83..4919639af 100644 --- a/public/theme/freshrss.css +++ b/public/theme/freshrss.css @@ -349,14 +349,29 @@ } .pagination .item { display: table-cell; - border-top: 1px solid #aaa; line-height: 40px; } + .pagination .item.pager-current { + font-weight: bold; + font-size: 140%; + } + .pagination .item.pager-first, + .pagination .item.pager-previous, + .pagination .item.pager-next, + .pagination .item.pager-last { + width: 100px; + } .pagination .item a { display: block; color: #333; font-style: italic; } + .pagination:first-child .item { + border-bottom: 1px solid #aaa; + } + .pagination:last-child .item { + border-top: 1px solid #aaa; + } .loading { background: url("loader.gif") center center no-repeat; font-size: 0; @@ -421,6 +436,33 @@ vertical-align: middle; } +.logs { + border: 1px solid #aaa; +} + .logs .log { + padding: 5px 2%; + overflow: auto; + background: #fafafa; + border-bottom: 1px solid #999; + color: #333; + font-size: 90%; + } + .logs .log .date { + display: block; + } + .logs .log.error { + background: #fdd; + color: #844; + } + .logs .log.warning { + background: #ffe; + color: #c95; + } + .logs .log.notice { + background: #f4f4f4; + color: #aaa; + } + @media(max-width: 840px) { .header, .aside .btn-important, -- cgit v1.2.3 From d3078fb726639eed478a2a449b0a9043af04a756 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Jun 2013 19:42:02 +0200 Subject: Mise en place de la structure pour les différentes vues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/i18n/en.php | 3 + app/i18n/fr.php | 3 + app/layout/nav_menu.phtml | 67 +++++++++++++------ app/views/helpers/global_view.phtml | 5 ++ app/views/helpers/normal_view.phtml | 114 ++++++++++++++++++++++++++++++++ app/views/helpers/reader_view.phtml | 5 ++ app/views/helpers/rss.phtml | 30 --------- app/views/helpers/rss_view.phtml | 30 +++++++++ app/views/index/index.phtml | 128 ++---------------------------------- lib/lib_text.php | 8 +++ public/theme/freshrss.css | 7 +- 11 files changed, 228 insertions(+), 172 deletions(-) create mode 100644 app/views/helpers/global_view.phtml create mode 100644 app/views/helpers/normal_view.phtml create mode 100644 app/views/helpers/reader_view.phtml delete mode 100755 app/views/helpers/rss.phtml create mode 100755 app/views/helpers/rss_view.phtml (limited to 'lib') diff --git a/app/i18n/en.php b/app/i18n/en.php index e40be045a..4dbfde715 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -37,6 +37,9 @@ return array ( 'before_one_day' => 'Before one day', 'before_one_week' => 'Before one week', 'display' => 'Display', + 'normal_view' => 'Normal view', + 'reader_view' => 'Reading view', + 'global_view' => 'Global view', 'show_all_articles' => 'Show all articles', 'show_not_reads' => 'Show only unread', 'older_first' => 'Oldest first', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 69c7a8ffe..7a58b984c 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -37,6 +37,9 @@ return array ( 'before_one_day' => 'Antérieurs à 1 jour', 'before_one_week' => 'Antérieurs à 1 semaine', 'display' => 'Affichage', + 'normal_view' => 'Vue normale', + 'reader_view' => 'Vue lecture', + 'global_view' => 'Vue globale', 'show_all_articles' => 'Afficher tous les articles', 'show_not_reads' => 'Afficher les non lus', 'older_first' => 'Plus anciens en premier', diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 3411f344b..dbe597985 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -59,43 +59,72 @@ diff --git a/app/views/helpers/global_view.phtml b/app/views/helpers/global_view.phtml new file mode 100644 index 000000000..b666fe620 --- /dev/null +++ b/app/views/helpers/global_view.phtml @@ -0,0 +1,5 @@ +partial ('nav_menu'); +?> + +Non implémenté \ No newline at end of file diff --git a/app/views/helpers/normal_view.phtml b/app/views/helpers/normal_view.phtml new file mode 100644 index 000000000..515084047 --- /dev/null +++ b/app/views/helpers/normal_view.phtml @@ -0,0 +1,114 @@ +partial ('aside_flux'); +$this->partial ('nav_menu'); + +if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { + $items = $this->entryPaginator->items (); +?> + +
    + + + + isDay (Days::TODAY)) { ?> +
    -
    + + isDay (Days::YESTERDAY)) { ?> +
    -
    + + isDay (Days::BEFORE_YESTERDAY)) { ?> +
    + + +
    +
      + conf) || is_logged ()) { ?> +
    • + isRead ()) { ?> +   + +   + + + isFavorite ()) { ?> +   + +   + +
    • + + feed (true); ?> +
    • name (); ?>
    • +
    • title (); ?>
    • +
    • date (); ?>
    • + +
    + +
    +
    +

    title (); ?>

    + author (); ?> + ' . Translate::t ('by_author', $author) . '
    ' : ''; ?> + conf->lazyload() == 'yes') { + echo lazyimg($item->content ()); + } else { + echo $item->content(); + } + ?> +
    + +
      +
    • + +
    • + tags(); ?> + +
    • + +
    • + +
    +
    +
    + + + entryPaginator->render ('pagination.phtml', 'next'); ?> + + + +
    + +
    + \ No newline at end of file diff --git a/app/views/helpers/reader_view.phtml b/app/views/helpers/reader_view.phtml new file mode 100644 index 000000000..b666fe620 --- /dev/null +++ b/app/views/helpers/reader_view.phtml @@ -0,0 +1,5 @@ +partial ('nav_menu'); +?> + +Non implémenté \ No newline at end of file diff --git a/app/views/helpers/rss.phtml b/app/views/helpers/rss.phtml deleted file mode 100755 index 83de6de2e..000000000 --- a/app/views/helpers/rss.phtml +++ /dev/null @@ -1,30 +0,0 @@ -'; ?> - - - <?php echo View::title(); ?> - - - - GMT - -entryPaginator->items (); -foreach ($items as $item) { -?> - - <?php echo htmlspecialchars(html_entity_decode($item->title ())); ?> - link (); ?> - author (); ?> - - - - content (); -?>]]> - date (true)); ?> - id (); ?> - - - - - diff --git a/app/views/helpers/rss_view.phtml b/app/views/helpers/rss_view.phtml new file mode 100755 index 000000000..83de6de2e --- /dev/null +++ b/app/views/helpers/rss_view.phtml @@ -0,0 +1,30 @@ +'; ?> + + + <?php echo View::title(); ?> + + + + GMT + +entryPaginator->items (); +foreach ($items as $item) { +?> + + <?php echo htmlspecialchars(html_entity_decode($item->title ())); ?> + link (); ?> + author (); ?> + + + + content (); +?>]]> + date (true)); ?> + id (); ?> + + + + + diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 30df591eb..46ff33b3a 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,127 +1,13 @@ /i', - '', - $content - ); -} $output = Request::param ('output', 'normal'); if ($output == 'rss') { - $this->renderHelper ('rss'); + $this->renderHelper ('rss_view'); +} elseif($output == 'reader') { + $this->renderHelper ('reader_view'); +} elseif($output == 'global') { + $this->renderHelper ('global_view'); } else { - $this->partial ('aside_flux'); - $this->partial ('nav_menu'); - - if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { - $items = $this->entryPaginator->items (); -?> - -
    - - - - isDay (Days::TODAY)) { ?> -
    -
    - - isDay (Days::YESTERDAY)) { ?> -
    -
    - - isDay (Days::BEFORE_YESTERDAY)) { ?> -
    - - -
    -
      - conf) || is_logged ()) { ?> -
    • - isRead ()) { ?> -   - -   - - - isFavorite ()) { ?> -   - -   - -
    • - - feed (true); ?> -
    • name (); ?>
    • -
    • title (); ?>
    • -
    • date (); ?>
    • - -
    - -
    -
    -

    title (); ?>

    - author (); ?> - ' . Translate::t ('by_author', $author) . '
    ' : ''; ?> - conf->lazyload() == 'yes') { - echo lazyimg($item->content ()); - } else { - echo $item->content(); - } - ?> -
    - -
      -
    • - -
    • - tags(); ?> - -
    • - -
    • - -
    -
    -
    - - - entryPaginator->render ('pagination.phtml', 'next'); ?> - - - -
    - -
    - - + $this->renderHelper ('normal_view'); +} \ No newline at end of file diff --git a/lib/lib_text.php b/lib/lib_text.php index 6e8f7b2bf..9792e191e 100644 --- a/lib/lib_text.php +++ b/lib/lib_text.php @@ -86,3 +86,11 @@ function parse_tags ($desc) { return $desc_parse; } + +function lazyimg($content) { + return preg_replace( + '//i', + '', + $content + ); +} \ No newline at end of file diff --git a/public/theme/freshrss.css b/public/theme/freshrss.css index 636f9e09d..26bb21d8f 100644 --- a/public/theme/freshrss.css +++ b/public/theme/freshrss.css @@ -245,11 +245,10 @@ line-height: 40px; } .flux_header .item.website .favicon { - padding: 12px; + padding: 5px; } .flux_header .item.website a { display: block; - padding: 0; height: 40px; } .flux_header .item.title { @@ -293,6 +292,7 @@ padding: 20px 10px; line-height: 170%; font-family: 'OpenSans'; + word-wrap: break-word; } .content .title { margin: 0 0 5px; @@ -480,6 +480,9 @@ width: 40px; text-align: center; } + .flux_header .item.website .favicon { + padding: 12px; + } .content { font-size: 120%; -- cgit v1.2.3