From 97c3c7575a586382ea87f8faa1e9e78afb64710a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Nov 2013 19:45:48 +0100 Subject: Suppression des warnings liés à filemtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ajout de "@" pour éviter les warnings, touch.txt sera créé un peu plus tard --- app/App_FrontController.php | 10 +++++----- app/controllers/indexController.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/App_FrontController.php b/app/App_FrontController.php index 82499ada3..5569d73a3 100644 --- a/app/App_FrontController.php +++ b/app/App_FrontController.php @@ -54,18 +54,18 @@ class App_FrontController extends FrontController { $theme = RSSThemes::get_infos($this->conf->theme()); if ($theme) { foreach($theme["files"] as $file) { - View::appendStyle (Url::display ('/themes/' . $theme['path'] . '/' . $file . '?' . filemtime(PUBLIC_PATH . '/themes/' . $theme['path'] . '/' . $file))); + View::appendStyle (Url::display ('/themes/' . $theme['path'] . '/' . $file . '?' . @filemtime(PUBLIC_PATH . '/themes/' . $theme['path'] . '/' . $file))); } } - View::appendStyle (Url::display ('/themes/printer/style.css?' . filemtime(PUBLIC_PATH . '/themes/printer/style.css')), 'print'); + View::appendStyle (Url::display ('/themes/printer/style.css?' . @filemtime(PUBLIC_PATH . '/themes/printer/style.css')), 'print'); if (login_is_conf ($this->conf)) { View::appendScript ('https://login.persona.org/include.js'); } - View::appendScript (Url::display ('/scripts/jquery.min.js?' . filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); + View::appendScript (Url::display ('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); if ($this->conf->lazyload () === 'yes' && ($this->conf->displayPosts () === 'yes' || Request::param ('output') === 'reader')) { - View::appendScript (Url::display ('/scripts/jquery.lazyload.min.js?' . filemtime(PUBLIC_PATH . '/scripts/jquery.lazyload.min.js'))); + View::appendScript (Url::display ('/scripts/jquery.lazyload.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.lazyload.min.js'))); } - View::appendScript (Url::display ('/scripts/main.js?' . filemtime(PUBLIC_PATH . '/scripts/main.js'))); + View::appendScript (Url::display ('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); } private function loadNotifications () { diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index ee40ff9d2..2f86034ee 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -49,10 +49,10 @@ class indexController extends ActionController { Request::_param ('output', $output); } - View::appendScript (Url::display ('/scripts/shortcut.js?' . filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); + View::appendScript (Url::display ('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); if ($output == 'global') { - View::appendScript (Url::display ('/scripts/global_view.js?' . filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); + View::appendScript (Url::display ('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); } } -- cgit v1.2.3 From a4fc7becb8553198d132633d775989c89c8116cd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 11 Nov 2013 17:40:28 +0100 Subject: Décode les entités HTML en conservant les entités XML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit N'ayant pas trouvé comment régler SimplePie pour ne pas avoir d'entités HTML comme `é`, voici un patch qui les décode en sortie de SimplePie tout en conservant les entités XML comme `&`. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/247 --- app/models/Feed.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/models/Feed.php b/app/models/Feed.php index 7f53d7be8..41750d43e 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -241,12 +241,22 @@ class Feed extends Model { } } } + static function html_only_entity_decode($text) { + static $htmlEntitiesOnly = null; + if ($htmlEntitiesOnly === null) { + $htmlEntitiesOnly = array_flip(array_diff( + get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES, 'UTF-8'), //Decode HTML entities + get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES, 'UTF-8') //Preserve XML entities + )); + } + return strtr($text, $htmlEntitiesOnly); + } private function loadEntries ($feed) { $entries = array (); foreach ($feed->get_items () as $item) { - $title = strip_tags($item->get_title ()); - $author = $item->get_author (); + $title = self::html_only_entity_decode (strip_tags ($item->get_title ())); + $author = self::html_only_entity_decode ($item->get_author ()); $link = $item->get_permalink (); $date = strtotime ($item->get_date ()); @@ -255,11 +265,12 @@ class Feed extends Model { $tags = array (); if (!is_null ($tags_tmp)) { foreach ($tags_tmp as $tag) { - $tags[] = $tag->get_label (); + $tags[] = self::html_only_entity_decode ($tag->get_label ()); } } - $content = $item->get_content (); + $content = self::html_only_entity_decode ($item->get_content ()); + $elinks = array(); foreach ($item->get_enclosures() as $enclosure) { $elink = $enclosure->get_link(); -- cgit v1.2.3 From a664b85372770155e2d9c4b500194f050a0c1685 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 11 Nov 2013 17:53:22 +0100 Subject: Remplace entité nbsp par son équivalent Unicode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chasse aux entités ! Nous devrions maintenant avoir des pages sans entités HTML (mais bien sûr des entités XML) ni depuis FreshRSS ni depuis le contenu. --- app/layout/aside_feed.phtml | 2 +- app/layout/aside_flux.phtml | 2 +- app/layout/header.phtml | 2 +- app/layout/nav_menu.phtml | 4 ++-- app/views/configure/display.phtml | 8 ++++---- app/views/helpers/view/normal_view.phtml | 20 ++++++++++---------- 6 files changed, 19 insertions(+), 19 deletions(-) (limited to 'app') diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 1f60e3ada..3cfce61c5 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -9,7 +9,7 @@ diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index 408cfca1b..d4983a32e 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -1,25 +1,25 @@
  • nextId)) { ?> nextId; ?> - + -
    +

    - +
    -
    +
  • diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index ac17d608a..bc6e24e37 100644 --- a/app/views/helpers/view/global_view.phtml +++ b/app/views/helpers/view/global_view.phtml @@ -32,5 +32,5 @@
    conf->displayPosts () === 'no' ? ' class="hide_posts"' : ''; ?>> - +
    \ No newline at end of file diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 1a7efa58f..094017957 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -24,23 +24,23 @@ if (!empty($this->entries)) { ?> entries as $item) { ?> - isDay (Days::TODAY)) { ?> + isDay (FreshRSS_Days::TODAY)) { ?>
    - + - currentName; ?>
    - isDay (Days::YESTERDAY)) { ?> + isDay (FreshRSS_Days::YESTERDAY)) { ?>
    - + - currentName; ?>
    - isDay (Days::BEFORE_YESTERDAY)) { ?> + isDay (FreshRSS_Days::BEFORE_YESTERDAY)) { ?>
    - + currentName; ?>
    @@ -51,13 +51,13 @@ if (!empty($this->entries)) { if ($this->conf->toplineRead ()) { ?>
  • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
  • conf->toplineFavorite ()) { ?>
  • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
  • entries)) {
  • ✇ name(); ?>
  • title (); ?>
  • conf->toplineDate ()) { ?>
  • date (); ?> 
  • - conf->toplineLink ()) { ?> + conf->toplineLink ()) { ?>
@@ -75,7 +75,7 @@ if (!empty($this->entries)) {

title (); ?>

author (); - echo $author != '' ? '
' . Translate::t ('by_author', $author) . '
' : ''; + echo $author != '' ? '
' . Minz_Translate::t ('by_author', $author) . '
' : ''; if($this->conf->lazyload() == 'yes') { echo lazyimg($item->content ()); } else { @@ -83,19 +83,18 @@ if (!empty($this->entries)) { } ?>
-
    conf) || is_logged ()) { if ($this->conf->bottomlineRead ()) { ?>
  • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
  • conf->bottomlineFavorite ()) { ?>
  • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
  • @@ -111,8 +110,8 @@ if (!empty($this->entries)) { @@ -204,6 +203,6 @@ if (!empty($this->entries)) {
    - +
    \ No newline at end of file diff --git a/app/views/helpers/view/reader_view.phtml b/app/views/helpers/view/reader_view.phtml index 30226af42..29b2be04c 100644 --- a/app/views/helpers/view/reader_view.phtml +++ b/app/views/helpers/view/reader_view.phtml @@ -21,7 +21,7 @@ if (!empty($this->entries)) {
    author (); ?> - + date (); ?>
    @@ -42,6 +42,6 @@ if (!empty($this->entries)) {
    - +
    \ No newline at end of file diff --git a/app/views/helpers/view/rss_view.phtml b/app/views/helpers/view/rss_view.phtml index 460146dc0..620bf1388 100755 --- a/app/views/helpers/view/rss_view.phtml +++ b/app/views/helpers/view/rss_view.phtml @@ -2,11 +2,11 @@ <?php echo $this->rss_title; ?> - - rss_title); ?> + + rss_title); ?> GMT - + entries as $item) { ?> diff --git a/app/views/index/about.phtml b/app/views/index/about.phtml index fa799154b..b5c00a1ed 100644 --- a/app/views/index/about.phtml +++ b/app/views/index/about.phtml @@ -1,24 +1,24 @@
    - + -

    +

    -
    +
    -
    -
    Marien Fressinaud -
    +
    +
    Marien Fressinaud -
    -
    -
    +
    +
    -
    -
    +
    +
    -

    +

    -

    -

    +

    +

    diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index bd18d2d77..cf98060c4 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,8 +1,8 @@ conf->token(); -$token_param = Request::param ('token', ''); +$token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); if(!login_is_conf ($this->conf) || @@ -21,9 +21,9 @@ if(!login_is_conf ($this->conf) || } else { ?>
    -

    -

    -

    +

    +

    +

    - + -

    +

    - +

    logsPaginator->items (); ?> @@ -20,6 +20,6 @@ logsPaginator->render ('logs_pagination.phtml','page'); ?> -

    +

    diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index f39540a9a..69689133c 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,12 +1,12 @@ var feeds = new Array (); feeds as $feed) { ?> -feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); +feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); function initProgressBar (init) { if (init) { $("body").after ("\
    \ - 0 / " + feeds.length + "
    \ + 0 / " + feeds.length + "
    \ \
    "); } else { 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 @@ + +*/ + +/** + * La classe Cache permet de gérer facilement les pages en cache + */ +class Minz_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 (Minz_Request::getURI ()); + + $this->file = CACHE_PATH . '/'.$file; + } + + public function _expire () { + if ($this->exist ()) { + $this->expire = filemtime ($this->file) + + Minz_Configuration::delayCache (); + } + } + + /** + * Permet de savoir si le cache est activé + * @return true si activé, false sinon + */ + public static function isEnabled () { + return Minz_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/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 @@ + +*/ + +/** + * 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 (is_null ($file_name)) { + $file_name = LOG_PATH . '/application.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'; + } + + if ($env == Minz_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 { + 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); + } +} diff --git a/lib/Minz/ModelArray.php b/lib/Minz/ModelArray.php new file mode 100644 index 000000000..4ba022143 --- /dev/null +++ b/lib/Minz/ModelArray.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 Minz_ModelArray extends Minz_ModelTxt { + /** + * $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 Minz_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 Minz_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/ModelPdo.php b/lib/Minz/ModelPdo.php new file mode 100644 index 000000000..9655539b2 --- /dev/null +++ b/lib/Minz/ModelPdo.php @@ -0,0 +1,111 @@ + +*/ + +/** + * 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; + + /** + * $bd variable représentant la base de données + */ + protected $bd; + + protected $prefix; + + /** + * 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 () { + if (self::$useSharedBd && self::$sharedBd != null) { + $this->bd = self::$sharedBd; + $this->prefix = self::$sharedPrefix; + return; + } + + $db = Minz_Configuration::dataBase (); + $driver_options = null; + + try { + $type = $db['type']; + if($type == 'mysql') { + $string = $type + . ':host=' . $db['host'] + . ';dbname=' . $db['base'] + . ';charset=utf8'; + $driver_options = array( + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' + ); + } elseif($type == 'sqlite') { + $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 + } + + $this->bd = new FreshPDO ( + $string, + $db['user'], + $db['password'], + $driver_options + ); + self::$sharedBd = $this->bd; + + $userPrefix = Minz_Configuration::currentUser (); + $this->prefix = $db['prefix'] . (empty($userPrefix) ? '' : ($userPrefix . '_')); + self::$sharedPrefix = $this->prefix; + } 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 function size() { + $db = Minz_Configuration::dataBase (); + $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; + $stm = $this->bd->prepare ($sql); + $values = array ($db['base']); + $stm->execute ($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } +} + +class FreshPDO extends PDO { + private static function check($statement) { + if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { + invalidateHttpCache(); + } + } + + public function prepare ($statement, $driver_options = array()) { + FreshPDO::check($statement); + return parent::prepare($statement, $driver_options); + } + + public function exec ($statement) { + FreshPDO::check($statement); + return parent::exec($statement); + } +} diff --git a/lib/Minz/ModelTxt.php b/lib/Minz/ModelTxt.php new file mode 100644 index 000000000..8c5973f4d --- /dev/null +++ b/lib/Minz/ModelTxt.php @@ -0,0 +1,84 @@ + +*/ + +/** + * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte + */ +class Minz_ModelTxt { + /** + * $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; + if (!file_exists($this->filename)) { + throw new Minz_FileNotExistException ( + $this->filename, + Minz_Exception::WARNING + ); + } + + $this->file = @fopen ($this->filename, $mode); + + if (!$this->file) { + throw new Minz_PermissionDeniedException ( + $this->filename, + Minz_Exception::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/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 @@ +route = $route; + + $message = 'Route `' . $route . '` not found'; + + parent::__construct ($message, $code); + } + + public function route () { + return $this->route; + } +} diff --git a/lib/SimplePie_autoloader.php b/lib/SimplePie_autoloader.php deleted file mode 100644 index 3f67635b0..000000000 --- a/lib/SimplePie_autoloader.php +++ /dev/null @@ -1,86 +0,0 @@ -path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'SimplePie'; - } - - /** - * Autoloader - * - * @param string $class The name of the class to attempt to load. - */ - public function autoload($class) - { - // Only load the class if it starts with "SimplePie" - if (strpos($class, 'SimplePie') !== 0) - { - return; - } - - $filename = $this->path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; - include $filename; - } -} diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 4f5b90b61..2fdfd4bd8 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -15,6 +15,31 @@ if (!function_exists('json_encode')) { } } +// +function classAutoloader($class) { + if (strpos($class, 'FreshRSS') === 0) { + $components = explode('_', $class); + switch (count($components)) { + case 1: + include(APP_PATH . '/' . $components[0] . '.php'); + return; + case 2: + include(APP_PATH . '/Models/' . $components[1] . '.php'); + return; + case 3: //Controllers, Exceptions + include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php'); + return; + } + } elseif (strpos($class, 'Minz') === 0) { + include(LIB_PATH . '/' . str_replace('_', '/', $class) . '.php'); + } elseif (strpos($class, 'SimplePie') === 0) { + include(LIB_PATH . '/SimplePie/' . str_replace('_', '/', $class) . '.php'); + } +} + +spl_autoload_register('classAutoloader'); +// + function checkUrl($url) { if (empty ($url)) { return ''; @@ -33,7 +58,7 @@ function checkUrl($url) { // vérifie qu'on est connecté function is_logged () { - return Session::param ('mail') != false; + return Minz_Session::param ('mail') != false; } // vérifie que le système d'authentification est configuré @@ -63,11 +88,11 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { } function timestamptodate ($t, $hour = true) { - $month = Translate::t (date('M', $t)); + $month = Minz_Translate::t (date('M', $t)); if ($hour) { - $date = Translate::t ('format_date_hour', $month); + $date = Minz_Translate::t ('format_date_hour', $month); } else { - $date = Translate::t ('format_date', $month); + $date = Minz_Translate::t ('format_date', $month); } return @date ($date, $t); @@ -123,10 +148,10 @@ function opml_import ($xml) { $opml = simplexml_import_dom($dom); if (!$opml) { - throw new OpmlException (); + throw new FreshRSS_Opml_Exception (); } - $catDAO = new CategoryDAO(); + $catDAO = new FreshRSS_CategoryDAO(); $catDAO->checkDefault(); $defCat = $catDAO->getDefault(); @@ -152,10 +177,10 @@ function opml_import ($xml) { // Y ne sera pas ajouté et le flux non plus vu que l'id // de sa catégorie n'exisera pas $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $cat = $catDAO->searchByName ($title); if ($cat === false) { - $cat = new Category ($title); + $cat = new FreshRSS_Category ($title); $values = array ( 'name' => $cat->name (), 'color' => $cat->color () @@ -204,7 +229,7 @@ function getFeed ($outline, $cat_id) { $title = (string) $outline['title']; } $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); - $feed = new Feed ($url); + $feed = new FreshRSS_Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); if (isset($outline['htmlUrl'])) { @@ -250,7 +275,7 @@ function get_content_by_parsing ($url, $path) { function lazyimg($content) { return preg_replace( '/]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', - '', + '', $content ); } diff --git a/lib/minz/ActionController.php b/lib/minz/ActionController.php index ab9389dbd..409d9611f 100755 --- a/lib/minz/ActionController.php +++ b/lib/minz/ActionController.php @@ -7,7 +7,7 @@ /** * La classe ActionController représente le contrôleur de l'application */ -class ActionController { +class Minz_ActionController { protected $router; protected $view; @@ -18,7 +18,7 @@ class ActionController { */ public function __construct ($router) { $this->router = $router; - $this->view = new View (); + $this->view = new Minz_View (); $this->view->attributeParams (); } diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php index 7d6e3743e..9fc913964 100755 --- a/lib/minz/Configuration.php +++ b/lib/minz/Configuration.php @@ -7,7 +7,7 @@ /** * La classe Configuration permet de gérer la configuration de l'application */ -class Configuration { +class Minz_Configuration { const CONF_PATH_NAME = '/application.ini'; /** @@ -43,7 +43,7 @@ class Configuration { * - base le nom de la base de données */ private static $sel_application = ''; - private static $environment = Configuration::PRODUCTION; + private static $environment = Minz_Configuration::PRODUCTION; private static $base_url = ''; private static $use_url_rewriting = false; private static $title = ''; @@ -99,30 +99,30 @@ class Configuration { /** * Initialise les variables de configuration - * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + * @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 (FileNotExistException $e) { + } catch (Minz_FileNotExistException $e) { throw $e; - } catch (BadConfigurationException $e) { + } catch (Minz_BadConfigurationException $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é + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté */ private static function parseFile () { if (!file_exists (DATA_PATH . self::CONF_PATH_NAME)) { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( DATA_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } @@ -132,17 +132,17 @@ class Configuration { ); if (!$ini_array) { - throw new PermissionDeniedException ( + throw new Minz_PermissionDeniedException ( DATA_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } // [general] est obligatoire if (!isset ($ini_array['general'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( '[general]', - MinzException::ERROR + Minz_Exception::ERROR ); } $general = $ini_array['general']; @@ -150,9 +150,9 @@ class Configuration { // sel_application est obligatoire if (!isset ($general['sel_application'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'sel_application', - MinzException::ERROR + Minz_Exception::ERROR ); } self::$sel_application = $general['sel_application']; @@ -160,18 +160,18 @@ class Configuration { if (isset ($general['environment'])) { switch ($general['environment']) { case 'silent': - self::$environment = Configuration::SILENT; + self::$environment = Minz_Configuration::SILENT; break; case 'development': - self::$environment = Configuration::DEVELOPMENT; + self::$environment = Minz_Configuration::DEVELOPMENT; break; case 'production': - self::$environment = Configuration::PRODUCTION; + self::$environment = Minz_Configuration::PRODUCTION; break; default: - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'environment', - MinzException::ERROR + Minz_Exception::ERROR ); } @@ -194,7 +194,7 @@ class Configuration { if (CACHE_PATH === false && self::$cache_enabled) { throw new FileNotExistException ( 'CACHE_PATH', - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -213,27 +213,27 @@ class Configuration { } if ($db) { if (!isset ($db['host'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'host', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['user'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'user', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['password'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'password', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['base'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'base', - MinzException::ERROR + Minz_Exception::ERROR ); } diff --git a/lib/minz/Dispatcher.php b/lib/minz/Dispatcher.php index 0cfdd8e75..2898b5f00 100644 --- a/lib/minz/Dispatcher.php +++ b/lib/minz/Dispatcher.php @@ -9,8 +9,8 @@ * déterminée dans la Request * C'est un singleton */ -class Dispatcher { - const CONTROLLERS_PATH_NAME = '/controllers'; +class Minz_Dispatcher { + const CONTROLLERS_PATH_NAME = '/Controllers'; /* singleton */ private static $instance = null; @@ -23,7 +23,7 @@ class Dispatcher { */ public static function getInstance ($router) { if (is_null (self::$instance)) { - self::$instance = new Dispatcher ($router); + self::$instance = new Minz_Dispatcher ($router); } return self::$instance; } @@ -38,7 +38,7 @@ class Dispatcher { /** * Lance le controller indiqué dans Request * Remplit le body de Response à partir de la Vue - * @exception MinzException + * @exception Minz_Exception */ public function run () { $cache = new Minz_Cache(); @@ -53,29 +53,25 @@ class Dispatcher { $cache->render (); $text = ob_get_clean(); } else { - while (Request::$reseted) { - Request::$reseted = false; + while (Minz_Request::$reseted) { + Minz_Request::$reseted = false; try { - $this->createController ( - Request::controllerName () - . 'Controller' - ); - + $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); $this->controller->init (); $this->controller->firstAction (); $this->launchAction ( - Request::actionName () + Minz_Request::actionName () . 'Action' ); $this->controller->lastAction (); - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { ob_start (); $this->controller->view ()->build (); $text = ob_get_clean(); } - } catch (MinzException $e) { + } catch (Minz_Exception $e) { throw $e; } } @@ -85,14 +81,12 @@ class Dispatcher { } } - Response::setBody ($text); + Minz_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 @@ -101,26 +95,18 @@ class Dispatcher { $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 ( + throw new Minz_ControllerNotExistException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } $this->controller = new $controller_name ($this->router); - if (! ($this->controller instanceof ActionController)) { - throw new ControllerNotActionControllerException ( + if (! ($this->controller instanceof Minz_ActionController)) { + throw new Minz_ControllerNotActionControllerException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -129,18 +115,18 @@ class Dispatcher { * 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 + * le controller */ private function launchAction ($action_name) { - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { if (!is_callable (array ( $this->controller, $action_name ))) { - throw new ActionException ( + throw new Minz_ActionException ( get_class ($this->controller), $action_name, - MinzException::ERROR + Minz_Exception::ERROR ); } call_user_func (array ( diff --git a/lib/minz/Error.php b/lib/minz/Error.php index 0e8c2f60b..1ad0d313c 100755 --- a/lib/minz/Error.php +++ b/lib/minz/Error.php @@ -1,5 +1,5 @@ */ @@ -7,7 +7,7 @@ /** * La classe Error permet de lancer des erreurs HTTP */ -class Error { +class Minz_Error { public function __construct () { } /** @@ -21,28 +21,28 @@ class Error { */ public static function error ($code = 404, $logs = array (), $redirect = false) { $logs = self::processLogs ($logs); - $error_filename = APP_PATH . '/controllers/errorController.php'; - + $error_filename = APP_PATH . '/Controllers/ErrorController.php'; + if (file_exists ($error_filename)) { $params = array ( 'code' => $code, 'logs' => $logs ); - - Response::setHeader ($code); + + Minz_Response::setHeader ($code); if ($redirect) { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error' ), true); } else { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error', 'params' => $params ), false); } } else { $text = '

    An error occured

    '."\n"; - + if (!empty ($logs)) { $text .= '
      '."\n"; foreach ($logs as $log) { @@ -50,14 +50,14 @@ class Error { } $text .= '
    '."\n"; } - - Response::setHeader ($code); - Response::setBody ($text); - Response::send (); + + Minz_Response::setHeader ($code); + Minz_Response::setBody ($text); + Minz_Response::send (); exit (); } } - + /** * Permet de retourner les logs de façon à n'avoir que * ceux que l'on veut réellement @@ -66,12 +66,12 @@ class Error { * > en fonction de l'environment */ private static function processLogs ($logs) { - $env = Configuration::environment (); + $env = Minz_Configuration::environment (); $logs_ok = array (); $error = array (); $warning = array (); $notice = array (); - + if (isset ($logs['error'])) { $error = $logs['error']; } @@ -81,14 +81,14 @@ class Error { if (isset ($logs['notice'])) { $notice = $logs['notice']; } - - if ($env == Configuration::PRODUCTION) { + + if ($env == Minz_Configuration::PRODUCTION) { $logs_ok = $error; } - if ($env == Configuration::DEVELOPMENT) { + if ($env == Minz_Configuration::DEVELOPMENT) { $logs_ok = array_merge ($error, $warning, $notice); } - + return $logs_ok; } } diff --git a/lib/minz/FrontController.php b/lib/minz/FrontController.php index d48d43d04..eb9835fe5 100755 --- a/lib/minz/FrontController.php +++ b/lib/minz/FrontController.php @@ -2,109 +2,79 @@ # ***** 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 . # # ***** END LICENSE BLOCK ***** /** - * La classe FrontController est le noyau du framework, elle lance l'application + * 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 FrontController { +class Minz_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 (); + Minz_Configuration::init (); - Request::init (); + Minz_Request::init (); - $this->router = new Router (); + $this->router = new Minz_Router (); $this->router->init (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - Error::error ( + Minz_Error::error ( 404, array ('error' => array ($e->getMessage ())) ); - } catch (MinzException $e) { + } catch (Minz_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $this->killApp ($e->getMessage ()); } - - $this->dispatcher = Dispatcher::getInstance ($this->router); - } - - /** - * Inclue les fichiers de la librairie - */ - private function loadLib () { - require ('ActionController.php'); - require ('Minz_Cache.php'); - require ('Configuration.php'); - require ('Dispatcher.php'); - require ('Error.php'); - require ('Helper.php'); - require ('Minz_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'); + + $this->dispatcher = Minz_Dispatcher::getInstance ($this->router); } - + /** * Démarre l'application (lance le dispatcher et renvoie la réponse */ public function run () { try { $this->dispatcher->run (); - Response::send (); - } catch (MinzException $e) { + Minz_Response::send (); + } catch (Minz_Exception $e) { try { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - } catch (PermissionDeniedException $e) { + } catch (Minz_PermissionDeniedException $e) { $this->killApp ($e->getMessage ()); } - if ($e instanceof FileNotExistException || - $e instanceof ControllerNotExistException || - $e instanceof ControllerNotActionControllerException || - $e instanceof ActionException) { - Error::error ( + 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 @@ -114,7 +84,7 @@ class FrontController { } } } - + /** * Permet d'arrêter le programme en urgence */ diff --git a/lib/minz/Helper.php b/lib/minz/Helper.php index 4f64ba218..b058211d3 100755 --- a/lib/minz/Helper.php +++ b/lib/minz/Helper.php @@ -7,7 +7,7 @@ /** * La classe Helper représente une aide pour des tâches récurrentes */ -class Helper { +class Minz_Helper { /** * Annule les effets des magic_quotes pour une variable donnée * @param $var variable à traiter (tableau ou simple variable) diff --git a/lib/minz/Minz_Cache.php b/lib/minz/Minz_Cache.php deleted file mode 100644 index 6848e3350..000000000 --- a/lib/minz/Minz_Cache.php +++ /dev/null @@ -1,116 +0,0 @@ - -*/ - -/** - * La classe Cache permet de gérer facilement les pages en cache - */ -class Minz_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/Minz_Log.php b/lib/minz/Minz_Log.php deleted file mode 100644 index 12005aa88..000000000 --- a/lib/minz/Minz_Log.php +++ /dev/null @@ -1,94 +0,0 @@ - -*/ - -/** - * 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 = Configuration::environment (); - - if (! ($env === Configuration::SILENT - || ($env === Configuration::PRODUCTION - && ($level >= Minz_Log::NOTICE)))) { - if (is_null ($file_name)) { - $file_name = LOG_PATH . '/application.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'; - } - - 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 { - throw new PermissionDeniedException ( - $file_name, - MinzException::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); - } -} diff --git a/lib/minz/Model.php b/lib/minz/Model.php index 37fc19ed1..adbaba942 100755 --- a/lib/minz/Model.php +++ b/lib/minz/Model.php @@ -7,6 +7,6 @@ /** * La classe Model représente un modèle de l'application (représentation MVC) */ -class Model { +class Minz_Model { } diff --git a/lib/minz/Paginator.php b/lib/minz/Paginator.php index 1a8376e75..5858e76a5 100755 --- a/lib/minz/Paginator.php +++ b/lib/minz/Paginator.php @@ -7,7 +7,7 @@ /** * La classe Paginator permet de gérer la pagination de l'application facilement */ -class Paginator { +class Minz_Paginator { /** * $items tableau des éléments à afficher/gérer */ diff --git a/lib/minz/Request.php b/lib/minz/Request.php index 3e508d8f1..c8ffa4a42 100644 --- a/lib/minz/Request.php +++ b/lib/minz/Request.php @@ -7,7 +7,7 @@ /** * Request représente la requête http */ -class Request { +class Minz_Request { private static $controller_name = ''; private static $action_name = ''; private static $params = array (); @@ -96,7 +96,7 @@ class Request { * @return la base de l'url */ public static function getBaseUrl () { - return Configuration::baseUrl (); + return Minz_Configuration::baseUrl (); } /** @@ -124,10 +124,10 @@ class Request { * > sinon, le dispatcher recharge en interne */ public static function forward ($url = array (), $redirect = false) { - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); if ($redirect) { - header ('Location: ' . Url::display ($url, 'php')); + header ('Location: ' . Minz_Url::display ($url, 'php')); exit (); } else { self::$reseted = true; @@ -185,9 +185,9 @@ class Request { */ private static function magicQuotesOff () { if (get_magic_quotes_gpc ()) { - $_GET = Helper::stripslashes_r ($_GET); - $_POST = Helper::stripslashes_r ($_POST); - $_COOKIE = Helper::stripslashes_r ($_COOKIE); + $_GET = Minz_Helper::stripslashes_r ($_GET); + $_POST = Minz_Helper::stripslashes_r ($_POST); + $_COOKIE = Minz_Helper::stripslashes_r ($_COOKIE); } } @@ -195,5 +195,3 @@ class Request { return !empty ($_POST) || !empty ($_FILES); } } - - diff --git a/lib/minz/Response.php b/lib/minz/Response.php index fcf53c5b1..f8ea3d946 100644 --- a/lib/minz/Response.php +++ b/lib/minz/Response.php @@ -7,7 +7,7 @@ /** * Response représente la requête http renvoyée à l'utilisateur */ -class Response { +class Minz_Response { private static $header = 'HTTP/1.0 200 OK'; private static $body = ''; diff --git a/lib/minz/Router.php b/lib/minz/Router.php index c5d6f5baa..1ccd72597 100755 --- a/lib/minz/Router.php +++ b/lib/minz/Router.php @@ -8,7 +8,7 @@ * La classe Router gère le routage de l'application * Les routes sont définies dans APP_PATH.'/configuration/routes.php' */ -class Router { +class Minz_Router { const ROUTES_PATH_NAME = '/configuration/routes.php'; private $routes = array (); @@ -19,7 +19,7 @@ class Router { * et que l'on utilise l'url rewriting */ public function __construct () { - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) { $routes = include ( APP_PATH . self::ROUTES_PATH_NAME @@ -34,9 +34,9 @@ class Router { $routes ); } else { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( self::ROUTES_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -51,10 +51,10 @@ class Router { public function init () { $url = array (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { try { $url = $this->buildWithRewriting (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { throw $e; } } else { @@ -63,10 +63,10 @@ class Router { $url['params'] = array_merge ( $url['params'], - Request::fetchPOST () + Minz_Request::fetchPOST () ); - Request::forward ($url); + Minz_Request::forward ($url); } /** @@ -77,15 +77,15 @@ class Router { public function buildWithoutRewriting () { $url = array (); - $url['c'] = Request::fetchGET ( + $url['c'] = Minz_Request::fetchGET ( 'c', - Request::defaultControllerName () + Minz_Request::defaultControllerName () ); - $url['a'] = Request::fetchGET ( + $url['a'] = Minz_Request::fetchGET ( 'a', - Request::defaultActionName () + Minz_Request::defaultActionName () ); - $url['params'] = Request::fetchGET (); + $url['params'] = Minz_Request::fetchGET (); // post-traitement unset ($url['params']['c']); @@ -103,7 +103,7 @@ class Router { */ public function buildWithRewriting () { $url = array (); - $uri = Request::getURI (); + $uri = Minz_Request::getURI (); $find = false; foreach ($this->routes as $route) { @@ -121,14 +121,14 @@ class Router { } if (!$find && $uri != '/') { - throw new RouteNotFoundException ( + throw new Minz_RouteNotFoundException ( $uri, - MinzException::ERROR + Minz_Exception::ERROR ); } // post-traitement - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); return $url; } diff --git a/lib/minz/Session.php b/lib/minz/Session.php index f9c9c6754..878caa556 100755 --- a/lib/minz/Session.php +++ b/lib/minz/Session.php @@ -4,7 +4,7 @@ * La classe Session gère la session utilisateur * C'est un singleton */ -class Session { +class Minz_Session { /** * $session stocke les variables de session */ @@ -15,7 +15,7 @@ class Session { */ public static function init () { // démarre la session - session_name (md5 (Configuration::selApplication ())); + session_name (md5 (Minz_Configuration::selApplication ())); session_start (); if (isset ($_SESSION)) { @@ -55,7 +55,7 @@ class Session { if($p == 'language') { // reset pour remettre à jour le fichier de langue à utiliser - Translate::reset (); + Minz_Translate::reset (); } } } diff --git a/lib/minz/Translate.php b/lib/minz/Translate.php index e8cbe4852..e14f783f7 100644 --- a/lib/minz/Translate.php +++ b/lib/minz/Translate.php @@ -8,7 +8,7 @@ * La classe Translate se charge de la traduction * Utilise les fichiers du répertoire /app/i18n/ */ -class Translate { +class Minz_Translate { /** * $language est la langue à afficher */ @@ -25,8 +25,8 @@ class Translate { * l'enregistre dans $translates */ public static function init () { - $l = Configuration::language (); - self::$language = Session::param ('language', $l); + $l = Minz_Configuration::language (); + self::$language = Minz_Session::param ('language', $l); $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; diff --git a/lib/minz/Url.php b/lib/minz/Url.php index ce051ebd9..30f7f6231 100755 --- a/lib/minz/Url.php +++ b/lib/minz/Url.php @@ -3,7 +3,7 @@ /** * La classe Url permet de gérer les URL à travers MINZ */ -class Url { +class Minz_Url { /** * Affiche une Url formatée selon que l'on utilise l'url_rewriting ou non * si oui, on cherche dans la table de routage la correspondance pour formater @@ -29,16 +29,16 @@ class Url { } else { $protocol = 'http:'; } - $url_string = $protocol . '//' . Request::getDomainName () . Request::getBaseUrl (); + $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl (); } else { $url_string = '.'; } if (is_array ($url)) { - $router = new Router (); + $router = new Minz_Router (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { $url_string .= $router->printUriRewrited ($url); } else { $url_string .= self::printUri ($url, $encodage); @@ -67,13 +67,13 @@ class Url { } if (isset ($url['c']) - && $url['c'] != Request::defaultControllerName ()) { + && $url['c'] != Minz_Request::defaultControllerName ()) { $uri .= $separator . 'c=' . $url['c']; $separator = $and; } if (isset ($url['a']) - && $url['a'] != Request::defaultActionName ()) { + && $url['a'] != Minz_Request::defaultActionName ()) { $uri .= $separator . 'a=' . $url['a']; $separator = $and; } @@ -98,10 +98,10 @@ class Url { if (is_array ($url)) { if (!isset ($url['c'])) { - $url_checked['c'] = Request::defaultControllerName (); + $url_checked['c'] = Minz_Request::defaultControllerName (); } if (!isset ($url['a'])) { - $url_checked['a'] = Request::defaultActionName (); + $url_checked['a'] = Minz_Request::defaultActionName (); } if (!isset ($url['params'])) { $url_checked['params'] = array (); @@ -125,5 +125,5 @@ function _url ($controller, $action) { $params[$args[$i]] = $args[$i + 1]; } - return Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); + return Minz_Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); } diff --git a/lib/minz/View.php b/lib/minz/View.php index 12202542f..c8d0aefed 100755 --- a/lib/minz/View.php +++ b/lib/minz/View.php @@ -7,7 +7,7 @@ /** * La classe View représente la vue de l'application */ -class View { +class Minz_View { const VIEWS_PATH_NAME = '/views'; const LAYOUT_PATH_NAME = '/layout'; const LAYOUT_FILENAME = '/layout.phtml'; @@ -28,8 +28,8 @@ class View { public function __construct () { $this->view_filename = APP_PATH . self::VIEWS_PATH_NAME . '/' - . Request::controllerName () . '/' - . Request::actionName () . '.phtml'; + . Minz_Request::controllerName () . '/' + . Minz_Request::actionName () . '.phtml'; if (file_exists (APP_PATH . self::LAYOUT_PATH_NAME @@ -37,7 +37,7 @@ class View { $this->use_layout = true; } - self::$title = Configuration::title (); + self::$title = Minz_Configuration::title (); } /** @@ -232,7 +232,7 @@ class View { self::$params[$key] = $value; } public function attributeParams () { - foreach (View::$params as $key => $value) { + foreach (Minz_View::$params as $key => $value) { $this->$key = $value; } } diff --git a/lib/minz/dao/Model_array.php b/lib/minz/dao/Model_array.php deleted file mode 100755 index 0b9ccf071..000000000 --- a/lib/minz/dao/Model_array.php +++ /dev/null @@ -1,122 +0,0 @@ - -*/ - -/** - * 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 deleted file mode 100755 index a93291fc8..000000000 --- a/lib/minz/dao/Model_pdo.php +++ /dev/null @@ -1,111 +0,0 @@ - -*/ - -/** - * 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 { - - /** - * Partage la connexion à la base de données entre toutes les instances. - */ - public static $useSharedBd = true; - private static $sharedBd = null; - private static $sharedPrefix; - - /** - * $bd variable représentant la base de données - */ - protected $bd; - - protected $prefix; - - /** - * 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 () { - if (self::$useSharedBd && self::$sharedBd != null) { - $this->bd = self::$sharedBd; - $this->prefix = self::$sharedPrefix; - return; - } - - $db = Configuration::dataBase (); - $driver_options = null; - - try { - $type = $db['type']; - if($type == 'mysql') { - $string = $type - . ':host=' . $db['host'] - . ';dbname=' . $db['base'] - . ';charset=utf8'; - $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' - ); - } elseif($type == 'sqlite') { - $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 - } - - $this->bd = new FreshPDO ( - $string, - $db['user'], - $db['password'], - $driver_options - ); - self::$sharedBd = $this->bd; - - $userPrefix = Configuration::currentUser (); - $this->prefix = $db['prefix'] . (empty($userPrefix) ? '' : ($userPrefix . '_')); - self::$sharedPrefix = $this->prefix; - } catch (Exception $e) { - throw new PDOConnectionException ( - $string, - $db['user'], MinzException::ERROR - ); - } - } - - public function beginTransaction() { - $this->bd->beginTransaction(); - } - public function commit() { - $this->bd->commit(); - } - public function rollBack() { - $this->bd->rollBack(); - } - - public function size() { - $db = Configuration::dataBase (); - $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; - $stm = $this->bd->prepare ($sql); - $values = array ($db['base']); - $stm->execute ($values); - $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); - return $res[0]; - } -} - -class FreshPDO extends PDO { - private static function check($statement) { - if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { - invalidateHttpCache(); - } - } - - public function prepare ($statement, $driver_options = array()) { - FreshPDO::check($statement); - return parent::prepare($statement, $driver_options); - } - - public function exec ($statement) { - FreshPDO::check($statement); - return parent::exec($statement); - } -} diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php deleted file mode 100755 index aed653068..000000000 --- a/lib/minz/dao/Model_txt.php +++ /dev/null @@ -1,84 +0,0 @@ - -*/ - -/** - * 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; - if (!file_exists($this->filename)) { - throw new FileNotExistException ( - $this->filename, - MinzException::WARNING - ); - } - - $this->file = @fopen ($this->filename, $mode); - - if (!$this->file) { - throw new PermissionDeniedException ( - $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 deleted file mode 100644 index 4568c4da8..000000000 --- a/lib/minz/exceptions/MinzException.php +++ /dev/null @@ -1,94 +0,0 @@ -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); - } -} diff --git a/public/index.php b/public/index.php index 3a2bcd3ae..829e418f9 100755 --- a/public/index.php +++ b/public/index.php @@ -37,18 +37,10 @@ if (file_exists ('install.php')) { } } - set_include_path (get_include_path () - . PATH_SEPARATOR - . LIB_PATH - . PATH_SEPARATOR - . LIB_PATH . '/minz' - . PATH_SEPARATOR - . APP_PATH); - - require (APP_PATH . '/App_FrontController.php'); + require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader try { - $front_controller = new App_FrontController (); + $front_controller = new FreshRSS(); $front_controller->init (); $front_controller->run (); } catch (Exception $e) { -- cgit v1.2.3 From 83e8c68b6f9fc563230920ee520eae138898a2c1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 04:03:32 +0100 Subject: Refactorisation : oubli --- app/controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/controllers/configureController.php b/app/controllers/configureController.php index 0e7fbbdde..62fead315 100755 --- a/app/controllers/configureController.php +++ b/app/controllers/configureController.php @@ -249,7 +249,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Session::_param ('mail', $this->view->conf->mailLogin ()); Minz_Session::_param ('language', $this->view->conf->language ()); - Translate::reset (); + Minz_Translate::reset (); // notif $notif = array ( -- cgit v1.2.3 From 7e64cda41548500c25825cca29bb7e0167249b83 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 04:07:12 +0100 Subject: Date minimum pour afficher les articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente décision https://github.com/marienfressinaud/FreshRSS/issues/323 --- app/Models/EntryDAO.php | 7 +++++-- app/controllers/feedController.php | 6 +++--- app/controllers/indexController.php | 8 ++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 8c18150b6..b61b97624 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -259,7 +259,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return isset ($entries[0]) ? $entries[0] : false; } - public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = -1, $filter = '') { + public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { $where = ''; $values = array(); switch ($type) { @@ -299,9 +299,12 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { default: throw new FreshRSS_EntriesGetter_Exception ('Bad order in Entry->listByType: [' . $order . ']!'); } - if ($firstId > 0) { + if ($firstId !== '') { $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } + if ($date_min > 0) { + $where .= 'AND e.id >= ' . $date_min . '000000 '; + } $terms = array_unique(explode(' ', trim($filter))); sort($terms); //Put #tags first $having = ''; diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index e4014c326..a85877724 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -96,7 +96,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on calcule la date des articles les plus anciens qu'on accepte $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); $transactionStarted = true; $feedDAO->beginTransaction (); @@ -196,7 +196,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on calcule la date des articles les plus anciens qu'on accepte $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); $i = 0; $flux_update = 0; @@ -310,7 +310,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on calcule la date des articles les plus anciens qu'on accepte $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); // la variable $error permet de savoir si une erreur est survenue // Le but est de ne pas arrêter l'import même en cas d'erreur diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index 16a053ba3..92070590a 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -124,15 +124,19 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } + // on calcule la date des articles les plus anciens qu'on affiche + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + try { - $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter); + $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles if ($state === 'not_read' && empty($entries)) { //TODO: Remove in v0.8 Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; - $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter); + $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min); } if (count($entries) <= $nb) { -- cgit v1.2.3 From 74bceb2e2cdf0e3da5fb36990f3ee54e745e3d09 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 04:20:23 +0100 Subject: Date minimum : cas des favoris et de l'historique complet Suite de https://github.com/marienfressinaud/FreshRSS/issues/323 --- app/Models/EntryDAO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index b61b97624..1bce6cbf2 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -303,7 +303,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if ($date_min > 0) { - $where .= 'AND e.id >= ' . $date_min . '000000 '; + $where .= 'AND (e.id >= ' . $date_min . '000000 OR e.is_favorite = 1 OR f.keep_history = 1) '; } $terms = array_unique(explode(' ', trim($filter))); sort($terms); //Put #tags first -- cgit v1.2.3 From 02452e6a5ccf287dd3a08c3bb14c0395cab2d926 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 11:21:44 +0100 Subject: Delete Category.php --- app/models/Category.php | 85 ------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100755 app/models/Category.php (limited to 'app') diff --git a/app/models/Category.php b/app/models/Category.php deleted file mode 100755 index e70d1303f..000000000 --- a/app/models/Category.php +++ /dev/null @@ -1,85 +0,0 @@ -_name ($name); - $this->_color ($color); - if (isset ($feeds)) { - $this->_feeds ($feeds); - $this->nbFeed = 0; - $this->nbNotRead = 0; - foreach ($feeds as $feed) { - $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); - } - } - } - - public function id () { - return $this->id; - } - public function name () { - return $this->name; - } - public function color () { - return $this->color; - } - public function nbFeed () { - if ($this->nbFeed < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbFeed = $catDAO->countFeed ($this->id ()); - } - - return $this->nbFeed; - } - public function nbNotRead () { - if ($this->nbNotRead < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbNotRead = $catDAO->countNotRead ($this->id ()); - } - - return $this->nbNotRead; - } - public function feeds () { - if (is_null ($this->feeds)) { - $feedDAO = new FreshRSS_FeedDAO (); - $this->feeds = $feedDAO->listByCategory ($this->id ()); - $this->nbFeed = 0; - $this->nbNotRead = 0; - foreach ($this->feeds as $feed) { - $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); - } - } - - return $this->feeds; - } - - public function _id ($value) { - $this->id = $value; - } - public function _name ($value) { - $this->name = $value; - } - public function _color ($value) { - if (preg_match ('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) { - $this->color = $value; - } else { - $this->color = '#0062BE'; - } - } - public function _feeds ($values) { - if (!is_array ($values)) { - $values = array ($values); - } - - $this->feeds = $values; - } -} -- cgit v1.2.3 From 16c2696f2ada2c22e0ac6392bd27365f10e66004 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 11:21:49 +0100 Subject: Delete Days.php --- app/models/Days.php | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 app/models/Days.php (limited to 'app') diff --git a/app/models/Days.php b/app/models/Days.php deleted file mode 100644 index 2d770c30b..000000000 --- a/app/models/Days.php +++ /dev/null @@ -1,7 +0,0 @@ - Date: Sun, 15 Dec 2013 11:21:55 +0100 Subject: Delete Entry.php --- app/models/Entry.php | 193 --------------------------------------------------- 1 file changed, 193 deletions(-) delete mode 100755 app/models/Entry.php (limited to 'app') diff --git a/app/models/Entry.php b/app/models/Entry.php deleted file mode 100755 index ba0fb48f4..000000000 --- a/app/models/Entry.php +++ /dev/null @@ -1,193 +0,0 @@ -_guid ($guid); - $this->_title ($title); - $this->_author ($author); - $this->_content ($content); - $this->_link ($link); - $this->_date ($pubdate); - $this->_isRead ($is_read); - $this->_isFavorite ($is_favorite); - $this->_feed ($feed); - $this->_tags (preg_split('/[\s#]/', $tags)); - } - - public function id () { - return $this->id; - } - public function guid () { - return $this->guid; - } - public function title () { - return $this->title; - } - public function author () { - if (is_null ($this->author)) { - return ''; - } else { - return $this->author; - } - } - public function content () { - return $this->content; - } - public function link () { - return $this->link; - } - public function date ($raw = false) { - if ($raw) { - return $this->date; - } else { - return timestamptodate ($this->date); - } - } - public function dateAdded ($raw = false) { - $date = intval(substr($this->id, 0, -6)); - if ($raw) { - return $date; - } else { - return timestamptodate ($date); - } - } - public function isRead () { - return $this->is_read; - } - public function isFavorite () { - return $this->is_favorite; - } - public function feed ($object = false) { - if ($object) { - $feedDAO = new FreshRSS_FeedDAO (); - return $feedDAO->searchById ($this->feed); - } else { - return $this->feed; - } - } - public function tags ($inString = false) { - if ($inString) { - return empty ($this->tags) ? '' : '#' . implode(' #', $this->tags); - } else { - return $this->tags; - } - } - - public function _id ($value) { - $this->id = $value; - } - public function _guid ($value) { - $this->guid = $value; - } - public function _title ($value) { - $this->title = $value; - } - public function _author ($value) { - $this->author = $value; - } - public function _content ($value) { - $this->content = $value; - } - public function _link ($value) { - $this->link = $value; - } - public function _date ($value) { - if (ctype_digit ($value)) { - $this->date = intval ($value); - } else { - $this->date = time (); - } - } - public function _isRead ($value) { - $this->is_read = $value; - } - public function _isFavorite ($value) { - $this->is_favorite = $value; - } - public function _feed ($value) { - $this->feed = $value; - } - public function _tags ($value) { - if (!is_array ($value)) { - $value = array ($value); - } - - foreach ($value as $key => $t) { - if (!$t) { - unset ($value[$key]); - } - } - - $this->tags = $value; - } - - public function isDay ($day) { - $date = $this->dateAdded(true); - $today = @strtotime('today'); - $yesterday = $today - 86400; - - if ($day === FreshRSS_Days::TODAY && - $date >= $today && $date < $today + 86400) { - return true; - } elseif ($day === FreshRSS_Days::YESTERDAY && - $date >= $yesterday && $date < $yesterday + 86400) { - return true; - } elseif ($day === FreshRSS_Days::BEFORE_YESTERDAY && $date < $yesterday) { - return true; - } else { - return false; - } - } - - public function loadCompleteContent($pathEntries) { - // Gestion du contenu - // On cherche à récupérer les articles en entier... même si le flux ne le propose pas - if ($pathEntries) { - $entryDAO = new FreshRSS_EntryDAO(); - $entry = $entryDAO->searchByGuid($this->feed, $this->guid); - - if($entry) { - // l'article existe déjà en BDD, en se contente de recharger ce contenu - $this->content = $entry->content(); - } else { - try { - // l'article n'est pas en BDD, on va le chercher sur le site - $this->content = get_content_by_parsing( - $this->link(), $pathEntries - ); - } catch (Exception $e) { - // rien à faire, on garde l'ancien contenu (requête a échoué) - } - } - } - } - - public function toArray () { - return array ( - 'id' => $this->id (), - 'guid' => $this->guid (), - 'title' => $this->title (), - 'author' => $this->author (), - 'content' => $this->content (), - 'link' => $this->link (), - 'date' => $this->date (true), - 'is_read' => $this->isRead (), - 'is_favorite' => $this->isFavorite (), - 'id_feed' => $this->feed (), - 'tags' => $this->tags (true), - ); - } -} -- cgit v1.2.3 From a29dad13761208bfdf024e7f6703023d85428695 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 11:22:02 +0100 Subject: Delete Feed.php --- app/models/Feed.php | 319 ---------------------------------------------------- 1 file changed, 319 deletions(-) delete mode 100644 app/models/Feed.php (limited to 'app') diff --git a/app/models/Feed.php b/app/models/Feed.php deleted file mode 100644 index e63ac8c7a..000000000 --- a/app/models/Feed.php +++ /dev/null @@ -1,319 +0,0 @@ -_url ($url); - } else { - $this->url = $url; - } - } - - public function id () { - return $this->id; - } - public function url () { - return $this->url; - } - public function category () { - return $this->category; - } - public function entries () { - if (!is_null ($this->entries)) { - return $this->entries; - } else { - return array (); - } - } - public function name () { - return $this->name; - } - public function website () { - return $this->website; - } - public function description () { - return $this->description; - } - public function lastUpdate () { - return $this->lastUpdate; - } - public function priority () { - return $this->priority; - } - public function pathEntries () { - return $this->pathEntries; - } - public function httpAuth ($raw = true) { - if ($raw) { - return $this->httpAuth; - } else { - $pos_colon = strpos ($this->httpAuth, ':'); - $user = substr ($this->httpAuth, 0, $pos_colon); - $pass = substr ($this->httpAuth, $pos_colon + 1); - - return array ( - 'username' => $user, - 'password' => $pass - ); - } - } - public function inError () { - return $this->error; - } - public function keepHistory () { - return $this->keep_history; - } - public function nbEntries () { - if ($this->nbEntries < 0) { - $feedDAO = new FreshRSS_FeedDAO (); - $this->nbEntries = $feedDAO->countEntries ($this->id ()); - } - - return $this->nbEntries; - } - public function nbNotRead () { - if ($this->nbNotRead < 0) { - $feedDAO = new FreshRSS_FeedDAO (); - $this->nbNotRead = $feedDAO->countNotRead ($this->id ()); - } - - return $this->nbNotRead; - } - public function faviconPrepare() { - $file = DATA_PATH . '/favicons/' . $this->id () . '.txt'; - if (!file_exists ($file)) { - $t = $this->website; - if (empty($t)) { - $t = $this->url; - } - file_put_contents($file, $t); - } - } - public static function faviconDelete($id) { - $path = DATA_PATH . '/favicons/' . $id; - @unlink($path . '.ico'); - @unlink($path . '.txt'); - } - public function favicon () { - return Minz_Url::display ('/f.php?' . $this->id ()); - } - - public function _id ($value) { - $this->id = $value; - } - public function _url ($value, $validate=true) { - if ($validate) { - $value = checkUrl($value); - } - if (empty ($value)) { - throw new FreshRSS_BadUrl_Exception ($value); - } - $this->url = $value; - } - public function _category ($value) { - $this->category = $value; - } - public function _name ($value) { - if (is_null ($value)) { - $value = ''; - } - $this->name = $value; - } - public function _website ($value, $validate=true) { - if ($validate) { - $value = checkUrl($value); - } - if (empty ($value)) { - $value = ''; - } - $this->website = $value; - } - public function _description ($value) { - if (is_null ($value)) { - $value = ''; - } - $this->description = $value; - } - public function _lastUpdate ($value) { - $this->lastUpdate = $value; - } - public function _priority ($value) { - $this->priority = ctype_digit ($value) ? intval ($value) : 10; - } - public function _pathEntries ($value) { - $this->pathEntries = $value; - } - public function _httpAuth ($value) { - $this->httpAuth = $value; - } - public function _error ($value) { - if ($value) { - $value = true; - } else { - $value = false; - } - $this->error = $value; - } - public function _keepHistory ($value) { - if ($value) { - $value = true; - } else { - $value = false; - } - $this->keep_history = $value; - } - public function _nbNotRead ($value) { - $this->nbNotRead = ctype_digit ($value) ? intval ($value) : -1; - } - public function _nbEntries ($value) { - $this->nbEntries = ctype_digit ($value) ? intval ($value) : -1; - } - - public function load () { - if (!is_null ($this->url)) { - if (CACHE_PATH === false) { - throw new Minz_FileNotExistException ( - 'CACHE_PATH', - Minz_Exception::ERROR - ); - } else { - $feed = new SimplePie (); - $feed->set_useragent(Minz_Translate::t ('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); - $url = htmlspecialchars_decode ($this->url, ENT_QUOTES); - if ($this->httpAuth != '') { - $url = preg_replace ('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url); - } - - $feed->set_feed_url ($url); - $feed->set_cache_location (CACHE_PATH); - $feed->set_cache_duration(1500); - $feed->strip_htmltags (array ( - 'base', 'blink', 'body', 'doctype', 'embed', - 'font', 'form', 'frame', 'frameset', 'html', - 'input', 'marquee', 'meta', 'noscript', - 'object', 'param', 'plaintext', 'script', 'style', - )); - $feed->strip_attributes(array_merge($feed->strip_attributes, array( - 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', - 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', - 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); - $feed->add_attributes(array( - 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/ - 'audio' => array('preload' => 'none'), - 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), - 'video' => array('postpone' => '', 'preload' => 'none'), - )); - $feed->set_url_replacements(array( - 'a' => 'href', - 'area' => 'href', - 'audio' => 'src', - 'blockquote' => 'cite', - 'del' => 'cite', - 'form' => 'action', - 'iframe' => 'src', - 'img' => array( - 'longdesc', - 'src' - ), - 'input' => 'src', - 'ins' => 'cite', - 'q' => 'cite', - 'source' => 'src', - 'track' => 'src', - 'video' => array( - 'poster', - 'src', - ), - )); - $feed->init (); - - if ($feed->error ()) { - throw new FreshRSS_Feed_Exception ($feed->error . ' [' . $url . ']'); - } - - // si on a utilisé l'auto-discover, notre url va avoir changé - $subscribe_url = $feed->subscribe_url (); - if (!is_null ($subscribe_url) && $subscribe_url != $this->url) { - if ($this->httpAuth != '') { - // on enlève les id si authentification HTTP - $subscribe_url = preg_replace ('#((.+)://)((.+)@)(.+)#', '${1}${5}', $subscribe_url); - } - $this->_url ($subscribe_url); - } - - $title = $feed->get_title (); - $this->_name (!is_null ($title) ? $title : $this->url); - - $this->_website ($feed->get_link ()); - $this->_description ($feed->get_description ()); - - // et on charge les articles du flux - $this->loadEntries ($feed); - } - } - } - private function loadEntries ($feed) { - $entries = array (); - - foreach ($feed->get_items () as $item) { - $title = html_only_entity_decode (strip_tags ($item->get_title ())); - $author = $item->get_author (); - $link = $item->get_permalink (); - $date = @strtotime ($item->get_date ()); - - // gestion des tags (catégorie == tag) - $tags_tmp = $item->get_categories (); - $tags = array (); - if (!is_null ($tags_tmp)) { - foreach ($tags_tmp as $tag) { - $tags[] = html_only_entity_decode ($tag->get_label ()); - } - } - - $content = html_only_entity_decode ($item->get_content ()); - - $elinks = array(); - foreach ($item->get_enclosures() as $enclosure) { - $elink = $enclosure->get_link(); - if (array_key_exists($elink, $elinks)) continue; - $elinks[$elink] = '1'; - $mime = strtolower($enclosure->get_type()); - if (strpos($mime, 'image/') === 0) { - $content .= '
    '; - } - } - - $entry = new FreshRSS_Entry ( - $this->id (), - $item->get_id (), - !is_null ($title) ? $title : '', - !is_null ($author) ? html_only_entity_decode ($author->name) : '', - !is_null ($content) ? $content : '', - !is_null ($link) ? $link : '', - $date ? $date : time () - ); - $entry->_tags ($tags); - // permet de récupérer le contenu des flux tronqués - $entry->loadCompleteContent($this->pathEntries()); - - $entries[] = $entry; - } - - $this->entries = $entries; - } -} -- cgit v1.2.3 From 4ee4f16ffe06e247d2cb79a2054ab5d5315d82b2 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 11:24:14 +0100 Subject: Problème de casse renommage répertoire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/Category.php | 85 +++++++++++ app/Models/Days.php | 7 + app/Models/Entry.php | 193 +++++++++++++++++++++++++ app/Models/Feed.php | 319 ++++++++++++++++++++++++++++++++++++++++++ lib/Minz/ActionController.php | 42 ++++++ lib/Minz/Configuration.php | 262 ++++++++++++++++++++++++++++++++++ lib/Minz/Dispatcher.php | 138 ++++++++++++++++++ lib/Minz/Error.php | 94 +++++++++++++ lib/Minz/FrontController.php | 97 +++++++++++++ lib/Minz/Helper.php | 22 +++ lib/Minz/Model.php | 12 ++ lib/Minz/Paginator.php | 196 ++++++++++++++++++++++++++ lib/Minz/Request.php | 197 ++++++++++++++++++++++++++ lib/Minz/Response.php | 60 ++++++++ lib/Minz/Router.php | 209 +++++++++++++++++++++++++++ lib/Minz/Session.php | 78 +++++++++++ lib/Minz/Translate.php | 71 ++++++++++ lib/Minz/Url.php | 129 +++++++++++++++++ lib/Minz/View.php | 241 +++++++++++++++++++++++++++++++ 19 files changed, 2452 insertions(+) create mode 100644 app/Models/Category.php create mode 100644 app/Models/Days.php create mode 100644 app/Models/Entry.php create mode 100644 app/Models/Feed.php create mode 100644 lib/Minz/ActionController.php create mode 100644 lib/Minz/Configuration.php create mode 100644 lib/Minz/Dispatcher.php create mode 100644 lib/Minz/Error.php create mode 100644 lib/Minz/FrontController.php create mode 100644 lib/Minz/Helper.php create mode 100644 lib/Minz/Model.php create mode 100644 lib/Minz/Paginator.php create mode 100644 lib/Minz/Request.php create mode 100644 lib/Minz/Response.php create mode 100644 lib/Minz/Router.php create mode 100644 lib/Minz/Session.php create mode 100644 lib/Minz/Translate.php create mode 100644 lib/Minz/Url.php create mode 100644 lib/Minz/View.php (limited to 'app') diff --git a/app/Models/Category.php b/app/Models/Category.php new file mode 100644 index 000000000..e70d1303f --- /dev/null +++ b/app/Models/Category.php @@ -0,0 +1,85 @@ +_name ($name); + $this->_color ($color); + if (isset ($feeds)) { + $this->_feeds ($feeds); + $this->nbFeed = 0; + $this->nbNotRead = 0; + foreach ($feeds as $feed) { + $this->nbFeed++; + $this->nbNotRead += $feed->nbNotRead (); + } + } + } + + public function id () { + return $this->id; + } + public function name () { + return $this->name; + } + public function color () { + return $this->color; + } + public function nbFeed () { + if ($this->nbFeed < 0) { + $catDAO = new FreshRSS_CategoryDAO (); + $this->nbFeed = $catDAO->countFeed ($this->id ()); + } + + return $this->nbFeed; + } + public function nbNotRead () { + if ($this->nbNotRead < 0) { + $catDAO = new FreshRSS_CategoryDAO (); + $this->nbNotRead = $catDAO->countNotRead ($this->id ()); + } + + return $this->nbNotRead; + } + public function feeds () { + if (is_null ($this->feeds)) { + $feedDAO = new FreshRSS_FeedDAO (); + $this->feeds = $feedDAO->listByCategory ($this->id ()); + $this->nbFeed = 0; + $this->nbNotRead = 0; + foreach ($this->feeds as $feed) { + $this->nbFeed++; + $this->nbNotRead += $feed->nbNotRead (); + } + } + + return $this->feeds; + } + + public function _id ($value) { + $this->id = $value; + } + public function _name ($value) { + $this->name = $value; + } + public function _color ($value) { + if (preg_match ('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) { + $this->color = $value; + } else { + $this->color = '#0062BE'; + } + } + public function _feeds ($values) { + if (!is_array ($values)) { + $values = array ($values); + } + + $this->feeds = $values; + } +} diff --git a/app/Models/Days.php b/app/Models/Days.php new file mode 100644 index 000000000..2d770c30b --- /dev/null +++ b/app/Models/Days.php @@ -0,0 +1,7 @@ +_guid ($guid); + $this->_title ($title); + $this->_author ($author); + $this->_content ($content); + $this->_link ($link); + $this->_date ($pubdate); + $this->_isRead ($is_read); + $this->_isFavorite ($is_favorite); + $this->_feed ($feed); + $this->_tags (preg_split('/[\s#]/', $tags)); + } + + public function id () { + return $this->id; + } + public function guid () { + return $this->guid; + } + public function title () { + return $this->title; + } + public function author () { + if (is_null ($this->author)) { + return ''; + } else { + return $this->author; + } + } + public function content () { + return $this->content; + } + public function link () { + return $this->link; + } + public function date ($raw = false) { + if ($raw) { + return $this->date; + } else { + return timestamptodate ($this->date); + } + } + public function dateAdded ($raw = false) { + $date = intval(substr($this->id, 0, -6)); + if ($raw) { + return $date; + } else { + return timestamptodate ($date); + } + } + public function isRead () { + return $this->is_read; + } + public function isFavorite () { + return $this->is_favorite; + } + public function feed ($object = false) { + if ($object) { + $feedDAO = new FreshRSS_FeedDAO (); + return $feedDAO->searchById ($this->feed); + } else { + return $this->feed; + } + } + public function tags ($inString = false) { + if ($inString) { + return empty ($this->tags) ? '' : '#' . implode(' #', $this->tags); + } else { + return $this->tags; + } + } + + public function _id ($value) { + $this->id = $value; + } + public function _guid ($value) { + $this->guid = $value; + } + public function _title ($value) { + $this->title = $value; + } + public function _author ($value) { + $this->author = $value; + } + public function _content ($value) { + $this->content = $value; + } + public function _link ($value) { + $this->link = $value; + } + public function _date ($value) { + if (ctype_digit ($value)) { + $this->date = intval ($value); + } else { + $this->date = time (); + } + } + public function _isRead ($value) { + $this->is_read = $value; + } + public function _isFavorite ($value) { + $this->is_favorite = $value; + } + public function _feed ($value) { + $this->feed = $value; + } + public function _tags ($value) { + if (!is_array ($value)) { + $value = array ($value); + } + + foreach ($value as $key => $t) { + if (!$t) { + unset ($value[$key]); + } + } + + $this->tags = $value; + } + + public function isDay ($day) { + $date = $this->dateAdded(true); + $today = @strtotime('today'); + $yesterday = $today - 86400; + + if ($day === FreshRSS_Days::TODAY && + $date >= $today && $date < $today + 86400) { + return true; + } elseif ($day === FreshRSS_Days::YESTERDAY && + $date >= $yesterday && $date < $yesterday + 86400) { + return true; + } elseif ($day === FreshRSS_Days::BEFORE_YESTERDAY && $date < $yesterday) { + return true; + } else { + return false; + } + } + + public function loadCompleteContent($pathEntries) { + // Gestion du contenu + // On cherche à récupérer les articles en entier... même si le flux ne le propose pas + if ($pathEntries) { + $entryDAO = new FreshRSS_EntryDAO(); + $entry = $entryDAO->searchByGuid($this->feed, $this->guid); + + if($entry) { + // l'article existe déjà en BDD, en se contente de recharger ce contenu + $this->content = $entry->content(); + } else { + try { + // l'article n'est pas en BDD, on va le chercher sur le site + $this->content = get_content_by_parsing( + $this->link(), $pathEntries + ); + } catch (Exception $e) { + // rien à faire, on garde l'ancien contenu (requête a échoué) + } + } + } + } + + public function toArray () { + return array ( + 'id' => $this->id (), + 'guid' => $this->guid (), + 'title' => $this->title (), + 'author' => $this->author (), + 'content' => $this->content (), + 'link' => $this->link (), + 'date' => $this->date (true), + 'is_read' => $this->isRead (), + 'is_favorite' => $this->isFavorite (), + 'id_feed' => $this->feed (), + 'tags' => $this->tags (true), + ); + } +} diff --git a/app/Models/Feed.php b/app/Models/Feed.php new file mode 100644 index 000000000..e63ac8c7a --- /dev/null +++ b/app/Models/Feed.php @@ -0,0 +1,319 @@ +_url ($url); + } else { + $this->url = $url; + } + } + + public function id () { + return $this->id; + } + public function url () { + return $this->url; + } + public function category () { + return $this->category; + } + public function entries () { + if (!is_null ($this->entries)) { + return $this->entries; + } else { + return array (); + } + } + public function name () { + return $this->name; + } + public function website () { + return $this->website; + } + public function description () { + return $this->description; + } + public function lastUpdate () { + return $this->lastUpdate; + } + public function priority () { + return $this->priority; + } + public function pathEntries () { + return $this->pathEntries; + } + public function httpAuth ($raw = true) { + if ($raw) { + return $this->httpAuth; + } else { + $pos_colon = strpos ($this->httpAuth, ':'); + $user = substr ($this->httpAuth, 0, $pos_colon); + $pass = substr ($this->httpAuth, $pos_colon + 1); + + return array ( + 'username' => $user, + 'password' => $pass + ); + } + } + public function inError () { + return $this->error; + } + public function keepHistory () { + return $this->keep_history; + } + public function nbEntries () { + if ($this->nbEntries < 0) { + $feedDAO = new FreshRSS_FeedDAO (); + $this->nbEntries = $feedDAO->countEntries ($this->id ()); + } + + return $this->nbEntries; + } + public function nbNotRead () { + if ($this->nbNotRead < 0) { + $feedDAO = new FreshRSS_FeedDAO (); + $this->nbNotRead = $feedDAO->countNotRead ($this->id ()); + } + + return $this->nbNotRead; + } + public function faviconPrepare() { + $file = DATA_PATH . '/favicons/' . $this->id () . '.txt'; + if (!file_exists ($file)) { + $t = $this->website; + if (empty($t)) { + $t = $this->url; + } + file_put_contents($file, $t); + } + } + public static function faviconDelete($id) { + $path = DATA_PATH . '/favicons/' . $id; + @unlink($path . '.ico'); + @unlink($path . '.txt'); + } + public function favicon () { + return Minz_Url::display ('/f.php?' . $this->id ()); + } + + public function _id ($value) { + $this->id = $value; + } + public function _url ($value, $validate=true) { + if ($validate) { + $value = checkUrl($value); + } + if (empty ($value)) { + throw new FreshRSS_BadUrl_Exception ($value); + } + $this->url = $value; + } + public function _category ($value) { + $this->category = $value; + } + public function _name ($value) { + if (is_null ($value)) { + $value = ''; + } + $this->name = $value; + } + public function _website ($value, $validate=true) { + if ($validate) { + $value = checkUrl($value); + } + if (empty ($value)) { + $value = ''; + } + $this->website = $value; + } + public function _description ($value) { + if (is_null ($value)) { + $value = ''; + } + $this->description = $value; + } + public function _lastUpdate ($value) { + $this->lastUpdate = $value; + } + public function _priority ($value) { + $this->priority = ctype_digit ($value) ? intval ($value) : 10; + } + public function _pathEntries ($value) { + $this->pathEntries = $value; + } + public function _httpAuth ($value) { + $this->httpAuth = $value; + } + public function _error ($value) { + if ($value) { + $value = true; + } else { + $value = false; + } + $this->error = $value; + } + public function _keepHistory ($value) { + if ($value) { + $value = true; + } else { + $value = false; + } + $this->keep_history = $value; + } + public function _nbNotRead ($value) { + $this->nbNotRead = ctype_digit ($value) ? intval ($value) : -1; + } + public function _nbEntries ($value) { + $this->nbEntries = ctype_digit ($value) ? intval ($value) : -1; + } + + public function load () { + if (!is_null ($this->url)) { + if (CACHE_PATH === false) { + throw new Minz_FileNotExistException ( + 'CACHE_PATH', + Minz_Exception::ERROR + ); + } else { + $feed = new SimplePie (); + $feed->set_useragent(Minz_Translate::t ('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $url = htmlspecialchars_decode ($this->url, ENT_QUOTES); + if ($this->httpAuth != '') { + $url = preg_replace ('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url); + } + + $feed->set_feed_url ($url); + $feed->set_cache_location (CACHE_PATH); + $feed->set_cache_duration(1500); + $feed->strip_htmltags (array ( + 'base', 'blink', 'body', 'doctype', 'embed', + 'font', 'form', 'frame', 'frameset', 'html', + 'input', 'marquee', 'meta', 'noscript', + 'object', 'param', 'plaintext', 'script', 'style', + )); + $feed->strip_attributes(array_merge($feed->strip_attributes, array( + 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', + 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', + 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); + $feed->add_attributes(array( + 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/ + 'audio' => array('preload' => 'none'), + 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), + 'video' => array('postpone' => '', 'preload' => 'none'), + )); + $feed->set_url_replacements(array( + 'a' => 'href', + 'area' => 'href', + 'audio' => 'src', + 'blockquote' => 'cite', + 'del' => 'cite', + 'form' => 'action', + 'iframe' => 'src', + 'img' => array( + 'longdesc', + 'src' + ), + 'input' => 'src', + 'ins' => 'cite', + 'q' => 'cite', + 'source' => 'src', + 'track' => 'src', + 'video' => array( + 'poster', + 'src', + ), + )); + $feed->init (); + + if ($feed->error ()) { + throw new FreshRSS_Feed_Exception ($feed->error . ' [' . $url . ']'); + } + + // si on a utilisé l'auto-discover, notre url va avoir changé + $subscribe_url = $feed->subscribe_url (); + if (!is_null ($subscribe_url) && $subscribe_url != $this->url) { + if ($this->httpAuth != '') { + // on enlève les id si authentification HTTP + $subscribe_url = preg_replace ('#((.+)://)((.+)@)(.+)#', '${1}${5}', $subscribe_url); + } + $this->_url ($subscribe_url); + } + + $title = $feed->get_title (); + $this->_name (!is_null ($title) ? $title : $this->url); + + $this->_website ($feed->get_link ()); + $this->_description ($feed->get_description ()); + + // et on charge les articles du flux + $this->loadEntries ($feed); + } + } + } + private function loadEntries ($feed) { + $entries = array (); + + foreach ($feed->get_items () as $item) { + $title = html_only_entity_decode (strip_tags ($item->get_title ())); + $author = $item->get_author (); + $link = $item->get_permalink (); + $date = @strtotime ($item->get_date ()); + + // gestion des tags (catégorie == tag) + $tags_tmp = $item->get_categories (); + $tags = array (); + if (!is_null ($tags_tmp)) { + foreach ($tags_tmp as $tag) { + $tags[] = html_only_entity_decode ($tag->get_label ()); + } + } + + $content = html_only_entity_decode ($item->get_content ()); + + $elinks = array(); + foreach ($item->get_enclosures() as $enclosure) { + $elink = $enclosure->get_link(); + if (array_key_exists($elink, $elinks)) continue; + $elinks[$elink] = '1'; + $mime = strtolower($enclosure->get_type()); + if (strpos($mime, 'image/') === 0) { + $content .= '
    '; + } + } + + $entry = new FreshRSS_Entry ( + $this->id (), + $item->get_id (), + !is_null ($title) ? $title : '', + !is_null ($author) ? html_only_entity_decode ($author->name) : '', + !is_null ($content) ? $content : '', + !is_null ($link) ? $link : '', + $date ? $date : time () + ); + $entry->_tags ($tags); + // permet de récupérer le contenu des flux tronqués + $entry->loadCompleteContent($this->pathEntries()); + + $entries[] = $entry; + } + + $this->entries = $entries; + } +} diff --git a/lib/Minz/ActionController.php b/lib/Minz/ActionController.php new file mode 100644 index 000000000..409d9611f --- /dev/null +++ b/lib/Minz/ActionController.php @@ -0,0 +1,42 @@ + +*/ + +/** + * La classe ActionController représente le contrôleur de l'application + */ +class Minz_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 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/Configuration.php b/lib/Minz/Configuration.php new file mode 100644 index 000000000..9fc913964 --- /dev/null +++ b/lib/Minz/Configuration.php @@ -0,0 +1,262 @@ + +*/ + +/** + * La classe Configuration permet de gérer la configuration de l'application + */ +class Minz_Configuration { + const CONF_PATH_NAME = '/application.ini'; + + /** + * 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 + * $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 = Minz_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 $default_user = ''; + private static $current_user = ''; + + 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 stripslashes(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; + } + public static function defaultUser () { + return self::$default_user; + } + public static function currentUser () { + return self::$current_user; + } + + /** + * 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; + } + } + + /** + * Parse un fichier de configuration de type ".ini" + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + */ + private static function parseFile () { + if (!file_exists (DATA_PATH . self::CONF_PATH_NAME)) { + throw new Minz_FileNotExistException ( + DATA_PATH . self::CONF_PATH_NAME, + Minz_Exception::ERROR + ); + } + + $ini_array = parse_ini_file ( + DATA_PATH . self::CONF_PATH_NAME, + true + ); + + if (!$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']; + + + // sel_application est obligatoire + if (!isset ($general['sel_application'])) { + throw new Minz_BadConfigurationException ( + 'sel_application', + Minz_Exception::ERROR + ); + } + self::$sel_application = $general['sel_application']; + + 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: + throw new Minz_BadConfigurationException ( + 'environment', + Minz_Exception::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', + Minz_Exception::ERROR + ); + } + } + if (isset ($general['delay_cache'])) { + self::$delay_cache = $general['delay_cache']; + } + if (isset ($general['default_user'])) { + self::$default_user = $general['default_user']; + self::$current_user = self::$default_user; + } + + // Base de données + $db = false; + if (isset ($ini_array['db'])) { + $db = $ini_array['db']; + } + if ($db) { + if (!isset ($db['host'])) { + throw new Minz_BadConfigurationException ( + 'host', + Minz_Exception::ERROR + ); + } + if (!isset ($db['user'])) { + throw new Minz_BadConfigurationException ( + 'user', + Minz_Exception::ERROR + ); + } + if (!isset ($db['password'])) { + throw new Minz_BadConfigurationException ( + 'password', + Minz_Exception::ERROR + ); + } + if (!isset ($db['base'])) { + throw new Minz_BadConfigurationException ( + 'base', + Minz_Exception::ERROR + ); + } + + self::$db['type'] = isset ($db['type']) ? $db['type'] : 'mysql'; + self::$db['host'] = $db['host']; + self::$db['user'] = $db['user']; + self::$db['password'] = $db['password']; + self::$db['base'] = $db['base']; + self::$db['prefix'] = isset ($db['prefix']) ? $db['prefix'] : ''; + } + } + + 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..2898b5f00 --- /dev/null +++ b/lib/Minz/Dispatcher.php @@ -0,0 +1,138 @@ + +*/ + +/** + * 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 $router; + private $controller; + + /** + * Récupère l'instance du Dispatcher + */ + public static function getInstance ($router) { + if (is_null (self::$instance)) { + self::$instance = new Minz_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 Minz_Exception + */ + public function run () { + $cache = new Minz_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 (Minz_Cache::isEnabled () && !$cache->expired ()) { + ob_start (); + $cache->render (); + $text = ob_get_clean(); + } else { + while (Minz_Request::$reseted) { + Minz_Request::$reseted = false; + + try { + $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); + $this->controller->init (); + $this->controller->firstAction (); + $this->launchAction ( + Minz_Request::actionName () + . 'Action' + ); + $this->controller->lastAction (); + + if (!Minz_Request::$reseted) { + ob_start (); + $this->controller->view ()->build (); + $text = ob_get_clean(); + } + } catch (Minz_Exception $e) { + throw $e; + } + } + + if (Minz_Cache::isEnabled ()) { + $cache->cache ($text); + } + } + + Minz_Response::setBody ($text); + } + + /** + * 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 ($this->router); + + 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 (!Minz_Request::$reseted) { + 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..1ad0d313c --- /dev/null +++ b/lib/Minz/Error.php @@ -0,0 +1,94 @@ + +*/ + +/** + * 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'; + + if (file_exists ($error_filename)) { + $params = array ( + 'code' => $code, + 'logs' => $logs + ); + + Minz_Response::setHeader ($code); + if ($redirect) { + Minz_Request::forward (array ( + 'c' => 'error' + ), true); + } else { + Minz_Request::forward (array ( + 'c' => 'error', + 'params' => $params + ), false); + } + } else { + $text = '

    An error occured

    '."\n"; + + if (!empty ($logs)) { + $text .= '
      '."\n"; + foreach ($logs as $log) { + $text .= '
    • ' . $log . '
    • '."\n"; + } + $text .= '
    '."\n"; + } + + Minz_Response::setHeader ($code); + Minz_Response::setBody ($text); + Minz_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 = 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/FrontController.php b/lib/Minz/FrontController.php new file mode 100644 index 000000000..eb9835fe5 --- /dev/null +++ b/lib/Minz/FrontController.php @@ -0,0 +1,97 @@ +. +# +# ***** 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; + protected $router; + + /** + * Constructeur + * Initialise le router et le dispatcher + */ + public function __construct () { + if (LOG_PATH === false) { + $this->killApp ('Path doesn\'t exist : LOG_PATH'); + } + + try { + Minz_Configuration::init (); + + Minz_Request::init (); + + $this->router = new Minz_Router (); + $this->router->init (); + } catch (Minz_RouteNotFoundException $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + Minz_Error::error ( + 404, + array ('error' => array ($e->getMessage ())) + ); + } catch (Minz_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + $this->killApp ($e->getMessage ()); + } + + $this->dispatcher = Minz_Dispatcher::getInstance ($this->router); + } + + /** + * Démarre l'application (lance le dispatcher et renvoie la réponse + */ + public function run () { + try { + $this->dispatcher->run (); + Minz_Response::send (); + } 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 ###
    '."\n".$txt); + } +} diff --git a/lib/Minz/Helper.php b/lib/Minz/Helper.php new file mode 100644 index 000000000..b058211d3 --- /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 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 ('Helper', 'stripslashes_r'), $var); + } else { + return stripslashes($var); + } + } +} 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 @@ + +*/ + +/** + * La classe Model représente un modèle de l'application (représentation MVC) + */ +class Minz_Model { + +} 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 @@ + +*/ + +/** + * 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/Request.php b/lib/Minz/Request.php new file mode 100644 index 000000000..c8ffa4a42 --- /dev/null +++ b/lib/Minz/Request.php @@ -0,0 +1,197 @@ + +*/ + +/** + * 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'; + + 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; + } + static function htmlspecialchars_utf8 ($p) { + return htmlspecialchars($p, ENT_QUOTES, 'UTF-8'); + } + 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; + } elseif(is_array($p)) { + return array_map('self::htmlspecialchars_utf8', $p); + } else { + return self::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 () { + return Minz_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 = Minz_Url::checkUrl ($url); + + if ($redirect) { + header ('Location: ' . Minz_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 = Minz_Helper::stripslashes_r ($_GET); + $_POST = Minz_Helper::stripslashes_r ($_POST); + $_COOKIE = Minz_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..f8ea3d946 --- /dev/null +++ b/lib/Minz/Response.php @@ -0,0 +1,60 @@ + +*/ + +/** + * Response représente la requête http renvoyée à l'utilisateur + */ +class Minz_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 100644 index 000000000..1ccd72597 --- /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 Minz_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 (Minz_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 Minz_FileNotExistException ( + self::ROUTES_PATH_NAME, + Minz_Exception::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 (Minz_Configuration::useUrlRewriting ()) { + try { + $url = $this->buildWithRewriting (); + } catch (Minz_RouteNotFoundException $e) { + throw $e; + } + } else { + $url = $this->buildWithoutRewriting (); + } + + $url['params'] = array_merge ( + $url['params'], + Minz_Request::fetchPOST () + ); + + Minz_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'] = 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; + } + + /** + * 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 = Minz_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 Minz_RouteNotFoundException ( + $uri, + Minz_Exception::ERROR + ); + } + + // post-traitement + $url = Minz_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 100644 index 000000000..878caa556 --- /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 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; + } +} diff --git a/lib/Minz/Url.php b/lib/Minz/Url.php new file mode 100644 index 000000000..30f7f6231 --- /dev/null +++ b/lib/Minz/Url.php @@ -0,0 +1,129 @@ +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'] != 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..c8d0aefed --- /dev/null +++ b/lib/Minz/View.php @@ -0,0 +1,241 @@ + +*/ + +/** + * 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 = 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 . '/' + . Minz_Request::controllerName () . '/' + . Minz_Request::actionName () . '.phtml'; + + if (file_exists (APP_PATH + . self::LAYOUT_PATH_NAME + . self::LAYOUT_FILENAME)) { + $this->use_layout = true; + } + + self::$title = Minz_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 { + Minz_Log::record ('File doesn\'t exist : `' + . $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 (file_exists ($fic_partial)) { + include ($fic_partial); + } else { + Minz_Log::record ('File doesn\'t exist : `' + . $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 (file_exists ($fic_helper)) { + include ($fic_helper); + } else { + Minz_Log::record ('File doesn\'t exist : `' + . $fic_helper . '`', + Minz_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, $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; + } + } +} + + -- cgit v1.2.3 From b4463cb69e64ff2dfe840ef69f1b825ecdbee43e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 11:28:27 +0100 Subject: Problème casse renommage répertoire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/configureController.php | 415 ++++++++++++++++++++++++++++++ app/Controllers/entryController.php | 112 ++++++++ app/Controllers/errorController.php | 26 ++ app/Controllers/feedController.php | 428 +++++++++++++++++++++++++++++++ app/Controllers/indexController.php | 277 ++++++++++++++++++++ app/Controllers/javascriptController.php | 13 + app/controllers/configureController.php | 415 ------------------------------ app/controllers/entryController.php | 112 -------- app/controllers/errorController.php | 26 -- app/controllers/feedController.php | 428 ------------------------------- app/controllers/indexController.php | 277 -------------------- app/controllers/javascriptController.php | 13 - 12 files changed, 1271 insertions(+), 1271 deletions(-) create mode 100755 app/Controllers/configureController.php create mode 100755 app/Controllers/entryController.php create mode 100644 app/Controllers/errorController.php create mode 100755 app/Controllers/feedController.php create mode 100755 app/Controllers/indexController.php create mode 100755 app/Controllers/javascriptController.php delete mode 100755 app/controllers/configureController.php delete mode 100755 app/controllers/entryController.php delete mode 100644 app/controllers/errorController.php delete mode 100755 app/controllers/feedController.php delete mode 100755 app/controllers/indexController.php delete mode 100755 app/controllers/javascriptController.php (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php new file mode 100755 index 000000000..62fead315 --- /dev/null +++ b/app/Controllers/configureController.php @@ -0,0 +1,415 @@ +view->conf) && !is_logged ()) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + } + + $catDAO = new FreshRSS_CategoryDAO (); + $catDAO->checkDefault (); + } + + public function categorizeAction () { + $feedDAO = new FreshRSS_FeedDAO (); + $catDAO = new FreshRSS_CategoryDAO (); + $catDAO->checkDefault (); + $defaultCategory = $catDAO->getDefault (); + $defaultId = $defaultCategory->id (); + + if (Minz_Request::isPost ()) { + $cats = Minz_Request::param ('categories', array ()); + $ids = Minz_Request::param ('ids', array ()); + $newCat = trim (Minz_Request::param ('new_category', '')); + + foreach ($cats as $key => $name) { + if (strlen ($name) > 0) { + $cat = new FreshRSS_Category ($name); + $values = array ( + 'name' => $cat->name (), + 'color' => $cat->color () + ); + $catDAO->updateCategory ($ids[$key], $values); + } elseif ($ids[$key] != $defaultId) { + $feedDAO->changeCategory ($ids[$key], $defaultId); + $catDAO->deleteCategory ($ids[$key]); + } + } + + if ($newCat != '') { + $cat = new FreshRSS_Category ($newCat); + $values = array ( + 'id' => $cat->id (), + 'name' => $cat->name (), + 'color' => $cat->color () + ); + + if ($catDAO->searchByName ($newCat) == false) { + $catDAO->addCategory ($values); + } + } + + // notif + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('categories_updated') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + } + + $this->view->categories = $catDAO->listCategories (false); + $this->view->defaultCategory = $catDAO->getDefault (); + $this->view->feeds = $feedDAO->listFeeds (); + $this->view->flux = false; + + Minz_View::prependTitle (Minz_Translate::t ('categories_management') . ' - '); + } + + public function feedAction () { + $catDAO = new FreshRSS_CategoryDAO (); + $this->view->categories = $catDAO->listCategories (false); + + $feedDAO = new FreshRSS_FeedDAO (); + $this->view->feeds = $feedDAO->listFeeds (); + + $id = Minz_Request::param ('id'); + if ($id == false && !empty ($this->view->feeds)) { + $id = current ($this->view->feeds)->id (); + } + + $this->view->flux = false; + if ($id != false) { + $this->view->flux = $this->view->feeds[$id]; + + if (!$this->view->flux) { + Minz_Error::error ( + 404, + array ('error' => array (Minz_Translate::t ('page_not_found'))) + ); + } else { + if (Minz_Request::isPost () && $this->view->flux) { + $name = Minz_Request::param ('name', ''); + $description = Minz_Request::param('description', ''); + $website = Minz_Request::param('website', ''); + $url = Minz_Request::param('url', ''); + $hist = Minz_Request::param ('keep_history', 'no'); + $cat = Minz_Request::param ('category', 0); + $path = Minz_Request::param ('path_entries', ''); + $priority = Minz_Request::param ('priority', 0); + $user = Minz_Request::param ('http_user', ''); + $pass = Minz_Request::param ('http_pass', ''); + + $keep_history = false; + if ($hist == 'yes') { + $keep_history = true; + } + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + + $values = array ( + 'name' => $name, + 'description' => $description, + 'website' => $website, + 'url' => $url, + 'category' => $cat, + 'pathEntries' => $path, + 'priority' => $priority, + 'httpAuth' => $httpAuth, + 'keep_history' => $keep_history + ); + + if ($feedDAO->updateFeed ($id, $values)) { + $this->view->flux->_category ($cat); + + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feed_updated') + ); + } else { + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('error_occurred_update') + ); + } + + Minz_Session::_param ('notification', $notif); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); + } + + Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - ' . $this->view->flux->name () . ' - '); + } + } else { + Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - '); + } + } + + public function displayAction () { + if (Minz_Request::isPost ()) { + $current_token = $this->view->conf->token (); + + $language = Minz_Request::param ('language', 'en'); + $nb = Minz_Request::param ('posts_per_page', 10); + $mode = Minz_Request::param ('view_mode', 'normal'); + $view = Minz_Request::param ('default_view', 'a'); + $auto_load_more = Minz_Request::param ('auto_load_more', 'no'); + $display = Minz_Request::param ('display_posts', 'no'); + $onread_jump_next = Minz_Request::param ('onread_jump_next', 'no'); + $lazyload = Minz_Request::param ('lazyload', 'no'); + $sort = Minz_Request::param ('sort_order', 'DESC'); + $old = Minz_Request::param ('old_entries', 3); + $mail = Minz_Request::param ('mail_login', false); + $anon = Minz_Request::param ('anon_access', 'no'); + $token = Minz_Request::param ('token', $current_token); + $openArticle = Minz_Request::param ('mark_open_article', 'no'); + $openSite = Minz_Request::param ('mark_open_site', 'no'); + $scroll = Minz_Request::param ('mark_scroll', 'no'); + $reception = Minz_Request::param ('mark_upon_reception', 'no'); + $theme = Minz_Request::param ('theme', 'default'); + $topline_read = Minz_Request::param ('topline_read', 'no'); + $topline_favorite = Minz_Request::param ('topline_favorite', 'no'); + $topline_date = Minz_Request::param ('topline_date', 'no'); + $topline_link = Minz_Request::param ('topline_link', 'no'); + $bottomline_read = Minz_Request::param ('bottomline_read', 'no'); + $bottomline_favorite = Minz_Request::param ('bottomline_favorite', 'no'); + $bottomline_sharing = Minz_Request::param ('bottomline_sharing', 'no'); + $bottomline_tags = Minz_Request::param ('bottomline_tags', 'no'); + $bottomline_date = Minz_Request::param ('bottomline_date', 'no'); + $bottomline_link = Minz_Request::param ('bottomline_link', 'no'); + + $this->view->conf->_language ($language); + $this->view->conf->_postsPerPage (intval ($nb)); + $this->view->conf->_viewMode ($mode); + $this->view->conf->_defaultView ($view); + $this->view->conf->_autoLoadMore ($auto_load_more); + $this->view->conf->_displayPosts ($display); + $this->view->conf->_onread_jump_next ($onread_jump_next); + $this->view->conf->_lazyload ($lazyload); + $this->view->conf->_sortOrder ($sort); + $this->view->conf->_oldEntries ($old); + $this->view->conf->_mailLogin ($mail); + $this->view->conf->_anonAccess ($anon); + $this->view->conf->_token ($token); + $this->view->conf->_markWhen (array ( + 'article' => $openArticle, + 'site' => $openSite, + 'scroll' => $scroll, + 'reception' => $reception, + )); + $this->view->conf->_theme ($theme); + $this->view->conf->_topline_read ($topline_read); + $this->view->conf->_topline_favorite ($topline_favorite); + $this->view->conf->_topline_date ($topline_date); + $this->view->conf->_topline_link ($topline_link); + $this->view->conf->_bottomline_read ($bottomline_read); + $this->view->conf->_bottomline_favorite ($bottomline_favorite); + $this->view->conf->_bottomline_sharing ($bottomline_sharing); + $this->view->conf->_bottomline_tags ($bottomline_tags); + $this->view->conf->_bottomline_date ($bottomline_date); + $this->view->conf->_bottomline_link ($bottomline_link); + + $values = array ( + 'language' => $this->view->conf->language (), + 'posts_per_page' => $this->view->conf->postsPerPage (), + 'view_mode' => $this->view->conf->viewMode (), + 'default_view' => $this->view->conf->defaultView (), + 'auto_load_more' => $this->view->conf->autoLoadMore (), + 'display_posts' => $this->view->conf->displayPosts (), + 'onread_jump_next' => $this->view->conf->onread_jump_next (), + 'lazyload' => $this->view->conf->lazyload (), + 'sort_order' => $this->view->conf->sortOrder (), + 'old_entries' => $this->view->conf->oldEntries (), + 'mail_login' => $this->view->conf->mailLogin (), + 'anon_access' => $this->view->conf->anonAccess (), + 'token' => $this->view->conf->token (), + 'mark_when' => $this->view->conf->markWhen (), + 'theme' => $this->view->conf->theme (), + 'topline_read' => $this->view->conf->toplineRead () ? 'yes' : 'no', + 'topline_favorite' => $this->view->conf->toplineFavorite () ? 'yes' : 'no', + 'topline_date' => $this->view->conf->toplineDate () ? 'yes' : 'no', + 'topline_link' => $this->view->conf->toplineLink () ? 'yes' : 'no', + 'bottomline_read' => $this->view->conf->bottomlineRead () ? 'yes' : 'no', + 'bottomline_favorite' => $this->view->conf->bottomlineFavorite () ? 'yes' : 'no', + 'bottomline_sharing' => $this->view->conf->bottomlineSharing () ? 'yes' : 'no', + 'bottomline_tags' => $this->view->conf->bottomlineTags () ? 'yes' : 'no', + 'bottomline_date' => $this->view->conf->bottomlineDate () ? 'yes' : 'no', + 'bottomline_link' => $this->view->conf->bottomlineLink () ? 'yes' : 'no', + ); + + $confDAO = new FreshRSS_ConfigurationDAO (); + $confDAO->update ($values); + Minz_Session::_param ('conf', $this->view->conf); + Minz_Session::_param ('mail', $this->view->conf->mailLogin ()); + + Minz_Session::_param ('language', $this->view->conf->language ()); + Minz_Translate::reset (); + + // notif + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('configuration_updated') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward (array ('c' => 'configure', 'a' => 'display'), true); + } + + $this->view->themes = FreshRSS_Themes::get(); + + Minz_View::prependTitle (Minz_Translate::t ('general_and_reading_management') . ' - '); + + $entryDAO = new FreshRSS_EntryDAO (); + $this->view->nb_total = $entryDAO->count (); + $this->view->size_total = $entryDAO->size (); + } + + public function sharingAction () { + if (Minz_Request::isPost ()) { + $this->view->conf->_sharing (array ( + 'shaarli' => Minz_Request::param ('shaarli', ''), + 'poche' => Minz_Request::param ('poche', ''), + 'diaspora' => Minz_Request::param ('diaspora', ''), + 'twitter' => Minz_Request::param ('twitter', 'no') === 'yes', + 'g+' => Minz_Request::param ('g+', 'no') === 'yes', + 'facebook' => Minz_Request::param ('facebook', 'no') === 'yes', + 'email' => Minz_Request::param ('email', 'no') === 'yes', + 'print' => Minz_Request::param ('print', 'no') === 'yes' + )); + + $confDAO = new FreshRSS_ConfigurationDAO (); + $confDAO->update ($this->view->conf->sharing ()); + Minz_Session::_param ('conf', $this->view->conf); + + // notif + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('configuration_updated') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward (array ('c' => 'configure', 'a' => 'sharing'), true); + } + + Minz_View::prependTitle (Minz_Translate::t ('sharing_management') . ' - '); + + $entryDAO = new FreshRSS_EntryDAO (); + $this->view->nb_total = $entryDAO->count (); + } + + public function importExportAction () { + $catDAO = new FreshRSS_CategoryDAO (); + $this->view->categories = $catDAO->listCategories (); + + $this->view->req = Minz_Request::param ('q'); + + if ($this->view->req == 'export') { + Minz_View::_title ('freshrss_feeds.opml'); + + $this->view->_useLayout (false); + header('Content-Type: application/xml; charset=utf-8'); + header('Content-disposition: attachment; filename=freshrss_feeds.opml'); + + $feedDAO = new FreshRSS_FeedDAO (); + $catDAO = new FreshRSS_CategoryDAO (); + + $list = array (); + foreach ($catDAO->listCategories () as $key => $cat) { + $list[$key]['name'] = $cat->name (); + $list[$key]['feeds'] = $feedDAO->listByCategory ($cat->id ()); + } + + $this->view->categories = $list; + } elseif ($this->view->req == 'import' && Minz_Request::isPost ()) { + if ($_FILES['file']['error'] == 0) { + // on parse le fichier OPML pour récupérer les catégories et les flux associés + try { + list ($categories, $feeds) = opml_import ( + file_get_contents ($_FILES['file']['tmp_name']) + ); + + // On redirige vers le controller feed qui va se charger d'insérer les flux en BDD + // les flux sont mis au préalable dans des variables de Request + Minz_Request::_param ('q', 'null'); + Minz_Request::_param ('categories', $categories); + Minz_Request::_param ('feeds', $feeds); + Minz_Request::forward (array ('c' => 'feed', 'a' => 'massiveImport')); + } catch (FreshRSS_Opml_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); + + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('bad_opml_file') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward (array ( + 'c' => 'configure', + 'a' => 'importExport' + ), true); + } + } + } + + $feedDAO = new FreshRSS_FeedDAO (); + $this->view->feeds = $feedDAO->listFeeds (); + + // au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste + $this->view->flux = false; + + Minz_View::prependTitle (Translate::t ('import_export_opml') . ' - '); + } + + public function shortcutAction () { + $list_keys = array ('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter', + 'escape', 'f', 'g', 'h', 'i', 'insert', 'j', 'k', 'l', 'left', + 'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right', + 's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y', + 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', + 'f10', 'f11', 'f12'); + $this->view->list_keys = $list_keys; + $list_names = array ('mark_read', 'mark_favorite', 'go_website', 'next_entry', + 'prev_entry', 'next_page', 'prev_page', 'collapse_entry', + 'load_more'); + + if (Minz_Request::isPost ()) { + $shortcuts = Minz_Request::param ('shortcuts'); + $shortcuts_ok = array (); + + foreach ($shortcuts as $key => $value) { + if (in_array ($key, $list_names) + && in_array ($value, $list_keys)) { + $shortcuts_ok[$key] = $value; + } + } + + $this->view->conf->_shortcuts ($shortcuts_ok); + + $values = array ( + 'shortcuts' => $this->view->conf->shortcuts () + ); + + $confDAO = new FreshRSS_ConfigurationDAO (); + $confDAO->update ($values); + Minz_Session::_param ('conf', $this->view->conf); + + // notif + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('shortcuts_updated') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward (array ('c' => 'configure', 'a' => 'shortcut'), true); + } + + Minz_View::prependTitle (Minz_Translate::t ('shortcuts_management') . ' - '); + } +} diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php new file mode 100755 index 000000000..a332ca8a9 --- /dev/null +++ b/app/Controllers/entryController.php @@ -0,0 +1,112 @@ +view->conf) && !is_logged ()) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + } + + $this->params = array (); + $this->redirect = false; + $ajax = Minz_Request::param ('ajax'); + if ($ajax) { + $this->view->_useLayout (false); + } + } + public function lastAction () { + $ajax = Minz_Request::param ('ajax'); + if (!$ajax && $this->redirect) { + Minz_Request::forward (array ( + 'c' => 'index', + 'a' => 'index', + 'params' => $this->params + ), true); + } else { + Minz_Request::_param ('ajax'); + } + } + + public function readAction () { + $this->redirect = true; + + $id = Minz_Request::param ('id'); + $is_read = Minz_Request::param ('is_read'); + $get = Minz_Request::param ('get'); + $nextGet = Minz_Request::param ('nextGet', $get); + $idMax = Minz_Request::param ('idMax', 0); + + $is_read = !!$is_read; + + $entryDAO = new FreshRSS_EntryDAO (); + if ($id == false) { + if (!$get) { + $entryDAO->markReadEntries ($idMax); + } else { + $typeGet = $get[0]; + $get = substr ($get, 2); + switch ($typeGet) { + case 'c': + $entryDAO->markReadCat ($get, $idMax); + break; + case 'f': + $entryDAO->markReadFeed ($get, $idMax); + break; + case 's': + $entryDAO->markReadEntries ($idMax, true); + break; + case 'a': + $entryDAO->markReadEntries ($idMax); + break; + } + if ($nextGet !== 'a') { + $this->params = array ('get' => $nextGet); + } + } + + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feeds_marked_read') + ); + Minz_Session::_param ('notification', $notif); + } else { + $entryDAO->markRead ($id, $is_read); + } + } + + public function bookmarkAction () { + $this->redirect = true; + + $id = Minz_Request::param ('id'); + if ($id) { + $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO->markFavorite ($id, Minz_Request::param ('is_favorite')); + } + } + + public function optimizeAction() { + @set_time_limit(300); + invalidateHttpCache(); + + // La table des entrées a tendance à grossir énormément + // Cette action permet d'optimiser cette table permettant de grapiller un peu de place + // Cette fonctionnalité n'est à appeler qu'occasionnellement + $entryDAO = new FreshRSS_EntryDAO(); + $entryDAO->optimizeTable(); + + invalidateHttpCache(); + + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('optimization_complete') + ); + Minz_Session::_param ('notification', $notif); + + Minz_Request::forward(array( + 'c' => 'configure', + 'a' => 'display' + ), true); + } +} diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php new file mode 100644 index 000000000..d1c2f8fec --- /dev/null +++ b/app/Controllers/errorController.php @@ -0,0 +1,26 @@ +view->code = 'Error 403 - Forbidden'; + break; + case 404: + $this->view->code = 'Error 404 - Not found'; + break; + case 500: + $this->view->code = 'Error 500 - Internal Server Error'; + break; + case 503: + $this->view->code = 'Error 503 - Service Unavailable'; + break; + default: + $this->view->code = 'Error 404 - Not found'; + } + + $this->view->logs = Minz_Request::param ('logs'); + + Minz_View::prependTitle ($this->view->code . ' - '); + } +} diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php new file mode 100755 index 000000000..a85877724 --- /dev/null +++ b/app/Controllers/feedController.php @@ -0,0 +1,428 @@ +view->conf->token(); + $token_param = Minz_Request::param ('token', ''); + $token_is_ok = ($token != '' && $token == $token_param); + $action = Minz_Request::actionName (); + + if (login_is_conf ($this->view->conf) && + !is_logged () && + !($token_is_ok && $action == 'actualize')) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + } + + $this->catDAO = new FreshRSS_CategoryDAO (); + $this->catDAO->checkDefault (); + } + + private static function entryDateComparer($e1, $e2) { + $d1 = $e1->date(true); + $d2 = $e2->date(true); + if ($d1 === $d2) { + return 0; + } + return ($d1 < $d2) ? -1 : 1; + } + + public function addAction () { + @set_time_limit(300); + + if (Minz_Request::isPost ()) { + $url = Minz_Request::param ('url_rss'); + $cat = Minz_Request::param ('category', false); + if ($cat === false) { + $def_cat = $this->catDAO->getDefault (); + $cat = $def_cat->id (); + } + + $user = Minz_Request::param ('username'); + $pass = Minz_Request::param ('password'); + $params = array (); + + $transactionStarted = false; + try { + $feed = new FreshRSS_Feed ($url); + $feed->_category ($cat); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + $feed->_httpAuth ($httpAuth); + + $feed->load (); + + $feedDAO = new FreshRSS_FeedDAO (); + $values = array ( + 'url' => $feed->url (), + 'category' => $feed->category (), + 'name' => $feed->name (), + 'website' => $feed->website (), + 'description' => $feed->description (), + 'lastUpdate' => time (), + 'httpAuth' => $feed->httpAuth (), + ); + + if ($feedDAO->searchByUrl ($values['url'])) { + // on est déjà abonné à ce flux + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) + ); + Minz_Session::_param ('notification', $notif); + } else { + $id = $feedDAO->addFeed ($values); + if (!$id) { + // problème au niveau de la base de données + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) + ); + Minz_Session::_param ('notification', $notif); + } else { + $feed->_id ($id); + $feed->faviconPrepare(); + + $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; + + $entryDAO = new FreshRSS_EntryDAO (); + $entries = $feed->entries (); + usort($entries, 'self::entryDateComparer'); + + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + + $transactionStarted = true; + $feedDAO->beginTransaction (); + // on ajoute les articles en masse sans vérification + foreach ($entries as $entry) { + if ($entry->date (true) >= $date_min || + $feed->keepHistory ()) { + $values = $entry->toArray (); + $values['id_feed'] = $feed->id (); + $values['id'] = min(time(), $entry->date (true)) . uSecString(); + $values['is_read'] = $is_read; + $entryDAO->addEntry ($values); + } + } + $feedDAO->updateLastUpdate ($feed->id ()); + $feedDAO->commit (); + $transactionStarted = false; + + // ok, ajout terminé + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feed_added', $feed->name ()) + ); + Minz_Session::_param ('notification', $notif); + + // permet de rediriger vers la page de conf du flux + $params['id'] = $feed->id (); + } + } + } catch (FreshRSS_BadUrl_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('invalid_url', $url) + ); + Minz_Session::_param ('notification', $notif); + } catch (FreshRSS_Feed_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('internal_problem_feed') + ); + Minz_Session::_param ('notification', $notif); + } catch (Minz_FileNotExistException $e) { + // Répertoire de cache n'existe pas + Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('internal_problem_feed') + ); + Minz_Session::_param ('notification', $notif); + } + if ($transactionStarted) { + $feedDAO->rollBack (); + } + + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); + } + } + + public function truncateAction () { + if (Minz_Request::isPost ()) { + $id = Minz_Request::param ('id'); + $feedDAO = new FreshRSS_FeedDAO (); + $n = $feedDAO->truncate($id); + $notif = array( + 'type' => $n === false ? 'bad' : 'good', + 'content' => Minz_Translate::t ('n_entries_deleted', $n) + ); + Minz_Session::_param ('notification', $notif); + invalidateHttpCache(); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); + } + } + + public function actualizeAction () { + @set_time_limit(300); + + $feedDAO = new FreshRSS_FeedDAO (); + $entryDAO = new FreshRSS_EntryDAO (); + + $id = Minz_Request::param ('id'); + $force = Minz_Request::param ('force', false); + + // on créé la liste des flux à mettre à actualiser + // si on veut mettre un flux à jour spécifiquement, on le met + // dans la liste, mais seul (permet d'automatiser le traitement) + $feeds = array (); + if ($id) { + $feed = $feedDAO->searchById ($id); + if ($feed) { + $feeds = array ($feed); + } + } else { + $feeds = $feedDAO->listFeedsOrderUpdate (); + } + + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + + $i = 0; + $flux_update = 0; + foreach ($feeds as $feed) { + try { + $feed->load (); + $feed->faviconPrepare(); + $entries = $feed->entries (); + usort($entries, 'self::entryDateComparer'); + + $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; + + //For this feed, check last n entry GUIDs already in database + $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); + + // On ne vérifie pas strictement que l'article n'est pas déjà en BDD + // La BDD refusera l'ajout car (id_feed, guid) doit être unique + $feedDAO->beginTransaction (); + foreach ($entries as $entry) { + if ((!isset ($existingGuids[$entry->guid ()])) && + ($entry->date (true) >= $date_min || + $feed->keepHistory ())) { + $values = $entry->toArray (); + //Use declared date at first import, otherwise use discovery date + $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString(); + $values['is_read'] = $is_read; + $entryDAO->addEntry ($values); + } + } + + if ((!$feed->keepHistory()) && (rand(0, 30) === 1)) { + $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, count($entries) + 10); + Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); + } + + // on indique que le flux vient d'être mis à jour en BDD + $feedDAO->updateLastUpdate ($feed->id ()); + $feedDAO->commit (); + $flux_update++; + } catch (FreshRSS_Feed_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); + $feedDAO->updateLastUpdate ($feed->id (), 1); + } + + // On arrête à 10 flux pour ne pas surcharger le serveur + // sauf si le paramètre $force est à vrai + $i++; + if ($i >= 10 && !$force) { + break; + } + } + + $url = array (); + if ($flux_update === 1) { + // on a mis un seul flux à jour + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) + ); + } elseif ($flux_update > 1) { + // plusieurs flux on été mis à jour + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) + ); + } else { + // aucun flux n'a été mis à jour, oups + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('no_feed_actualized') + ); + } + + if ($i === 1) { + // Si on a voulu mettre à jour qu'un flux + // on filtre l'affichage par ce flux + $feed = reset ($feeds); + $url['params'] = array ('get' => 'f_' . $feed->id ()); + } + + if (Minz_Request::param ('ajax', 0) === 0) { + Minz_Session::_param ('notification', $notif); + Minz_Request::forward ($url, true); + } else { + // Une requête Ajax met un seul flux à jour. + // Comme en principe plusieurs requêtes ont lieu, + // on indique que "plusieurs flux ont été mis à jour". + // Cela permet d'avoir une notification plus proche du + // ressenti utilisateur + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feeds_actualized') + ); + Minz_Session::_param ('notification', $notif); + // et on désactive le layout car ne sert à rien + $this->view->_useLayout (false); + } + } + + public function massiveImportAction () { + @set_time_limit(300); + + $entryDAO = new FreshRSS_EntryDAO (); + $feedDAO = new FreshRSS_FeedDAO (); + + $categories = Minz_Request::param ('categories', array (), true); + $feeds = Minz_Request::param ('feeds', array (), true); + + // on ajoute les catégories en masse dans une fonction à part + $this->addCategories ($categories); + + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + + // la variable $error permet de savoir si une erreur est survenue + // Le but est de ne pas arrêter l'import même en cas d'erreur + // L'utilisateur sera mis au courant s'il y a eu des erreurs, mais + // ne connaîtra pas les détails. Ceux-ci seront toutefois logguées + $error = false; + $i = 0; + foreach ($feeds as $feed) { + try { + $values = array ( + 'id' => $feed->id (), + 'url' => $feed->url (), + 'category' => $feed->category (), + 'name' => $feed->name (), + 'website' => $feed->website (), + 'description' => $feed->description (), + 'lastUpdate' => 0, + 'httpAuth' => $feed->httpAuth () + ); + + // ajout du flux que s'il n'est pas déjà en BDD + if (!$feedDAO->searchByUrl ($values['url'])) { + $id = $feedDAO->addFeed ($values); + if ($id) { + $feed->_id ($id); + $feed->faviconPrepare(); + } else { + $error = true; + } + } + } catch (FreshRSS_Feed_Exception $e) { + $error = true; + Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); + } + } + + if ($error) { + $res = Minz_Translate::t ('feeds_imported_with_errors'); + } else { + $res = Minz_Translate::t ('feeds_imported'); + } + + $notif = array ( + 'type' => 'good', + 'content' => $res + ); + Minz_Session::_param ('notification', $notif); + Minz_Session::_param ('actualize_feeds', true); + + // et on redirige vers la page d'accueil + Minz_Request::forward (array ( + 'c' => 'index', + 'a' => 'index' + ), true); + } + + public function deleteAction () { + if (Minz_Request::isPost ()) { + $type = Minz_Request::param ('type', 'feed'); + $id = Minz_Request::param ('id'); + + $feedDAO = new FreshRSS_FeedDAO (); + if ($type == 'category') { + if ($feedDAO->deleteFeedByCategory ($id)) { + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('category_emptied') + ); + //TODO: Delete old favicons + } else { + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('error_occured') + ); + } + } else { + if ($feedDAO->deleteFeed ($id)) { + $notif = array ( + 'type' => 'good', + 'content' => Minz_Translate::t ('feed_deleted') + ); + Feed::faviconDelete($id); + } else { + $notif = array ( + 'type' => 'bad', + 'content' => Minz_Translate::t ('error_occured') + ); + } + } + + Minz_Session::_param ('notification', $notif); + + if ($type == 'category') { + Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + } else { + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); + } + } + } + + private function addCategories ($categories) { + $catDAO = new FreshRSS_CategoryDAO (); + + foreach ($categories as $cat) { + if (!$catDAO->searchByName ($cat->name ())) { + $values = array ( + 'id' => $cat->id (), + 'name' => $cat->name (), + 'color' => $cat->color () + ); + $catDAO->addCategory ($values); + } + } + } +} diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php new file mode 100755 index 000000000..92070590a --- /dev/null +++ b/app/Controllers/indexController.php @@ -0,0 +1,277 @@ +entryDAO = new FreshRSS_EntryDAO (); + $this->feedDAO = new FreshRSS_FeedDAO (); + $this->catDAO = new FreshRSS_CategoryDAO (); + } + + public function indexAction () { + $output = Minz_Request::param ('output'); + + $token = $this->view->conf->token(); + $token_param = Minz_Request::param ('token', ''); + $token_is_ok = ($token != '' && $token === $token_param); + + // check if user is log in + if(login_is_conf ($this->view->conf) && + !is_logged() && + $this->view->conf->anonAccess() === 'no' && + !($output === 'rss' && $token_is_ok)) { + return; + } + + // construction of RSS url of this feed + $params = Minz_Request::params (); + $params['output'] = 'rss'; + if (isset ($params['search'])) { + $params['search'] = urlencode ($params['search']); + } + if (login_is_conf($this->view->conf) && + $this->view->conf->anonAccess() === 'no' && + $token != '') { + $params['token'] = $token; + } + $this->view->rss_url = array ( + 'c' => 'index', + 'a' => 'index', + 'params' => $params + ); + + if ($output === 'rss') { + // no layout for RSS output + $this->view->_useLayout (false); + header('Content-Type: application/rss+xml; charset=utf-8'); + } else { + Minz_View::appendScript (Minz_Url::display ('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); + + if ($output === 'global') { + Minz_View::appendScript (Minz_Url::display ('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); + } + } + + $this->view->cat_aside = $this->catDAO->listCategories (); + $this->view->nb_favorites = $this->entryDAO->countUnreadReadFavorites (); + $this->view->currentName = ''; + + $this->view->get_c = ''; + $this->view->get_f = ''; + + $get = Minz_Request::param ('get', 'a'); + $getType = $get[0]; + $getId = substr ($get, 2); + if (!$this->checkAndProcessType ($getType, $getId)) { + Minz_Log::record ('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); + Minz_Error::error ( + 404, + array ('error' => array (Minz_Translate::t ('page_not_found'))) + ); + return; + } + + $this->view->nb_not_read = HelperCategory::CountUnreads($this->view->cat_aside, 1); + + // mise à jour des titres + $this->view->rss_title = $this->view->currentName . ' | ' . Minz_View::title(); + if ($this->view->nb_not_read > 0) { + Minz_View::appendTitle (' (' . $this->view->nb_not_read . ')'); + } + Minz_View::prependTitle ( + $this->view->currentName . + ($this->nb_not_read_cat > 0 ? ' (' . $this->nb_not_read_cat . ')' : '') . + ' - ' + ); + + // On récupère les différents éléments de filtrage + $this->view->state = $state = Minz_Request::param ('state', $this->view->conf->defaultView ()); + $filter = Minz_Request::param ('search', ''); + if (!empty($filter)) { + $state = 'all'; //Search always in read and unread articles + } + $this->view->order = $order = Minz_Request::param ('order', $this->view->conf->sortOrder ()); + $nb = Minz_Request::param ('nb', $this->view->conf->postsPerPage ()); + $first = Minz_Request::param ('next', ''); + + if ($state === 'not_read') { //Any unread article in this category at all? + switch ($getType) { + case 'a': + $hasUnread = $this->view->nb_not_read > 0; + break; + case 's': + $hasUnread = $this->view->nb_favorites['unread'] > 0; + break; + case 'c': + $hasUnread = (!isset($this->view->cat_aside[$getId])) || ($this->view->cat_aside[$getId]->nbNotRead() > 0); + break; + case 'f': + $myFeed = HelperCategory::findFeed($this->view->cat_aside, $getId); + $hasUnread = ($myFeed === null) || ($myFeed->nbNotRead() > 0); + break; + default: + $hasUnread = true; + break; + } + if (!$hasUnread) { + $this->view->state = $state = 'all'; + } + } + + // on calcule la date des articles les plus anciens qu'on affiche + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + + try { + $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min); + + // Si on a récupéré aucun article "non lus" + // on essaye de récupérer tous les articles + if ($state === 'not_read' && empty($entries)) { //TODO: Remove in v0.8 + Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); + $this->view->state = 'all'; + $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min); + } + + if (count($entries) <= $nb) { + $this->view->nextId = ''; + } else { //We have more elements for pagination + $lastEntry = array_pop($entries); + $this->view->nextId = $lastEntry->id(); + } + + $this->view->entries = $entries; + } catch (FreshRSS_EntriesGetter_Exception $e) { + Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); + Minz_Error::error ( + 404, + array ('error' => array (Minz_Translate::t ('page_not_found'))) + ); + } + } + + /* + * Vérifie que la catégorie / flux sélectionné existe + * + Initialise correctement les variables de vue get_c et get_f + * + Met à jour la variable $this->nb_not_read_cat + */ + private function checkAndProcessType ($getType, $getId) { + switch ($getType) { + case 'a': + $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); + $this->view->get_c = $getType; + return true; + case 's': + $this->view->currentName = Minz_Translate::t ('your_favorites'); + $this->view->get_c = $getType; + return true; + case 'c': + $cat = isset($this->view->cat_aside[$getId]) ? $this->view->cat_aside[$getId] : null; + if ($cat === null) { + $cat = $this->catDAO->searchById ($getId); + } + if ($cat) { + $this->view->currentName = $cat->name (); + $this->nb_not_read_cat = $cat->nbNotRead (); + $this->view->get_c = $getId; + return true; + } else { + return false; + } + case 'f': + $feed = HelperCategory::findFeed($this->view->cat_aside, $getId); + if (empty($feed)) { + $feed = $this->feedDAO->searchById ($getId); + } + if ($feed) { + $this->view->currentName = $feed->name (); + $this->nb_not_read_cat = $feed->nbNotRead (); + $this->view->get_f = $getId; + $this->view->get_c = $feed->category (); + return true; + } else { + return false; + } + default: + return false; + } + } + + public function aboutAction () { + Minz_View::prependTitle (Minz_Translate::t ('about') . ' - '); + } + + public function logsAction () { + if (login_is_conf ($this->view->conf) && !is_logged ()) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + } + + Minz_View::prependTitle (Minz_Translate::t ('logs') . ' - '); + + if (Minz_Request::isPost ()) { + file_put_contents(LOG_PATH . '/application.log', ''); + } + + $logs = array(); + try { + $logDAO = new FreshRSS_LogDAO (); + $logs = $logDAO->lister (); + $logs = array_reverse ($logs); + } catch (Minz_FileNotExistException $e) { + + } + + //gestion pagination + $page = Minz_Request::param ('page', 1); + $this->view->logsPaginator = new Minz_Paginator ($logs); + $this->view->logsPaginator->_nbItemsPerPage (50); + $this->view->logsPaginator->_currentPage ($page); + } + + public function loginAction () { + $this->view->_useLayout (false); + + $url = 'https://verifier.login.persona.org/verify'; + $assert = Minz_Request::param ('assertion'); + $params = 'assertion=' . $assert . '&audience=' . + urlencode (Minz_Url::display (null, 'php', true)); + $ch = curl_init (); + $options = array ( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_POST => 2, + CURLOPT_POSTFIELDS => $params + ); + curl_setopt_array ($ch, $options); + $result = curl_exec ($ch); + curl_close ($ch); + + $res = json_decode ($result, true); + if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mailLogin ()) { + Minz_Session::_param ('mail', $res['email']); + invalidateHttpCache(); + } else { + $res = array (); + $res['status'] = 'failure'; + $res['reason'] = Minz_Translate::t ('invalid_login'); + } + + header('Content-Type: application/json; charset=UTF-8'); + $this->view->res = json_encode ($res); + } + + public function logoutAction () { + $this->view->_useLayout (false); + Minz_Session::_param ('mail'); + invalidateHttpCache(); + } +} diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php new file mode 100755 index 000000000..e7e25f656 --- /dev/null +++ b/app/Controllers/javascriptController.php @@ -0,0 +1,13 @@ +view->_useLayout (false); + header('Content-type: text/javascript'); + } + + public function actualizeAction () { + $feedDAO = new FreshRSS_FeedDAO (); + $this->view->feeds = $feedDAO->listFeeds (); + } +} diff --git a/app/controllers/configureController.php b/app/controllers/configureController.php deleted file mode 100755 index 62fead315..000000000 --- a/app/controllers/configureController.php +++ /dev/null @@ -1,415 +0,0 @@ -view->conf) && !is_logged ()) { - Minz_Error::error ( - 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) - ); - } - - $catDAO = new FreshRSS_CategoryDAO (); - $catDAO->checkDefault (); - } - - public function categorizeAction () { - $feedDAO = new FreshRSS_FeedDAO (); - $catDAO = new FreshRSS_CategoryDAO (); - $catDAO->checkDefault (); - $defaultCategory = $catDAO->getDefault (); - $defaultId = $defaultCategory->id (); - - if (Minz_Request::isPost ()) { - $cats = Minz_Request::param ('categories', array ()); - $ids = Minz_Request::param ('ids', array ()); - $newCat = trim (Minz_Request::param ('new_category', '')); - - foreach ($cats as $key => $name) { - if (strlen ($name) > 0) { - $cat = new FreshRSS_Category ($name); - $values = array ( - 'name' => $cat->name (), - 'color' => $cat->color () - ); - $catDAO->updateCategory ($ids[$key], $values); - } elseif ($ids[$key] != $defaultId) { - $feedDAO->changeCategory ($ids[$key], $defaultId); - $catDAO->deleteCategory ($ids[$key]); - } - } - - if ($newCat != '') { - $cat = new FreshRSS_Category ($newCat); - $values = array ( - 'id' => $cat->id (), - 'name' => $cat->name (), - 'color' => $cat->color () - ); - - if ($catDAO->searchByName ($newCat) == false) { - $catDAO->addCategory ($values); - } - } - - // notif - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('categories_updated') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); - } - - $this->view->categories = $catDAO->listCategories (false); - $this->view->defaultCategory = $catDAO->getDefault (); - $this->view->feeds = $feedDAO->listFeeds (); - $this->view->flux = false; - - Minz_View::prependTitle (Minz_Translate::t ('categories_management') . ' - '); - } - - public function feedAction () { - $catDAO = new FreshRSS_CategoryDAO (); - $this->view->categories = $catDAO->listCategories (false); - - $feedDAO = new FreshRSS_FeedDAO (); - $this->view->feeds = $feedDAO->listFeeds (); - - $id = Minz_Request::param ('id'); - if ($id == false && !empty ($this->view->feeds)) { - $id = current ($this->view->feeds)->id (); - } - - $this->view->flux = false; - if ($id != false) { - $this->view->flux = $this->view->feeds[$id]; - - if (!$this->view->flux) { - Minz_Error::error ( - 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) - ); - } else { - if (Minz_Request::isPost () && $this->view->flux) { - $name = Minz_Request::param ('name', ''); - $description = Minz_Request::param('description', ''); - $website = Minz_Request::param('website', ''); - $url = Minz_Request::param('url', ''); - $hist = Minz_Request::param ('keep_history', 'no'); - $cat = Minz_Request::param ('category', 0); - $path = Minz_Request::param ('path_entries', ''); - $priority = Minz_Request::param ('priority', 0); - $user = Minz_Request::param ('http_user', ''); - $pass = Minz_Request::param ('http_pass', ''); - - $keep_history = false; - if ($hist == 'yes') { - $keep_history = true; - } - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - - $values = array ( - 'name' => $name, - 'description' => $description, - 'website' => $website, - 'url' => $url, - 'category' => $cat, - 'pathEntries' => $path, - 'priority' => $priority, - 'httpAuth' => $httpAuth, - 'keep_history' => $keep_history - ); - - if ($feedDAO->updateFeed ($id, $values)) { - $this->view->flux->_category ($cat); - - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feed_updated') - ); - } else { - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('error_occurred_update') - ); - } - - Minz_Session::_param ('notification', $notif); - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); - } - - Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - ' . $this->view->flux->name () . ' - '); - } - } else { - Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - '); - } - } - - public function displayAction () { - if (Minz_Request::isPost ()) { - $current_token = $this->view->conf->token (); - - $language = Minz_Request::param ('language', 'en'); - $nb = Minz_Request::param ('posts_per_page', 10); - $mode = Minz_Request::param ('view_mode', 'normal'); - $view = Minz_Request::param ('default_view', 'a'); - $auto_load_more = Minz_Request::param ('auto_load_more', 'no'); - $display = Minz_Request::param ('display_posts', 'no'); - $onread_jump_next = Minz_Request::param ('onread_jump_next', 'no'); - $lazyload = Minz_Request::param ('lazyload', 'no'); - $sort = Minz_Request::param ('sort_order', 'DESC'); - $old = Minz_Request::param ('old_entries', 3); - $mail = Minz_Request::param ('mail_login', false); - $anon = Minz_Request::param ('anon_access', 'no'); - $token = Minz_Request::param ('token', $current_token); - $openArticle = Minz_Request::param ('mark_open_article', 'no'); - $openSite = Minz_Request::param ('mark_open_site', 'no'); - $scroll = Minz_Request::param ('mark_scroll', 'no'); - $reception = Minz_Request::param ('mark_upon_reception', 'no'); - $theme = Minz_Request::param ('theme', 'default'); - $topline_read = Minz_Request::param ('topline_read', 'no'); - $topline_favorite = Minz_Request::param ('topline_favorite', 'no'); - $topline_date = Minz_Request::param ('topline_date', 'no'); - $topline_link = Minz_Request::param ('topline_link', 'no'); - $bottomline_read = Minz_Request::param ('bottomline_read', 'no'); - $bottomline_favorite = Minz_Request::param ('bottomline_favorite', 'no'); - $bottomline_sharing = Minz_Request::param ('bottomline_sharing', 'no'); - $bottomline_tags = Minz_Request::param ('bottomline_tags', 'no'); - $bottomline_date = Minz_Request::param ('bottomline_date', 'no'); - $bottomline_link = Minz_Request::param ('bottomline_link', 'no'); - - $this->view->conf->_language ($language); - $this->view->conf->_postsPerPage (intval ($nb)); - $this->view->conf->_viewMode ($mode); - $this->view->conf->_defaultView ($view); - $this->view->conf->_autoLoadMore ($auto_load_more); - $this->view->conf->_displayPosts ($display); - $this->view->conf->_onread_jump_next ($onread_jump_next); - $this->view->conf->_lazyload ($lazyload); - $this->view->conf->_sortOrder ($sort); - $this->view->conf->_oldEntries ($old); - $this->view->conf->_mailLogin ($mail); - $this->view->conf->_anonAccess ($anon); - $this->view->conf->_token ($token); - $this->view->conf->_markWhen (array ( - 'article' => $openArticle, - 'site' => $openSite, - 'scroll' => $scroll, - 'reception' => $reception, - )); - $this->view->conf->_theme ($theme); - $this->view->conf->_topline_read ($topline_read); - $this->view->conf->_topline_favorite ($topline_favorite); - $this->view->conf->_topline_date ($topline_date); - $this->view->conf->_topline_link ($topline_link); - $this->view->conf->_bottomline_read ($bottomline_read); - $this->view->conf->_bottomline_favorite ($bottomline_favorite); - $this->view->conf->_bottomline_sharing ($bottomline_sharing); - $this->view->conf->_bottomline_tags ($bottomline_tags); - $this->view->conf->_bottomline_date ($bottomline_date); - $this->view->conf->_bottomline_link ($bottomline_link); - - $values = array ( - 'language' => $this->view->conf->language (), - 'posts_per_page' => $this->view->conf->postsPerPage (), - 'view_mode' => $this->view->conf->viewMode (), - 'default_view' => $this->view->conf->defaultView (), - 'auto_load_more' => $this->view->conf->autoLoadMore (), - 'display_posts' => $this->view->conf->displayPosts (), - 'onread_jump_next' => $this->view->conf->onread_jump_next (), - 'lazyload' => $this->view->conf->lazyload (), - 'sort_order' => $this->view->conf->sortOrder (), - 'old_entries' => $this->view->conf->oldEntries (), - 'mail_login' => $this->view->conf->mailLogin (), - 'anon_access' => $this->view->conf->anonAccess (), - 'token' => $this->view->conf->token (), - 'mark_when' => $this->view->conf->markWhen (), - 'theme' => $this->view->conf->theme (), - 'topline_read' => $this->view->conf->toplineRead () ? 'yes' : 'no', - 'topline_favorite' => $this->view->conf->toplineFavorite () ? 'yes' : 'no', - 'topline_date' => $this->view->conf->toplineDate () ? 'yes' : 'no', - 'topline_link' => $this->view->conf->toplineLink () ? 'yes' : 'no', - 'bottomline_read' => $this->view->conf->bottomlineRead () ? 'yes' : 'no', - 'bottomline_favorite' => $this->view->conf->bottomlineFavorite () ? 'yes' : 'no', - 'bottomline_sharing' => $this->view->conf->bottomlineSharing () ? 'yes' : 'no', - 'bottomline_tags' => $this->view->conf->bottomlineTags () ? 'yes' : 'no', - 'bottomline_date' => $this->view->conf->bottomlineDate () ? 'yes' : 'no', - 'bottomline_link' => $this->view->conf->bottomlineLink () ? 'yes' : 'no', - ); - - $confDAO = new FreshRSS_ConfigurationDAO (); - $confDAO->update ($values); - Minz_Session::_param ('conf', $this->view->conf); - Minz_Session::_param ('mail', $this->view->conf->mailLogin ()); - - Minz_Session::_param ('language', $this->view->conf->language ()); - Minz_Translate::reset (); - - // notif - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('configuration_updated') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward (array ('c' => 'configure', 'a' => 'display'), true); - } - - $this->view->themes = FreshRSS_Themes::get(); - - Minz_View::prependTitle (Minz_Translate::t ('general_and_reading_management') . ' - '); - - $entryDAO = new FreshRSS_EntryDAO (); - $this->view->nb_total = $entryDAO->count (); - $this->view->size_total = $entryDAO->size (); - } - - public function sharingAction () { - if (Minz_Request::isPost ()) { - $this->view->conf->_sharing (array ( - 'shaarli' => Minz_Request::param ('shaarli', ''), - 'poche' => Minz_Request::param ('poche', ''), - 'diaspora' => Minz_Request::param ('diaspora', ''), - 'twitter' => Minz_Request::param ('twitter', 'no') === 'yes', - 'g+' => Minz_Request::param ('g+', 'no') === 'yes', - 'facebook' => Minz_Request::param ('facebook', 'no') === 'yes', - 'email' => Minz_Request::param ('email', 'no') === 'yes', - 'print' => Minz_Request::param ('print', 'no') === 'yes' - )); - - $confDAO = new FreshRSS_ConfigurationDAO (); - $confDAO->update ($this->view->conf->sharing ()); - Minz_Session::_param ('conf', $this->view->conf); - - // notif - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('configuration_updated') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward (array ('c' => 'configure', 'a' => 'sharing'), true); - } - - Minz_View::prependTitle (Minz_Translate::t ('sharing_management') . ' - '); - - $entryDAO = new FreshRSS_EntryDAO (); - $this->view->nb_total = $entryDAO->count (); - } - - public function importExportAction () { - $catDAO = new FreshRSS_CategoryDAO (); - $this->view->categories = $catDAO->listCategories (); - - $this->view->req = Minz_Request::param ('q'); - - if ($this->view->req == 'export') { - Minz_View::_title ('freshrss_feeds.opml'); - - $this->view->_useLayout (false); - header('Content-Type: application/xml; charset=utf-8'); - header('Content-disposition: attachment; filename=freshrss_feeds.opml'); - - $feedDAO = new FreshRSS_FeedDAO (); - $catDAO = new FreshRSS_CategoryDAO (); - - $list = array (); - foreach ($catDAO->listCategories () as $key => $cat) { - $list[$key]['name'] = $cat->name (); - $list[$key]['feeds'] = $feedDAO->listByCategory ($cat->id ()); - } - - $this->view->categories = $list; - } elseif ($this->view->req == 'import' && Minz_Request::isPost ()) { - if ($_FILES['file']['error'] == 0) { - // on parse le fichier OPML pour récupérer les catégories et les flux associés - try { - list ($categories, $feeds) = opml_import ( - file_get_contents ($_FILES['file']['tmp_name']) - ); - - // On redirige vers le controller feed qui va se charger d'insérer les flux en BDD - // les flux sont mis au préalable dans des variables de Request - Minz_Request::_param ('q', 'null'); - Minz_Request::_param ('categories', $categories); - Minz_Request::_param ('feeds', $feeds); - Minz_Request::forward (array ('c' => 'feed', 'a' => 'massiveImport')); - } catch (FreshRSS_Opml_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('bad_opml_file') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward (array ( - 'c' => 'configure', - 'a' => 'importExport' - ), true); - } - } - } - - $feedDAO = new FreshRSS_FeedDAO (); - $this->view->feeds = $feedDAO->listFeeds (); - - // au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste - $this->view->flux = false; - - Minz_View::prependTitle (Translate::t ('import_export_opml') . ' - '); - } - - public function shortcutAction () { - $list_keys = array ('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter', - 'escape', 'f', 'g', 'h', 'i', 'insert', 'j', 'k', 'l', 'left', - 'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right', - 's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y', - 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', - 'f10', 'f11', 'f12'); - $this->view->list_keys = $list_keys; - $list_names = array ('mark_read', 'mark_favorite', 'go_website', 'next_entry', - 'prev_entry', 'next_page', 'prev_page', 'collapse_entry', - 'load_more'); - - if (Minz_Request::isPost ()) { - $shortcuts = Minz_Request::param ('shortcuts'); - $shortcuts_ok = array (); - - foreach ($shortcuts as $key => $value) { - if (in_array ($key, $list_names) - && in_array ($value, $list_keys)) { - $shortcuts_ok[$key] = $value; - } - } - - $this->view->conf->_shortcuts ($shortcuts_ok); - - $values = array ( - 'shortcuts' => $this->view->conf->shortcuts () - ); - - $confDAO = new FreshRSS_ConfigurationDAO (); - $confDAO->update ($values); - Minz_Session::_param ('conf', $this->view->conf); - - // notif - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('shortcuts_updated') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward (array ('c' => 'configure', 'a' => 'shortcut'), true); - } - - Minz_View::prependTitle (Minz_Translate::t ('shortcuts_management') . ' - '); - } -} diff --git a/app/controllers/entryController.php b/app/controllers/entryController.php deleted file mode 100755 index a332ca8a9..000000000 --- a/app/controllers/entryController.php +++ /dev/null @@ -1,112 +0,0 @@ -view->conf) && !is_logged ()) { - Minz_Error::error ( - 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) - ); - } - - $this->params = array (); - $this->redirect = false; - $ajax = Minz_Request::param ('ajax'); - if ($ajax) { - $this->view->_useLayout (false); - } - } - public function lastAction () { - $ajax = Minz_Request::param ('ajax'); - if (!$ajax && $this->redirect) { - Minz_Request::forward (array ( - 'c' => 'index', - 'a' => 'index', - 'params' => $this->params - ), true); - } else { - Minz_Request::_param ('ajax'); - } - } - - public function readAction () { - $this->redirect = true; - - $id = Minz_Request::param ('id'); - $is_read = Minz_Request::param ('is_read'); - $get = Minz_Request::param ('get'); - $nextGet = Minz_Request::param ('nextGet', $get); - $idMax = Minz_Request::param ('idMax', 0); - - $is_read = !!$is_read; - - $entryDAO = new FreshRSS_EntryDAO (); - if ($id == false) { - if (!$get) { - $entryDAO->markReadEntries ($idMax); - } else { - $typeGet = $get[0]; - $get = substr ($get, 2); - switch ($typeGet) { - case 'c': - $entryDAO->markReadCat ($get, $idMax); - break; - case 'f': - $entryDAO->markReadFeed ($get, $idMax); - break; - case 's': - $entryDAO->markReadEntries ($idMax, true); - break; - case 'a': - $entryDAO->markReadEntries ($idMax); - break; - } - if ($nextGet !== 'a') { - $this->params = array ('get' => $nextGet); - } - } - - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_marked_read') - ); - Minz_Session::_param ('notification', $notif); - } else { - $entryDAO->markRead ($id, $is_read); - } - } - - public function bookmarkAction () { - $this->redirect = true; - - $id = Minz_Request::param ('id'); - if ($id) { - $entryDAO = new FreshRSS_EntryDAO (); - $entryDAO->markFavorite ($id, Minz_Request::param ('is_favorite')); - } - } - - public function optimizeAction() { - @set_time_limit(300); - invalidateHttpCache(); - - // La table des entrées a tendance à grossir énormément - // Cette action permet d'optimiser cette table permettant de grapiller un peu de place - // Cette fonctionnalité n'est à appeler qu'occasionnellement - $entryDAO = new FreshRSS_EntryDAO(); - $entryDAO->optimizeTable(); - - invalidateHttpCache(); - - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('optimization_complete') - ); - Minz_Session::_param ('notification', $notif); - - Minz_Request::forward(array( - 'c' => 'configure', - 'a' => 'display' - ), true); - } -} diff --git a/app/controllers/errorController.php b/app/controllers/errorController.php deleted file mode 100644 index d1c2f8fec..000000000 --- a/app/controllers/errorController.php +++ /dev/null @@ -1,26 +0,0 @@ -view->code = 'Error 403 - Forbidden'; - break; - case 404: - $this->view->code = 'Error 404 - Not found'; - break; - case 500: - $this->view->code = 'Error 500 - Internal Server Error'; - break; - case 503: - $this->view->code = 'Error 503 - Service Unavailable'; - break; - default: - $this->view->code = 'Error 404 - Not found'; - } - - $this->view->logs = Minz_Request::param ('logs'); - - Minz_View::prependTitle ($this->view->code . ' - '); - } -} diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php deleted file mode 100755 index a85877724..000000000 --- a/app/controllers/feedController.php +++ /dev/null @@ -1,428 +0,0 @@ -view->conf->token(); - $token_param = Minz_Request::param ('token', ''); - $token_is_ok = ($token != '' && $token == $token_param); - $action = Minz_Request::actionName (); - - if (login_is_conf ($this->view->conf) && - !is_logged () && - !($token_is_ok && $action == 'actualize')) { - Minz_Error::error ( - 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) - ); - } - - $this->catDAO = new FreshRSS_CategoryDAO (); - $this->catDAO->checkDefault (); - } - - private static function entryDateComparer($e1, $e2) { - $d1 = $e1->date(true); - $d2 = $e2->date(true); - if ($d1 === $d2) { - return 0; - } - return ($d1 < $d2) ? -1 : 1; - } - - public function addAction () { - @set_time_limit(300); - - if (Minz_Request::isPost ()) { - $url = Minz_Request::param ('url_rss'); - $cat = Minz_Request::param ('category', false); - if ($cat === false) { - $def_cat = $this->catDAO->getDefault (); - $cat = $def_cat->id (); - } - - $user = Minz_Request::param ('username'); - $pass = Minz_Request::param ('password'); - $params = array (); - - $transactionStarted = false; - try { - $feed = new FreshRSS_Feed ($url); - $feed->_category ($cat); - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - $feed->_httpAuth ($httpAuth); - - $feed->load (); - - $feedDAO = new FreshRSS_FeedDAO (); - $values = array ( - 'url' => $feed->url (), - 'category' => $feed->category (), - 'name' => $feed->name (), - 'website' => $feed->website (), - 'description' => $feed->description (), - 'lastUpdate' => time (), - 'httpAuth' => $feed->httpAuth (), - ); - - if ($feedDAO->searchByUrl ($values['url'])) { - // on est déjà abonné à ce flux - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) - ); - Minz_Session::_param ('notification', $notif); - } else { - $id = $feedDAO->addFeed ($values); - if (!$id) { - // problème au niveau de la base de données - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) - ); - Minz_Session::_param ('notification', $notif); - } else { - $feed->_id ($id); - $feed->faviconPrepare(); - - $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; - - $entryDAO = new FreshRSS_EntryDAO (); - $entries = $feed->entries (); - usort($entries, 'self::entryDateComparer'); - - // on calcule la date des articles les plus anciens qu'on accepte - $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); - - $transactionStarted = true; - $feedDAO->beginTransaction (); - // on ajoute les articles en masse sans vérification - foreach ($entries as $entry) { - if ($entry->date (true) >= $date_min || - $feed->keepHistory ()) { - $values = $entry->toArray (); - $values['id_feed'] = $feed->id (); - $values['id'] = min(time(), $entry->date (true)) . uSecString(); - $values['is_read'] = $is_read; - $entryDAO->addEntry ($values); - } - } - $feedDAO->updateLastUpdate ($feed->id ()); - $feedDAO->commit (); - $transactionStarted = false; - - // ok, ajout terminé - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feed_added', $feed->name ()) - ); - Minz_Session::_param ('notification', $notif); - - // permet de rediriger vers la page de conf du flux - $params['id'] = $feed->id (); - } - } - } catch (FreshRSS_BadUrl_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('invalid_url', $url) - ); - Minz_Session::_param ('notification', $notif); - } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed') - ); - Minz_Session::_param ('notification', $notif); - } catch (Minz_FileNotExistException $e) { - // Répertoire de cache n'existe pas - Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed') - ); - Minz_Session::_param ('notification', $notif); - } - if ($transactionStarted) { - $feedDAO->rollBack (); - } - - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); - } - } - - public function truncateAction () { - if (Minz_Request::isPost ()) { - $id = Minz_Request::param ('id'); - $feedDAO = new FreshRSS_FeedDAO (); - $n = $feedDAO->truncate($id); - $notif = array( - 'type' => $n === false ? 'bad' : 'good', - 'content' => Minz_Translate::t ('n_entries_deleted', $n) - ); - Minz_Session::_param ('notification', $notif); - invalidateHttpCache(); - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); - } - } - - public function actualizeAction () { - @set_time_limit(300); - - $feedDAO = new FreshRSS_FeedDAO (); - $entryDAO = new FreshRSS_EntryDAO (); - - $id = Minz_Request::param ('id'); - $force = Minz_Request::param ('force', false); - - // on créé la liste des flux à mettre à actualiser - // si on veut mettre un flux à jour spécifiquement, on le met - // dans la liste, mais seul (permet d'automatiser le traitement) - $feeds = array (); - if ($id) { - $feed = $feedDAO->searchById ($id); - if ($feed) { - $feeds = array ($feed); - } - } else { - $feeds = $feedDAO->listFeedsOrderUpdate (); - } - - // on calcule la date des articles les plus anciens qu'on accepte - $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); - - $i = 0; - $flux_update = 0; - foreach ($feeds as $feed) { - try { - $feed->load (); - $feed->faviconPrepare(); - $entries = $feed->entries (); - usort($entries, 'self::entryDateComparer'); - - $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; - - //For this feed, check last n entry GUIDs already in database - $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); - - // On ne vérifie pas strictement que l'article n'est pas déjà en BDD - // La BDD refusera l'ajout car (id_feed, guid) doit être unique - $feedDAO->beginTransaction (); - foreach ($entries as $entry) { - if ((!isset ($existingGuids[$entry->guid ()])) && - ($entry->date (true) >= $date_min || - $feed->keepHistory ())) { - $values = $entry->toArray (); - //Use declared date at first import, otherwise use discovery date - $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString(); - $values['is_read'] = $is_read; - $entryDAO->addEntry ($values); - } - } - - if ((!$feed->keepHistory()) && (rand(0, 30) === 1)) { - $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, count($entries) + 10); - Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); - } - - // on indique que le flux vient d'être mis à jour en BDD - $feedDAO->updateLastUpdate ($feed->id ()); - $feedDAO->commit (); - $flux_update++; - } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); - $feedDAO->updateLastUpdate ($feed->id (), 1); - } - - // On arrête à 10 flux pour ne pas surcharger le serveur - // sauf si le paramètre $force est à vrai - $i++; - if ($i >= 10 && !$force) { - break; - } - } - - $url = array (); - if ($flux_update === 1) { - // on a mis un seul flux à jour - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) - ); - } elseif ($flux_update > 1) { - // plusieurs flux on été mis à jour - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) - ); - } else { - // aucun flux n'a été mis à jour, oups - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('no_feed_actualized') - ); - } - - if ($i === 1) { - // Si on a voulu mettre à jour qu'un flux - // on filtre l'affichage par ce flux - $feed = reset ($feeds); - $url['params'] = array ('get' => 'f_' . $feed->id ()); - } - - if (Minz_Request::param ('ajax', 0) === 0) { - Minz_Session::_param ('notification', $notif); - Minz_Request::forward ($url, true); - } else { - // Une requête Ajax met un seul flux à jour. - // Comme en principe plusieurs requêtes ont lieu, - // on indique que "plusieurs flux ont été mis à jour". - // Cela permet d'avoir une notification plus proche du - // ressenti utilisateur - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_actualized') - ); - Minz_Session::_param ('notification', $notif); - // et on désactive le layout car ne sert à rien - $this->view->_useLayout (false); - } - } - - public function massiveImportAction () { - @set_time_limit(300); - - $entryDAO = new FreshRSS_EntryDAO (); - $feedDAO = new FreshRSS_FeedDAO (); - - $categories = Minz_Request::param ('categories', array (), true); - $feeds = Minz_Request::param ('feeds', array (), true); - - // on ajoute les catégories en masse dans une fonction à part - $this->addCategories ($categories); - - // on calcule la date des articles les plus anciens qu'on accepte - $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); - - // la variable $error permet de savoir si une erreur est survenue - // Le but est de ne pas arrêter l'import même en cas d'erreur - // L'utilisateur sera mis au courant s'il y a eu des erreurs, mais - // ne connaîtra pas les détails. Ceux-ci seront toutefois logguées - $error = false; - $i = 0; - foreach ($feeds as $feed) { - try { - $values = array ( - 'id' => $feed->id (), - 'url' => $feed->url (), - 'category' => $feed->category (), - 'name' => $feed->name (), - 'website' => $feed->website (), - 'description' => $feed->description (), - 'lastUpdate' => 0, - 'httpAuth' => $feed->httpAuth () - ); - - // ajout du flux que s'il n'est pas déjà en BDD - if (!$feedDAO->searchByUrl ($values['url'])) { - $id = $feedDAO->addFeed ($values); - if ($id) { - $feed->_id ($id); - $feed->faviconPrepare(); - } else { - $error = true; - } - } - } catch (FreshRSS_Feed_Exception $e) { - $error = true; - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - } - } - - if ($error) { - $res = Minz_Translate::t ('feeds_imported_with_errors'); - } else { - $res = Minz_Translate::t ('feeds_imported'); - } - - $notif = array ( - 'type' => 'good', - 'content' => $res - ); - Minz_Session::_param ('notification', $notif); - Minz_Session::_param ('actualize_feeds', true); - - // et on redirige vers la page d'accueil - Minz_Request::forward (array ( - 'c' => 'index', - 'a' => 'index' - ), true); - } - - public function deleteAction () { - if (Minz_Request::isPost ()) { - $type = Minz_Request::param ('type', 'feed'); - $id = Minz_Request::param ('id'); - - $feedDAO = new FreshRSS_FeedDAO (); - if ($type == 'category') { - if ($feedDAO->deleteFeedByCategory ($id)) { - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('category_emptied') - ); - //TODO: Delete old favicons - } else { - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('error_occured') - ); - } - } else { - if ($feedDAO->deleteFeed ($id)) { - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feed_deleted') - ); - Feed::faviconDelete($id); - } else { - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('error_occured') - ); - } - } - - Minz_Session::_param ('notification', $notif); - - if ($type == 'category') { - Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); - } else { - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); - } - } - } - - private function addCategories ($categories) { - $catDAO = new FreshRSS_CategoryDAO (); - - foreach ($categories as $cat) { - if (!$catDAO->searchByName ($cat->name ())) { - $values = array ( - 'id' => $cat->id (), - 'name' => $cat->name (), - 'color' => $cat->color () - ); - $catDAO->addCategory ($values); - } - } - } -} diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php deleted file mode 100755 index 92070590a..000000000 --- a/app/controllers/indexController.php +++ /dev/null @@ -1,277 +0,0 @@ -entryDAO = new FreshRSS_EntryDAO (); - $this->feedDAO = new FreshRSS_FeedDAO (); - $this->catDAO = new FreshRSS_CategoryDAO (); - } - - public function indexAction () { - $output = Minz_Request::param ('output'); - - $token = $this->view->conf->token(); - $token_param = Minz_Request::param ('token', ''); - $token_is_ok = ($token != '' && $token === $token_param); - - // check if user is log in - if(login_is_conf ($this->view->conf) && - !is_logged() && - $this->view->conf->anonAccess() === 'no' && - !($output === 'rss' && $token_is_ok)) { - return; - } - - // construction of RSS url of this feed - $params = Minz_Request::params (); - $params['output'] = 'rss'; - if (isset ($params['search'])) { - $params['search'] = urlencode ($params['search']); - } - if (login_is_conf($this->view->conf) && - $this->view->conf->anonAccess() === 'no' && - $token != '') { - $params['token'] = $token; - } - $this->view->rss_url = array ( - 'c' => 'index', - 'a' => 'index', - 'params' => $params - ); - - if ($output === 'rss') { - // no layout for RSS output - $this->view->_useLayout (false); - header('Content-Type: application/rss+xml; charset=utf-8'); - } else { - Minz_View::appendScript (Minz_Url::display ('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); - - if ($output === 'global') { - Minz_View::appendScript (Minz_Url::display ('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); - } - } - - $this->view->cat_aside = $this->catDAO->listCategories (); - $this->view->nb_favorites = $this->entryDAO->countUnreadReadFavorites (); - $this->view->currentName = ''; - - $this->view->get_c = ''; - $this->view->get_f = ''; - - $get = Minz_Request::param ('get', 'a'); - $getType = $get[0]; - $getId = substr ($get, 2); - if (!$this->checkAndProcessType ($getType, $getId)) { - Minz_Log::record ('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); - Minz_Error::error ( - 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) - ); - return; - } - - $this->view->nb_not_read = HelperCategory::CountUnreads($this->view->cat_aside, 1); - - // mise à jour des titres - $this->view->rss_title = $this->view->currentName . ' | ' . Minz_View::title(); - if ($this->view->nb_not_read > 0) { - Minz_View::appendTitle (' (' . $this->view->nb_not_read . ')'); - } - Minz_View::prependTitle ( - $this->view->currentName . - ($this->nb_not_read_cat > 0 ? ' (' . $this->nb_not_read_cat . ')' : '') . - ' - ' - ); - - // On récupère les différents éléments de filtrage - $this->view->state = $state = Minz_Request::param ('state', $this->view->conf->defaultView ()); - $filter = Minz_Request::param ('search', ''); - if (!empty($filter)) { - $state = 'all'; //Search always in read and unread articles - } - $this->view->order = $order = Minz_Request::param ('order', $this->view->conf->sortOrder ()); - $nb = Minz_Request::param ('nb', $this->view->conf->postsPerPage ()); - $first = Minz_Request::param ('next', ''); - - if ($state === 'not_read') { //Any unread article in this category at all? - switch ($getType) { - case 'a': - $hasUnread = $this->view->nb_not_read > 0; - break; - case 's': - $hasUnread = $this->view->nb_favorites['unread'] > 0; - break; - case 'c': - $hasUnread = (!isset($this->view->cat_aside[$getId])) || ($this->view->cat_aside[$getId]->nbNotRead() > 0); - break; - case 'f': - $myFeed = HelperCategory::findFeed($this->view->cat_aside, $getId); - $hasUnread = ($myFeed === null) || ($myFeed->nbNotRead() > 0); - break; - default: - $hasUnread = true; - break; - } - if (!$hasUnread) { - $this->view->state = $state = 'all'; - } - } - - // on calcule la date des articles les plus anciens qu'on affiche - $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); - - try { - $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min); - - // Si on a récupéré aucun article "non lus" - // on essaye de récupérer tous les articles - if ($state === 'not_read' && empty($entries)) { //TODO: Remove in v0.8 - Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); - $this->view->state = 'all'; - $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min); - } - - if (count($entries) <= $nb) { - $this->view->nextId = ''; - } else { //We have more elements for pagination - $lastEntry = array_pop($entries); - $this->view->nextId = $lastEntry->id(); - } - - $this->view->entries = $entries; - } catch (FreshRSS_EntriesGetter_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); - Minz_Error::error ( - 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) - ); - } - } - - /* - * Vérifie que la catégorie / flux sélectionné existe - * + Initialise correctement les variables de vue get_c et get_f - * + Met à jour la variable $this->nb_not_read_cat - */ - private function checkAndProcessType ($getType, $getId) { - switch ($getType) { - case 'a': - $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); - $this->view->get_c = $getType; - return true; - case 's': - $this->view->currentName = Minz_Translate::t ('your_favorites'); - $this->view->get_c = $getType; - return true; - case 'c': - $cat = isset($this->view->cat_aside[$getId]) ? $this->view->cat_aside[$getId] : null; - if ($cat === null) { - $cat = $this->catDAO->searchById ($getId); - } - if ($cat) { - $this->view->currentName = $cat->name (); - $this->nb_not_read_cat = $cat->nbNotRead (); - $this->view->get_c = $getId; - return true; - } else { - return false; - } - case 'f': - $feed = HelperCategory::findFeed($this->view->cat_aside, $getId); - if (empty($feed)) { - $feed = $this->feedDAO->searchById ($getId); - } - if ($feed) { - $this->view->currentName = $feed->name (); - $this->nb_not_read_cat = $feed->nbNotRead (); - $this->view->get_f = $getId; - $this->view->get_c = $feed->category (); - return true; - } else { - return false; - } - default: - return false; - } - } - - public function aboutAction () { - Minz_View::prependTitle (Minz_Translate::t ('about') . ' - '); - } - - public function logsAction () { - if (login_is_conf ($this->view->conf) && !is_logged ()) { - Minz_Error::error ( - 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) - ); - } - - Minz_View::prependTitle (Minz_Translate::t ('logs') . ' - '); - - if (Minz_Request::isPost ()) { - file_put_contents(LOG_PATH . '/application.log', ''); - } - - $logs = array(); - try { - $logDAO = new FreshRSS_LogDAO (); - $logs = $logDAO->lister (); - $logs = array_reverse ($logs); - } catch (Minz_FileNotExistException $e) { - - } - - //gestion pagination - $page = Minz_Request::param ('page', 1); - $this->view->logsPaginator = new Minz_Paginator ($logs); - $this->view->logsPaginator->_nbItemsPerPage (50); - $this->view->logsPaginator->_currentPage ($page); - } - - public function loginAction () { - $this->view->_useLayout (false); - - $url = 'https://verifier.login.persona.org/verify'; - $assert = Minz_Request::param ('assertion'); - $params = 'assertion=' . $assert . '&audience=' . - urlencode (Minz_Url::display (null, 'php', true)); - $ch = curl_init (); - $options = array ( - CURLOPT_URL => $url, - CURLOPT_RETURNTRANSFER => TRUE, - CURLOPT_POST => 2, - CURLOPT_POSTFIELDS => $params - ); - curl_setopt_array ($ch, $options); - $result = curl_exec ($ch); - curl_close ($ch); - - $res = json_decode ($result, true); - if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mailLogin ()) { - Minz_Session::_param ('mail', $res['email']); - invalidateHttpCache(); - } else { - $res = array (); - $res['status'] = 'failure'; - $res['reason'] = Minz_Translate::t ('invalid_login'); - } - - header('Content-Type: application/json; charset=UTF-8'); - $this->view->res = json_encode ($res); - } - - public function logoutAction () { - $this->view->_useLayout (false); - Minz_Session::_param ('mail'); - invalidateHttpCache(); - } -} diff --git a/app/controllers/javascriptController.php b/app/controllers/javascriptController.php deleted file mode 100755 index e7e25f656..000000000 --- a/app/controllers/javascriptController.php +++ /dev/null @@ -1,13 +0,0 @@ -view->_useLayout (false); - header('Content-type: text/javascript'); - } - - public function actualizeAction () { - $feedDAO = new FreshRSS_FeedDAO (); - $this->view->feeds = $feedDAO->listFeeds (); - } -} -- cgit v1.2.3 From ce3801e5acf22e64cb53cfad21ced1b962674a91 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 12:17:20 +0100 Subject: Message debug nettoyage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message dans le log uniquement lorsque des articles ont été supprimés https://github.com/marienfressinaud/FreshRSS/issues/323 --- app/Controllers/feedController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index a85877724..18476d559 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -229,7 +229,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ((!$feed->keepHistory()) && (rand(0, 30) === 1)) { $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, count($entries) + 10); - Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); + if ($nb > 0) { + Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); + } } // on indique que le flux vient d'être mis à jour en BDD -- cgit v1.2.3 From a2421185d0bc9a0e177b6ecbf98bb17086d43386 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 16:01:37 +0100 Subject: SQL : Petite amélioration de la requête principale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En particulier pour les favoris, où cela évite une jointure. --- app/Models/EntryDAO.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 1bce6cbf2..f80fe9b77 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -261,20 +261,23 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { $where = ''; + $joinFeed = false; $values = array(); switch ($type) { case 'a': - $where .= 'priority > 0 '; + $where .= 'f.priority > 0 '; + $joinFeed = true; break; case 's': - $where .= 'is_favorite = 1 '; + $where .= 'e.is_favorite = 1 '; break; case 'c': - $where .= 'category = ? '; + $where .= 'f.category = ? '; $values[] = intval($id); + $joinFeed = true; break; case 'f': - $where .= 'id_feed = ? '; + $where .= 'e.id_feed = ? '; $values[] = intval($id); break; default: @@ -284,10 +287,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { case 'all': break; case 'not_read': - $where .= 'AND is_read = 0 '; + $where .= 'AND e.is_read = 0 '; break; case 'read': - $where .= 'AND is_read = 1 '; + $where .= 'AND e.is_read = 1 '; break; default: throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!'); @@ -302,8 +305,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($firstId !== '') { $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } - if ($date_min > 0) { + if (($date_min > 0) && ($type !== 's')) { $where .= 'AND (e.id >= ' . $date_min . '000000 OR e.is_favorite = 1 OR f.keep_history = 1) '; + $joinFeed = true; } $terms = array_unique(explode(' ', trim($filter))); sort($terms); //Put #tags first @@ -311,7 +315,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { foreach ($terms as $word) { if (!empty($word)) { if ($word[0] === '#' && isset($word[1])) { - $having .= 'AND tags LIKE ? '; + $having .= 'AND e.tags LIKE ? '; $values[] = '%' . $word .'%'; } elseif (!empty($word)) { $having .= 'AND (e.title LIKE ? OR content LIKE ?) '; @@ -323,7 +327,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' . 'FROM `' . $this->prefix . 'entry` e ' - . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE ' . $where + . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' : '') + . 'WHERE ' . $where . (empty($having) ? '' : 'HAVING' . substr($having, 3)) . 'ORDER BY e.id ' . $order; -- cgit v1.2.3 From 529d6bcd15f7351cb7bdcf2f74c6a44930b0de55 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 00:50:24 +0100 Subject: SQL : performances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tentative de reformulation de la requête principale pour améliorer les performances. Utilisation d'une sous-jointure qui retourne uniquement e.id. Sur mon serveur avec 13000 articles, la requête de la page d'accueil sans article non lu mettait 1.38s avant le patch, contre 0.08s après (en désactivant bien sûr le cache SQL). Il faudra re-tester et tenter d'autres optimisations (notamment sur les index) avec un nombre d'articles plus important. Avant : SELECT SQL_NO_CACHE e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags FROM `freshrss_alex_entry` e INNER JOIN `freshrss_alex_feed` f ON e.id_feed = f.id WHERE f.priority > 0 AND (e.id >= 1371597014000000 OR e.is_favorite = 1 OR f.keep_history = 1) ORDER BY e.id DESC LIMIT 33; Après : SELECT SQL_NO_CACHE e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags FROM `freshrss_alex_entry` e INNER JOIN (SELECT e1.id FROM `freshrss_alex_entry` e1 INNER JOIN `freshrss_alex_feed` f ON e1.id_feed = f.id WHERE f.priority > 0 AND (e1.id >= 1371597014000000 OR e1.is_favorite = 1 OR f.keep_history = 1) ORDER BY e1.id DESC LIMIT 33) e2 ON e2.id = e.id ORDER BY e.id DESC; --- app/Controllers/indexController.php | 4 +++- app/Models/EntryDAO.php | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 92070590a..cc474302e 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -124,9 +124,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } + $today = @strtotime('today'); + // on calcule la date des articles les plus anciens qu'on affiche $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); + $date_min = $today - (3600 * 24 * 30 * $nb_month_old); //Do not use a fast changing value such as time() to allow SQL caching try { $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index f80fe9b77..5a34573db 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -269,7 +269,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $joinFeed = true; break; case 's': - $where .= 'e.is_favorite = 1 '; + $where .= 'e1.is_favorite = 1 '; break; case 'c': $where .= 'f.category = ? '; @@ -277,7 +277,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $joinFeed = true; break; case 'f': - $where .= 'e.id_feed = ? '; + $where .= 'e1.id_feed = ? '; $values[] = intval($id); break; default: @@ -287,10 +287,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { case 'all': break; case 'not_read': - $where .= 'AND e.is_read = 0 '; + $where .= 'AND e1.is_read = 0 '; break; case 'read': - $where .= 'AND e.is_read = 1 '; + $where .= 'AND e1.is_read = 1 '; break; default: throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!'); @@ -303,10 +303,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { throw new FreshRSS_EntriesGetter_Exception ('Bad order in Entry->listByType: [' . $order . ']!'); } if ($firstId !== '') { - $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; + $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e.id >= ' . $date_min . '000000 OR e.is_favorite = 1 OR f.keep_history = 1) '; + $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR f.keep_history = 1) '; $joinFeed = true; } $terms = array_unique(explode(' ', trim($filter))); @@ -315,10 +315,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { foreach ($terms as $word) { if (!empty($word)) { if ($word[0] === '#' && isset($word[1])) { - $having .= 'AND e.tags LIKE ? '; + $having .= 'AND e1.tags LIKE ? '; $values[] = '%' . $word .'%'; } elseif (!empty($word)) { - $having .= 'AND (e.title LIKE ? OR content LIKE ?) '; + $having .= 'AND (e1.title LIKE ? OR content LIKE ?) '; $values[] = '%' . $word .'%'; $values[] = '%' . $word .'%'; } @@ -327,15 +327,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' . 'FROM `' . $this->prefix . 'entry` e ' - . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' : '') - . 'WHERE ' . $where - . (empty($having) ? '' : 'HAVING' . substr($having, 3)) + . 'INNER JOIN (SELECT e1.id FROM `' . $this->prefix . 'entry` e1 ' + . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '') + . 'WHERE ' . $where + . (empty($having) ? '' : 'HAVING' . substr($having, 3)) + . 'ORDER BY e1.id ' . $order + . ($limit > 0 ? ' LIMIT ' . $limit : '') //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ + . ') e2 ON e2.id = e.id ' . 'ORDER BY e.id ' . $order; - if ($limit > 0) { - $sql .= ' LIMIT ' . $limit; //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ - } - $stm = $this->bd->prepare ($sql); $stm->execute ($values); -- cgit v1.2.3 From 847de9b3292ad854b281d7e12cc36ac93e745139 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 00:54:13 +0100 Subject: PHP : performances fonction isDay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amélioration des performances de Entry->isDay() --- app/Controllers/indexController.php | 1 + app/Models/Entry.php | 27 +++++++++++++-------------- app/layout/nav_menu.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 7 ++++--- 4 files changed, 19 insertions(+), 18 deletions(-) (limited to 'app') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index cc474302e..22c5683ea 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -125,6 +125,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } $today = @strtotime('today'); + $this->view->today = $today; // on calcule la date des articles les plus anciens qu'on affiche $nb_month_old = $this->view->conf->oldEntries (); diff --git a/app/Models/Entry.php b/app/Models/Entry.php index ba0fb48f4..983f94727 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -134,21 +134,20 @@ class FreshRSS_Entry extends Minz_Model { $this->tags = $value; } - public function isDay ($day) { + public function isDay ($day, $today) { $date = $this->dateAdded(true); - $today = @strtotime('today'); - $yesterday = $today - 86400; - - if ($day === FreshRSS_Days::TODAY && - $date >= $today && $date < $today + 86400) { - return true; - } elseif ($day === FreshRSS_Days::YESTERDAY && - $date >= $yesterday && $date < $yesterday + 86400) { - return true; - } elseif ($day === FreshRSS_Days::BEFORE_YESTERDAY && $date < $yesterday) { - return true; - } else { - return false; + switch ($day) { + case FreshRSS_Days::TODAY: + $tomorrow = $today + 86400; + return $date >= $today && $date < $tomorrow; + case FreshRSS_Days::YESTERDAY: + $yesterday = $today - 86400; + return $date >= $yesterday && $date < $today; + case FreshRSS_Days::BEFORE_YESTERDAY: + $yesterday = $today - 86400; + return $date < $yesterday; + default: + return false; } } diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 92a987aed..045f391f9 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -72,7 +72,7 @@
  • today; $one_week = $today - 604800; ?>
  • diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 094017957..d5328651d 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -21,24 +21,25 @@ if (!empty($this->entries)) { $facebook = $this->conf->sharing ('facebook'); $email = $this->conf->sharing ('email'); $print = $this->conf->sharing ('print'); + $today = $this->today; ?> entries as $item) { ?> - isDay (FreshRSS_Days::TODAY)) { ?> + isDay (FreshRSS_Days::TODAY, $today)) { ?>
    - currentName; ?>
    - isDay (FreshRSS_Days::YESTERDAY)) { ?> + isDay (FreshRSS_Days::YESTERDAY, $today)) { ?>
    - currentName; ?>
    - isDay (FreshRSS_Days::BEFORE_YESTERDAY)) { ?> + isDay (FreshRSS_Days::BEFORE_YESTERDAY, $today)) { ?>
    currentName; ?> -- cgit v1.2.3 From 8abeeaf65e79a464aae6d40f8868ecd29889df4c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 17:45:57 +0100 Subject: SQL : correction recherche MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oups, mon précédent changement SQL avait cassé la recherche. Patch rapide en attendant une ré-optimisation en particulier pour le cas de recherche sur plusieurs mots --- app/Models/EntryDAO.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 5a34573db..c4eb0a84a 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -311,14 +311,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } $terms = array_unique(explode(' ', trim($filter))); sort($terms); //Put #tags first - $having = ''; + $search = ''; foreach ($terms as $word) { if (!empty($word)) { if ($word[0] === '#' && isset($word[1])) { - $having .= 'AND e1.tags LIKE ? '; + $search .= 'AND e1.tags LIKE ? '; $values[] = '%' . $word .'%'; } elseif (!empty($word)) { - $having .= 'AND (e1.title LIKE ? OR content LIKE ?) '; + $search .= 'AND (e1.title LIKE ? OR UNCOMPRESS(e1.content_bin) LIKE ?) '; $values[] = '%' . $word .'%'; $values[] = '%' . $word .'%'; } @@ -330,7 +330,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . 'INNER JOIN (SELECT e1.id FROM `' . $this->prefix . 'entry` e1 ' . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '') . 'WHERE ' . $where - . (empty($having) ? '' : 'HAVING' . substr($having, 3)) + . $search . 'ORDER BY e1.id ' . $order . ($limit > 0 ? ' LIMIT ' . $limit : '') //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ . ') e2 ON e2.id = e.id ' -- cgit v1.2.3 From a1f8bade6176f03a6e2399d5de24975bb47d09d6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 21:58:47 +0100 Subject: SQL : petits changement recherche MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Traite mieux les caractères spéciaux. Permet par exemple une recherche sur des mots contenant des apostrophes, ou le signe pourcentage, etc. Il faudra toujours essayer d'améliorer la recherche en particulier lorsque plusieurs mots sont fournis --- app/Models/EntryDAO.php | 28 +++++++++++++++++----------- lib/Minz/Request.php | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c4eb0a84a..2af511527 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -309,18 +309,24 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR f.keep_history = 1) '; $joinFeed = true; } - $terms = array_unique(explode(' ', trim($filter))); - sort($terms); //Put #tags first $search = ''; - foreach ($terms as $word) { - if (!empty($word)) { - if ($word[0] === '#' && isset($word[1])) { - $search .= 'AND e1.tags LIKE ? '; - $values[] = '%' . $word .'%'; - } elseif (!empty($word)) { - $search .= 'AND (e1.title LIKE ? OR UNCOMPRESS(e1.content_bin) LIKE ?) '; - $values[] = '%' . $word .'%'; - $values[] = '%' . $word .'%'; + if ($filter !== '') { + $filter = trim($filter); + $filter = addcslashes($filter, '\\%_'); + $terms = array_unique(explode(' ', $filter)); + sort($terms); //Put #tags first + foreach ($terms as $word) { + $word = trim($word); + if (strlen($word) > 0) { + if ($word[0] === '#') { + if (isset($word[1])) { + $search .= 'AND e1.tags LIKE ? '; + $values[] = '%' . $word .'%'; + } + } else { + $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? '; + $values[] = '%' . $word .'%'; + } } } } diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index c8ffa4a42..fb48bd7a2 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -30,7 +30,7 @@ class Minz_Request { return self::$params; } static function htmlspecialchars_utf8 ($p) { - return htmlspecialchars($p, ENT_QUOTES, 'UTF-8'); + return htmlspecialchars($p, ENT_COMPAT, 'UTF-8'); } public static function param ($key, $default = false, $specialchars = false) { if (isset (self::$params[$key])) { -- cgit v1.2.3 From ba71d7747a8b0847ad59ff56870378b341c5171d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 22:03:16 +0100 Subject: SQL : permet recherche du caractère dièse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/EntryDAO.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 2af511527..d1f595d42 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -318,11 +318,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { foreach ($terms as $word) { $word = trim($word); if (strlen($word) > 0) { - if ($word[0] === '#') { - if (isset($word[1])) { - $search .= 'AND e1.tags LIKE ? '; - $values[] = '%' . $word .'%'; - } + if ($word[0] === '#' && isset($word[1])) { + $search .= 'AND e1.tags LIKE ? '; + $values[] = '%' . $word .'%'; } else { $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? '; $values[] = '%' . $word .'%'; -- cgit v1.2.3 From e29be10556e1994083bce7398eee0a3edc017a9d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 16 Dec 2013 22:22:56 +0100 Subject: Recherches spéciales intitle: ou inurl: ou author: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Permet de chercher en utilisant intitle: ou inurl: ou author: comme dans certains moteurs de recherche. Pour l'instant, un seul de ces mots clefs à la fois peut être spécifié en tout début de chaîne de recherche et sera appliqué à l'ensemble du reste de la recherche. NB: À ajouter à la documentation, wiki --- app/Models/EntryDAO.php | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index d1f595d42..c9989622a 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -313,17 +313,46 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($filter !== '') { $filter = trim($filter); $filter = addcslashes($filter, '\\%_'); + if (stripos($filter, 'intitle:') === 0) { + $filter = substr($filter, strlen('intitle:')); + $intitle = true; + } else { + $intitle = false; + } + if (stripos($filter, 'inurl:') === 0) { + $filter = substr($filter, strlen('inurl:')); + $inurl = true; + } else { + $inurl = false; + } + if (stripos($filter, 'author:') === 0) { + $filter = substr($filter, strlen('author:')); + $author = true; + } else { + $author = false; + } $terms = array_unique(explode(' ', $filter)); sort($terms); //Put #tags first foreach ($terms as $word) { $word = trim($word); if (strlen($word) > 0) { - if ($word[0] === '#' && isset($word[1])) { - $search .= 'AND e1.tags LIKE ? '; + if ($intitle) { + $search .= 'AND e1.title LIKE ? '; $values[] = '%' . $word .'%'; - } else { - $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? '; + } elseif ($inurl) { + $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? '; $values[] = '%' . $word .'%'; + } elseif ($author) { + $search .= 'AND e1.author LIKE ? '; + $values[] = '%' . $word .'%'; + } else { + if ($word[0] === '#' && isset($word[1])) { + $search .= 'AND e1.tags LIKE ? '; + $values[] = '%' . $word .'%'; + } else { + $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? '; + $values[] = '%' . $word .'%'; + } } } } -- cgit v1.2.3 From 6b7d96d0ea97579720ee6d560224cd80c2329d07 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 19 Dec 2013 21:19:45 +0100 Subject: Refactorisation : correction classes oubliées MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/indexController.php | 6 +++--- app/Models/CategoryDAO.php | 16 +++++++--------- app/Models/EntryDAO.php | 8 +++----- app/Models/FeedDAO.php | 12 +++++------- app/views/helpers/view/normal_view.phtml | 2 +- app/views/helpers/view/reader_view.phtml | 2 +- 6 files changed, 20 insertions(+), 26 deletions(-) (limited to 'app') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 22c5683ea..e3c253518 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -77,7 +77,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { return; } - $this->view->nb_not_read = HelperCategory::CountUnreads($this->view->cat_aside, 1); + $this->view->nb_not_read = FreshRSS_CategoryDAO::CountUnreads($this->view->cat_aside, 1); // mise à jour des titres $this->view->rss_title = $this->view->currentName . ' | ' . Minz_View::title(); @@ -112,7 +112,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $hasUnread = (!isset($this->view->cat_aside[$getId])) || ($this->view->cat_aside[$getId]->nbNotRead() > 0); break; case 'f': - $myFeed = HelperCategory::findFeed($this->view->cat_aside, $getId); + $myFeed = FreshRSS_CategoryDAO::findFeed($this->view->cat_aside, $getId); $hasUnread = ($myFeed === null) || ($myFeed->nbNotRead() > 0); break; default: @@ -188,7 +188,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { return false; } case 'f': - $feed = HelperCategory::findFeed($this->view->cat_aside, $getId); + $feed = FreshRSS_CategoryDAO::findFeed($this->view->cat_aside, $getId); if (empty($feed)) { $feed = $this->feedDAO->searchById ($getId); } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 793e593c3..3a810e9f0 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -60,7 +60,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = HelperCategory::daoToCategory ($res); + $cat = self::daoToCategory ($res); if (isset ($cat[0])) { return $cat[0]; @@ -76,7 +76,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = HelperCategory::daoToCategory ($res); + $cat = self::daoToCategory ($res); if (isset ($cat[0])) { return $cat[0]; @@ -96,12 +96,12 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { . 'ORDER BY c.name, f.name'; $stm = $this->bd->prepare ($sql); $stm->execute (); - return HelperCategory::daoToCategoryPrepopulated ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToCategoryPrepopulated ($stm->fetchAll (PDO::FETCH_ASSOC)); } else { $sql = 'SELECT * FROM `' . $this->prefix . 'category` ORDER BY name'; $stm = $this->bd->prepare ($sql); $stm->execute (); - return HelperCategory::daoToCategory ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToCategory ($stm->fetchAll (PDO::FETCH_ASSOC)); } } @@ -111,7 +111,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $stm->execute (); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = HelperCategory::daoToCategory ($res); + $cat = self::daoToCategory ($res); if (isset ($cat[0])) { return $cat[0]; @@ -164,9 +164,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $res[0]['count']; } -} -class HelperCategory { public static function findFeed($categories, $feed_id) { foreach ($categories as $category) { foreach ($category->feeds () as $feed) { @@ -205,7 +203,7 @@ class HelperCategory { $cat = new FreshRSS_Category ( $previousLine['c_name'], isset($previousLine['c_color']) ? $previousLine['c_color'] : '', - HelperFeed::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) ); $cat->_id ($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; @@ -222,7 +220,7 @@ class HelperCategory { $cat = new FreshRSS_Category ( $previousLine['c_name'], isset($previousLine['c_color']) ? $previousLine['c_color'] : '', - HelperFeed::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) ); $cat->_id ($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c9989622a..d8bc869ae 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -242,7 +242,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $entries = HelperEntry::daoToEntry ($res); + $entries = self::daoToEntry ($res); return isset ($entries[0]) ? $entries[0] : false; } @@ -255,7 +255,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $entries = HelperEntry::daoToEntry ($res); + $entries = self::daoToEntry ($res); return isset ($entries[0]) ? $entries[0] : false; } @@ -372,7 +372,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare ($sql); $stm->execute ($values); - return HelperEntry::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); } public function listLastGuidsByFeed($id, $n) { @@ -430,9 +430,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare ($sql); $stm->execute (); } -} -class HelperEntry { public static function daoToEntry ($listDAO) { $list = array (); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 8f59b1c76..9ebea4a47 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -158,7 +158,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $feed = HelperFeed::daoToFeed ($res); + $feed = self::daoToFeed ($res); if (isset ($feed[$id])) { return $feed[$id]; @@ -174,7 +174,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $feed = current (HelperFeed::daoToFeed ($res)); + $feed = current (self::daoToFeed ($res)); if (isset ($feed)) { return $feed; @@ -188,7 +188,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm = $this->bd->prepare ($sql); $stm->execute (); - return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); } public function listFeedsOrderUpdate () { @@ -196,7 +196,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm = $this->bd->prepare ($sql); $stm->execute (); - return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); } public function listByCategory ($cat) { @@ -207,7 +207,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm->execute ($values); - return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); } public function countEntries ($id) { @@ -299,9 +299,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return false; } } -} -class HelperFeed { public static function daoToFeed ($listDAO, $catID = null) { $list = array (); diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index d5328651d..f21a2bdd9 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -62,7 +62,7 @@ if (!empty($this->entries)) { ?>cat_aside, $item->feed ()); //We most likely already have the feed object in cache + $feed = FreshRSS_CategoryDAO::findFeed($this->cat_aside, $item->feed ()); //We most likely already have the feed object in cache if (empty($feed)) $feed = $item->feed (true); ?>
  • ✇ name(); ?>
  • diff --git a/app/views/helpers/view/reader_view.phtml b/app/views/helpers/view/reader_view.phtml index 29b2be04c..e28af6ade 100644 --- a/app/views/helpers/view/reader_view.phtml +++ b/app/views/helpers/view/reader_view.phtml @@ -11,7 +11,7 @@ if (!empty($this->entries)) {
    cat_aside, $item->feed ()); //We most likely already have the feed object in cache + $feed = FreshRSS_CategoryDAO::findFeed($this->cat_aside, $item->feed ()); //We most likely already have the feed object in cache if (empty($feed)) $feed = $item->feed (true); ?> -- cgit v1.2.3 From c013ecd0ae37db685d38b4a743f14bd55e437cf6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 19 Dec 2013 21:34:13 +0100 Subject: Refactorisation : Minz_Translate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Un préfixe Minz_ oublié --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 62fead315..ef03d9e1d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -363,7 +363,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { // au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste $this->view->flux = false; - Minz_View::prependTitle (Translate::t ('import_export_opml') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('import_export_opml') . ' - '); } public function shortcutAction () { -- cgit v1.2.3 From 1c0e7a49528d1fb972a0fa0e9551d70dc5636442 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 19 Dec 2013 21:53:21 +0100 Subject: Refactorisation : FreshRSS_Feed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Un préfixe FreshRSS_ oublié --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 18476d559..27b76dd42 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -394,7 +394,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'type' => 'good', 'content' => Minz_Translate::t ('feed_deleted') ); - Feed::faviconDelete($id); + FreshRSS_Feed::faviconDelete($id); } else { $notif = array ( 'type' => 'bad', -- cgit v1.2.3 From daefb8f095f1abe591347e99fcb09ab53701d39d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 19 Dec 2013 22:11:58 +0100 Subject: Caractères spéciaux feed->description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Feed->description est en HTML, il faut protéger les caractères spéciaux lors de certaines sorties. --- app/views/configure/feed.phtml | 2 +- lib/lib_rss.php | 2 +- public/themes/default/freshrss.css | 2 +- public/themes/flat-design/freshrss.css | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index 191e44b9b..4504b8d76 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -22,7 +22,7 @@
    - +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 2fdfd4bd8..8b64eb7b9 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -116,7 +116,7 @@ function opml_export ($cats) { $txt .= '' . "\n"; foreach ($cat['feeds'] as $feed) { - $txt .= "\t" . '' . "\n"; + $txt .= "\t" . '' . "\n"; } $txt .= '' . "\n"; diff --git a/public/themes/default/freshrss.css b/public/themes/default/freshrss.css index b53702c07..a63fc44bf 100644 --- a/public/themes/default/freshrss.css +++ b/public/themes/default/freshrss.css @@ -291,7 +291,7 @@ } .flux:hover .item.title { overflow: visible; - padding-right: 1.5em; + padding-right: 2em; position: absolute; } .flux .item.title a { diff --git a/public/themes/flat-design/freshrss.css b/public/themes/flat-design/freshrss.css index bbe477c04..839626227 100644 --- a/public/themes/flat-design/freshrss.css +++ b/public/themes/flat-design/freshrss.css @@ -273,7 +273,7 @@ body { } .flux:hover .item.title { overflow: visible; - padding-right: 1.5em; + padding-right: 2em; position: absolute; } .flux .item.title a { -- cgit v1.2.3 From 3dc50cbd6627f9dfeb35c8e656eaf35f1f77495a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 19 Dec 2013 23:32:24 +0100 Subject: Compatibilité contenu HTML pour Feed->description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente https://github.com/marienfressinaud/FreshRSS/issues/325 --- app/Controllers/configureController.php | 2 +- lib/lib_rss.php | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index ef03d9e1d..8d3e02d3e 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -94,7 +94,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } else { if (Minz_Request::isPost () && $this->view->flux) { $name = Minz_Request::param ('name', ''); - $description = Minz_Request::param('description', ''); + $description = sanitizeHTML(Minz_Request::param('description', '', true)); $website = Minz_Request::param('website', ''); $url = Minz_Request::param('url', ''); $hist = Minz_Request::param ('keep_history', 'no'); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index c7b8b4beb..4ef06ddbc 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -136,6 +136,14 @@ function html_only_entity_decode($text) { return strtr($text, $htmlEntitiesOnly); } +function sanitizeHTML($data) { + static $simplePie = null; + if ($simplePie == null) { + $simplePie = new SimplePie(); + } + return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_MAYBE_HTML)); +} + function opml_import ($xml) { $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 @@ -176,7 +184,7 @@ function opml_import ($xml) { // alors qu'il existe déjà la catégorie X mais avec l'id Z // Y ne sera pas ajouté et le flux non plus vu que l'id // de sa catégorie n'exisera pas - $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); $catDAO = new FreshRSS_CategoryDAO (); $cat = $catDAO->searchByName ($title); if ($cat === false) { @@ -221,22 +229,22 @@ function getFeedsOutline ($outline, $cat_id) { function getFeed ($outline, $cat_id) { $url = (string) $outline['xmlUrl']; - $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8'); + $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); $title = ''; if (isset ($outline['text'])) { $title = (string) $outline['text']; } elseif (isset ($outline['title'])) { $title = (string) $outline['title']; } - $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); $feed = new FreshRSS_Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); if (isset($outline['htmlUrl'])) { - $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_QUOTES, 'UTF-8')); + $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_COMPAT, 'UTF-8')); } if (isset($outline['description'])) { - $feed->_description((string)$outline['description']); + $feed->_description(sanitizeHTML((string)$outline['description'])); } return $feed; } -- cgit v1.2.3 From b90a6be35f8996b27719cf493b47d1592d09ae6d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 22 Dec 2013 14:54:10 +0100 Subject: i18n install.php pour mise à jour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Termine https://github.com/marienfressinaud/FreshRSS/issues/255 Sépare i18n de install.php dans des fichiers dédiés --- app/i18n/en.php | 56 --------------------------------------------- app/i18n/fr.php | 56 --------------------------------------------- app/i18n/install.en.php | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ app/i18n/install.fr.php | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ public/install.php | 16 +++++++++---- 5 files changed, 133 insertions(+), 117 deletions(-) create mode 100644 app/i18n/install.en.php create mode 100644 app/i18n/install.fr.php (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index 580e68c41..d450bf30f 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -271,60 +271,4 @@ return array ( // format for date() function, %s allows to indicate month in letter 'format_date' => '%s dS Y', 'format_date_hour' => '%s dS Y \a\t H\.i', - - // INSTALLATION - 'freshrss_installation' => 'Installation - FreshRSS', - 'freshrss' => 'FreshRSS', - 'installation_step' => 'Installation - step %d', - 'steps' => 'Steps', - 'checks' => 'Checks', - 'bdd_configuration' => 'Database configuration', - 'bdd_type' => 'Type of database', - 'this_is_the_end' => 'This is the end', - - 'ok' => 'Ok!', - 'congratulations' => 'Congratulations!', - 'attention' => 'Attention!', - 'damn' => 'Damn!', - 'oops' => 'Oops!', - 'next_step' => 'Go to the next step', - - 'language_defined' => 'Language has been defined.', - 'choose_language' => 'Choose a language for FreshRSS', - - 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', - 'php_is_ok' => 'Your PHP version is %s and it’s compatible with FreshRSS', - 'php_is_nok' => 'Your PHP version is %s. You must have at least version %s', - 'minz_is_ok' => 'You have Minz framework', - 'minz_is_nok' => 'You haven’t Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', - 'curl_is_ok' => 'You have version %s of cURL', - 'curl_is_nok' => 'You haven’t cURL', - 'pdomysql_is_ok' => 'You have PDO and its driver for MySQL', - 'pdomysql_is_nok' => 'You haven’t PDO or its driver for MySQL', - 'dom_is_ok' => 'You have the necessary to browse the DOM', - 'dom_is_nok' => 'You haven’t the necessary to browse the DOM (php-xml package can be useful)', - 'cache_is_ok' => 'Permissions on cache directory are good', - 'log_is_ok' => 'Permissions on logs directory are good', - 'favicons_is_ok' => 'Permissions on favicons directory are good', - 'data_is_ok' => 'Permissions on data directory are good', - 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', - 'fix_errors_before' => 'Fix errors before skip to the next step.', - - 'general_conf_is_ok' => 'General configuration has been saved.', - 'random_string' => 'Random string', - 'change_value' => 'You should change this value by any other', - 'base_url' => 'Base URL', - 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', - - 'bdd_conf_is_ok' => 'Database configuration has been saved.', - 'bdd_conf_is_ko' => 'Verify your database information.', - 'host' => 'Host', - 'username' => 'Username', - 'password' => 'Password', - 'bdd' => 'Database', - 'prefix' => 'Table prefix', - - 'installation_is_ok' => 'Installation process is finished. You must delete install.php file to access FreshRSS… or simply click on following button :)', - 'finish_installation' => 'Finish installation', - 'install_not_deleted' => 'Something was going wrong, you must delete the file %s manually.', ); diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 262e7700c..f65fa9fbc 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -271,60 +271,4 @@ return array ( // format pour la fonction date(), %s permet d'indiquer le mois en toutes lettres 'format_date' => 'd %s Y', 'format_date_hour' => '\l\e d %s Y \à H\:i', - - // INSTALLATION - 'freshrss_installation' => 'Installation - FreshRSS', - 'freshrss' => 'FreshRSS', - 'installation_step' => 'Installation - étape %d', - 'steps' => 'Étapes', - 'checks' => 'Vérifications', - 'bdd_configuration' => 'Configuration de la base de données', - 'bdd_type' => 'Type de base de données', - 'this_is_the_end' => 'This is the end', - - 'ok' => 'Ok !', - 'congratulations' => 'Félicitations !', - 'attention' => 'Attention !', - 'damn' => 'Arf !', - 'oops' => 'Oups !', - 'next_step' => 'Passer à l’étape suivante', - - 'language_defined' => 'La langue a bien été définie.', - 'choose_language' => 'Choisissez la langue pour FreshRSS', - - 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', - 'php_is_ok' => 'Votre version de PHP est la %s qui est compatible avec FreshRSS', - 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', - 'minz_is_ok' => 'Vous disposez du framework Minz', - 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', - 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', - 'curl_is_nok' => 'Vous ne disposez pas de cURL', - 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL', - 'pdomysql_is_nok' => 'Vous ne disposez pas de PDO ou de son driver pour MySQL', - 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'dom_is_nok' => 'Vous ne disposez pas du nécessaire pour parcourir le DOM (voir du côté du paquet php-xml ?)', - 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', - 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', - 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', - 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', - 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', - - 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', - 'random_string' => 'Chaîne aléatoire', - 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', - 'base_url' => 'Base de l’url', - 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', - - 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', - 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', - 'host' => 'Hôte', - 'username' => 'Nom utilisateur', - 'password' => 'Mot de passe', - 'bdd' => 'Base de données', - 'prefix' => 'Préfixe des tables', - - 'installation_is_ok' => 'L’installation s’est bien passée. Il faut maintenant supprimer le fichier install.php pour pouvoir accéder à FreshRSS… ou simplement cliquer sur le bouton ci-dessous :)', - 'finish_installation' => 'Terminer l’installation', - 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', ); diff --git a/app/i18n/install.en.php b/app/i18n/install.en.php new file mode 100644 index 000000000..74245d63b --- /dev/null +++ b/app/i18n/install.en.php @@ -0,0 +1,61 @@ + 'Installation - FreshRSS', + 'freshrss' => 'FreshRSS', + 'installation_step' => 'Installation - step %d', + 'steps' => 'Steps', + 'checks' => 'Checks', + 'bdd_configuration' => 'Database configuration', + 'bdd_type' => 'Type of database', + 'version_update' => 'Update', + 'this_is_the_end' => 'This is the end', + + 'ok' => 'Ok!', + 'congratulations' => 'Congratulations!', + 'attention' => 'Attention!', + 'damn' => 'Damn!', + 'oops' => 'Oops!', + 'next_step' => 'Go to the next step', + + 'language_defined' => 'Language has been defined.', + 'choose_language' => 'Choose a language for FreshRSS', + + 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', + 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', + 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', + 'minz_is_ok' => 'You have the Minz framework', + 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', + 'curl_is_ok' => 'You have version %s of cURL', + 'curl_is_nok' => 'You lack cURL (php5-curl package)', + 'pdomysql_is_ok' => 'You have PDO and its driver for MySQL', + 'pdomysql_is_nok' => 'You lack PDO or its driver for MySQL (php5-mysql package)', + 'dom_is_ok' => 'You have the required library to browse the DOM', + 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', + 'cache_is_ok' => 'Permissions on cache directory are good', + 'log_is_ok' => 'Permissions on logs directory are good', + 'favicons_is_ok' => 'Permissions on favicons directory are good', + 'data_is_ok' => 'Permissions on data directory are good', + 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', + 'fix_errors_before' => 'Fix errors before skip to the next step.', + + 'general_conf_is_ok' => 'General configuration has been saved.', + 'random_string' => 'Random string', + 'change_value' => 'You should change this value by any other', + 'base_url' => 'Base URL', + 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', + + 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'bdd_conf_is_ko' => 'Verify your database information.', + 'host' => 'Host', + 'username' => 'Username', + 'password' => 'Password', + 'bdd' => 'Database', + 'prefix' => 'Table prefix', + + 'update_start' => 'Start update process', + 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', + + 'installation_is_ok' => 'The installation process was successful.
    The final step will now attempt to delete the ./public/install.php file and any database backup created during the update process.
    You may choose to skip this step and delete ./public/install.php manually.', + 'finish_installation' => 'Complete installation', + 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', +); diff --git a/app/i18n/install.fr.php b/app/i18n/install.fr.php new file mode 100644 index 000000000..9b7a9bdff --- /dev/null +++ b/app/i18n/install.fr.php @@ -0,0 +1,61 @@ + 'Installation - FreshRSS', + 'freshrss' => 'FreshRSS', + 'installation_step' => 'Installation - étape %d', + 'steps' => 'Étapes', + 'checks' => 'Vérifications', + 'bdd_configuration' => 'Base de données', + 'bdd_type' => 'Type de base de données', + 'version_update' => 'Mise à jour', + 'this_is_the_end' => 'This is the end', + + 'ok' => 'Ok !', + 'congratulations' => 'Félicitations !', + 'attention' => 'Attention !', + 'damn' => 'Arf !', + 'oops' => 'Oups !', + 'next_step' => 'Passer à l’étape suivante', + + 'language_defined' => 'La langue a bien été définie.', + 'choose_language' => 'Choisissez la langue pour FreshRSS', + + 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', + 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', + 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', + 'minz_is_ok' => 'Vous disposez du framework Minz', + 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', + 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', + 'curl_is_nok' => 'Vous ne disposez pas de cURL (librairie php5-curl)', + 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL (librairie php5-mysql)', + 'pdomysql_is_nok' => 'Vous ne disposez pas de PDO ou de son driver pour MySQL', + 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', + 'dom_is_nok' => 'Vous ne disposez pas du nécessaire pour parcourir le DOM (librairie php-xml)', + 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', + 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', + 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', + 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', + 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', + + 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'random_string' => 'Chaîne aléatoire', + 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', + 'base_url' => 'Base de l’url', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', + + 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', + 'host' => 'Hôte', + 'username' => 'Nom utilisateur', + 'password' => 'Mot de passe', + 'bdd' => 'Base de données', + 'prefix' => 'Préfixe des tables', + + 'update_start' => 'Lancer la mise à jour', + 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', + + 'installation_is_ok' => 'L’installation s’est bien passée.
    La dernière étape va maintenant tenter de supprimer le fichier /public/install.php, ainsi que d’éventuelles copies de base de données créées durant le processus de mise à jour.
    Vous pouvez choisir de sauter cette étape et de supprimer /public/install.php manuellement.', + 'finish_installation' => 'Terminer l’installation', + 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', +); diff --git a/public/install.php b/public/install.php index 2823a269a..133e7fbe4 100644 --- a/public/install.php +++ b/public/install.php @@ -155,8 +155,13 @@ function initTranslate () { $actual = isset($_SESSION['language']) ? $_SESSION['language'] : getBetterLanguage('en'); $file = APP_PATH . '/i18n/' . $actual . '.php'; - if (file_exists ($file)) { - $translates = include ($file); + if (file_exists($file)) { + $translates = array_merge($translates, include($file)); + } + + $file = APP_PATH . '/i18n/install.' . $actual . '.php'; + if (file_exists($file)) { + $translates = array_merge($translates, include($file)); } } function getBetterLanguage ($fallback) { @@ -888,12 +893,13 @@ function printStep3 () { function printStep4 () { ?>
    - +
    - (This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.) + +

    @@ -970,7 +976,7 @@ case 6:
  • -
  • +
-- cgit v1.2.3 From 4bcfd591f0192aaa17f934e9f56291c453815134 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 22 Dec 2013 15:00:54 +0100 Subject: Chargement automatique activé par défaut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clôture https://github.com/marienfressinaud/FreshRSS/issues/308 --- app/Models/ConfigurationDAO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/ConfigurationDAO.php b/app/Models/ConfigurationDAO.php index fec58d234..57fc98047 100644 --- a/app/Models/ConfigurationDAO.php +++ b/app/Models/ConfigurationDAO.php @@ -38,7 +38,7 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray { public $theme = 'default'; public $anon_access = 'no'; public $token = ''; - public $auto_load_more = 'no'; + public $auto_load_more = 'yes'; public $topline_read = 'yes'; public $topline_favorite = 'yes'; public $topline_date = 'yes'; -- cgit v1.2.3 From 11b1d06b8c4672f7dab98f8de5a7f7f95eeeec12 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 23 Dec 2013 00:01:00 +0100 Subject: Chargement différé des iframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente https://github.com/marienfressinaud/FreshRSS/issues/313 (uniquement pour la vue en articles repliés) --- app/views/helpers/view/normal_view.phtml | 42 ++++++++++++++++---------------- app/views/helpers/view/reader_view.phtml | 3 ++- lib/lib_rss.php | 8 ++++++ public/scripts/main.js | 2 +- 4 files changed, 32 insertions(+), 23 deletions(-) (limited to 'app') diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index f21a2bdd9..4307c2113 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -4,25 +4,25 @@ $this->partial ('aside_flux'); $this->partial ('nav_menu'); if (!empty($this->entries)) { -?> + $display_today = true; + $display_yesterday = true; + $display_others = true; -
- conf) || is_logged (); + $shaarli = $this->conf->sharing ('shaarli'); + $poche = $this->conf->sharing ('poche'); + $diaspora = $this->conf->sharing ('diaspora'); + $twitter = $this->conf->sharing ('twitter'); + $google_plus = $this->conf->sharing ('g+'); + $facebook = $this->conf->sharing ('facebook'); + $email = $this->conf->sharing ('email'); + $print = $this->conf->sharing ('print'); + $today = $this->today; + $hidePosts = $this->conf->displayPosts() === 'no'; + $lazyload = $this->conf->lazyload() === 'yes'; +?> - $logged = !login_is_conf ($this->conf) || is_logged (); - $shaarli = $this->conf->sharing ('shaarli'); - $poche = $this->conf->sharing ('poche'); - $diaspora = $this->conf->sharing ('diaspora'); - $twitter = $this->conf->sharing ('twitter'); - $google_plus = $this->conf->sharing ('g+'); - $facebook = $this->conf->sharing ('facebook'); - $email = $this->conf->sharing ('email'); - $print = $this->conf->sharing ('print'); - $today = $this->today; - ?> +
entries as $item) { ?> isDay (FreshRSS_Days::TODAY, $today)) { ?> @@ -48,7 +48,7 @@ if (!empty($this->entries)) {
-
- -
- -
-
-
conf->mailLogin (); ?> @@ -59,7 +52,27 @@
- + + + +
+ +
+ + + + + + + + + + +
+ +
+
+
diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index 4504b8d76..3fe7d1b3a 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -52,6 +52,9 @@
+ + +
@@ -64,10 +67,21 @@
flux->nbEntries (); ?> - +
+
+
+ +
+ + + + + + + + + +
diff --git a/public/install.php b/public/install.php index afef7e473..3885f143e 100644 --- a/public/install.php +++ b/public/install.php @@ -93,7 +93,7 @@ FROM `%1$scategory006` ORDER BY id2; INSERT IGNORE INTO `%2$sfeed` (url, category, name, website, description, priority, pathEntries, httpAuth, keep_history) -SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, keep_history +SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, -1 * keep_history FROM `%1$sfeed006` ORDER BY id2; -- cgit v1.2.3 From a4b890b67fb4d97c97a2b1b455c327ce4b905194 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 14:29:29 +0100 Subject: Suite gestion plus fine de l'historique --- app/Controllers/configureController.php | 7 +------ app/Models/FeedDAO.php | 2 +- app/views/configure/display.phtml | 37 ++++++++++++++++++++++++++------- app/views/configure/feed.phtml | 12 +++++++---- 4 files changed, 39 insertions(+), 19 deletions(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 8d3e02d3e..b83501f0b 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -97,18 +97,13 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $description = sanitizeHTML(Minz_Request::param('description', '', true)); $website = Minz_Request::param('website', ''); $url = Minz_Request::param('url', ''); - $hist = Minz_Request::param ('keep_history', 'no'); + $keep_history = intval(Minz_Request::param ('keep_history', 0)); $cat = Minz_Request::param ('category', 0); $path = Minz_Request::param ('path_entries', ''); $priority = Minz_Request::param ('priority', 0); $user = Minz_Request::param ('http_user', ''); $pass = Minz_Request::param ('http_pass', ''); - $keep_history = false; - if ($hist == 'yes') { - $keep_history = true; - } - $httpAuth = ''; if ($user != '' || $pass != '') { $httpAuth = $user . ':' . $pass; diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 451fc3850..7d91a032a 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -193,7 +193,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { } public function listFeedsOrderUpdate () { - $sql = 'SELECT id, url, pathEntries, httpAuth, keep_history FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate'; + $sql = 'SELECT id, name, url, pathEntries, httpAuth, keep_history FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate'; $stm = $this->bd->prepare ($sql); $stm->execute (); diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 68ef26bbf..8995dc839 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -53,6 +53,13 @@
+
+
+ + +
+
+
@@ -73,6 +80,13 @@
+
+
+ + +
+
+
@@ -173,6 +187,13 @@
+
+
+ + +
+
+
@@ -206,7 +227,14 @@ -
conf->bottomlineLink () ? ' checked="checked"' : ''; ?> />
+
+
+ +
+
+ + +
@@ -220,12 +248,5 @@ - -
-
- - -
-
diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index 3fe7d1b3a..5940055ed 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -52,6 +52,12 @@ +
+
+ + +
+
@@ -84,9 +90,9 @@ -
- +
+
@@ -123,11 +129,9 @@
-
-
-- cgit v1.2.3 From 06d4b8d10247146d9c6f7c78ff9fc584438dd8fe Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 17:37:52 +0100 Subject: Option globale pour la taille minimale de l'historique par défaut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plus une réorganisation des options --- app/Controllers/configureController.php | 5 ++- app/Controllers/feedController.php | 9 +++-- app/Controllers/indexController.php | 5 +-- app/Models/Configuration.php | 14 +++++++- app/Models/ConfigurationDAO.php | 8 +++-- app/Models/EntryDAO.php | 8 +++-- app/Models/Feed.php | 4 +-- app/Models/FeedDAO.php | 4 +-- app/i18n/en.php | 8 +++-- app/i18n/fr.php | 8 +++-- app/views/configure/display.phtml | 35 ++++++++++++------- app/views/configure/feed.phtml | 62 ++++++++++++++++++--------------- public/install.php | 4 +-- public/themes/default/freshrss.css | 4 +++ public/themes/default/global.css | 3 ++ public/themes/flat-design/freshrss.css | 4 +++ public/themes/flat-design/global.css | 3 ++ 17 files changed, 124 insertions(+), 64 deletions(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index b83501f0b..762134dd0 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -97,7 +97,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $description = sanitizeHTML(Minz_Request::param('description', '', true)); $website = Minz_Request::param('website', ''); $url = Minz_Request::param('url', ''); - $keep_history = intval(Minz_Request::param ('keep_history', 0)); + $keep_history = intval(Minz_Request::param ('keep_history', -2)); $cat = Minz_Request::param ('category', 0); $path = Minz_Request::param ('path_entries', ''); $priority = Minz_Request::param ('priority', 0); @@ -160,6 +160,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $lazyload = Minz_Request::param ('lazyload', 'no'); $sort = Minz_Request::param ('sort_order', 'DESC'); $old = Minz_Request::param ('old_entries', 3); + $keepHistoryDefault = Minz_Request::param('keep_history_default', 0); $mail = Minz_Request::param ('mail_login', false); $anon = Minz_Request::param ('anon_access', 'no'); $token = Minz_Request::param ('token', $current_token); @@ -189,6 +190,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_lazyload ($lazyload); $this->view->conf->_sortOrder ($sort); $this->view->conf->_oldEntries ($old); + $this->view->conf->_keepHistoryDefault($keepHistoryDefault); $this->view->conf->_mailLogin ($mail); $this->view->conf->_anonAccess ($anon); $this->view->conf->_token ($token); @@ -221,6 +223,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'lazyload' => $this->view->conf->lazyload (), 'sort_order' => $this->view->conf->sortOrder (), 'old_entries' => $this->view->conf->oldEntries (), + 'keep_history_default' => $this->view->conf->keepHistoryDefault(), 'mail_login' => $this->view->conf->mailLogin (), 'anon_access' => $this->view->conf->anonAccess (), 'token' => $this->view->conf->token (), diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index e7d9c97c3..836044da6 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -223,8 +223,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - if (($feed->keepHistory() >= 0) && (rand(0, 30) === 1)) { - $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feed->keepHistory(), count($entries) + 10)); + $feedHistory = $feed->keepHistory(); + if ($feedHistory == -2) { //default + $feedHistory = $this->view->conf->keepHistoryDefault(); + } + + if (($feedHistory >= 0) && (rand(0, 30) === 1)) { + $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10)); if ($nb > 0) { Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e3c253518..6c0ba9058 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -130,16 +130,17 @@ class FreshRSS_index_Controller extends Minz_ActionController { // on calcule la date des articles les plus anciens qu'on affiche $nb_month_old = $this->view->conf->oldEntries (); $date_min = $today - (3600 * 24 * 30 * $nb_month_old); //Do not use a fast changing value such as time() to allow SQL caching + $keepHistoryDefault = $this->view->conf->keepHistoryDefault(); try { - $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min); + $entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, $keepHistoryDefault); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles if ($state === 'not_read' && empty($entries)) { //TODO: Remove in v0.8 Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; - $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min); + $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault); } if (count($entries) <= $nb) { diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index d5f69601f..47509636f 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -14,6 +14,7 @@ class FreshRSS_Configuration extends Minz_Model { private $lazyload; private $sort_order; private $old_entries; + private $keep_history_default; private $shortcuts = array (); private $mail_login = ''; private $mark_when = array (); @@ -44,6 +45,7 @@ class FreshRSS_Configuration extends Minz_Model { $this->_lazyload ($confDAO->lazyload); $this->_sortOrder ($confDAO->sort_order); $this->_oldEntries ($confDAO->old_entries); + $this->_keepHistoryDefault($confDAO->keep_history_default); $this->_shortcuts ($confDAO->shortcuts); $this->_mailLogin ($confDAO->mail_login); $this->_markWhen ($confDAO->mark_when); @@ -95,6 +97,9 @@ class FreshRSS_Configuration extends Minz_Model { public function oldEntries () { return $this->old_entries; } + public function keepHistoryDefault() { + return $this->keep_history_default; + } public function shortcuts () { return $this->shortcuts; } @@ -217,11 +222,18 @@ class FreshRSS_Configuration extends Minz_Model { } public function _oldEntries ($value) { if (ctype_digit ($value) && $value > 0) { - $this->old_entries = $value; + $this->old_entries = intval($value); } else { $this->old_entries = 3; } } + public function _keepHistoryDefault($value) { + if (ctype_digit($value) && $value >= -1) { + $this->keep_history_default = intval($value); + } else { + $this->keep_history_default = 0; + } + } public function _shortcuts ($values) { foreach ($values as $key => $value) { $this->shortcuts[$key] = $value; diff --git a/app/Models/ConfigurationDAO.php b/app/Models/ConfigurationDAO.php index 0eebf2d90..91210e701 100644 --- a/app/Models/ConfigurationDAO.php +++ b/app/Models/ConfigurationDAO.php @@ -10,6 +10,7 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray { public $lazyload = 'yes'; public $sort_order = 'DESC'; public $old_entries = 3; + public $keep_history_default = 0; public $shortcuts = array ( 'mark_read' => 'r', 'mark_favorite' => 'f', @@ -62,7 +63,7 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray { $this->language = $this->array['language']; } if (isset ($this->array['posts_per_page'])) { - $this->posts_per_page = $this->array['posts_per_page']; + $this->posts_per_page = intval($this->array['posts_per_page']); } if (isset ($this->array['view_mode'])) { $this->view_mode = $this->array['view_mode']; @@ -83,7 +84,10 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray { $this->sort_order = $this->array['sort_order']; } if (isset ($this->array['old_entries'])) { - $this->old_entries = $this->array['old_entries']; + $this->old_entries = intval($this->array['old_entries']); + } + if (isset ($this->array['keep_history_default'])) { + $this->keep_history_default = intval($this->array['keep_history_default']); } if (isset ($this->array['shortcuts'])) { $this->shortcuts = array_merge ( diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index f0207e96d..14d3ddcff 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -260,7 +260,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return isset ($entries[0]) ? $entries[0] : false; } - public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) { $where = ''; $joinFeed = false; $values = array(); @@ -307,7 +307,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR f.keep_history <> 0) '; + $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR (f.keep_history <> 0'; + if (intval($keepHistoryDefault) === 0) { + $where .= ' AND f.keep_history <> -2'; //default + } + $where .= ')) '; $joinFeed = true; } $search = ''; diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 5bdf5e6d7..ef554e083 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -15,7 +15,7 @@ class FreshRSS_Feed extends Minz_Model { private $pathEntries = ''; private $httpAuth = ''; private $error = false; - private $keep_history = 0; + private $keep_history = -2; public function __construct ($url, $validate=true) { if ($validate) { @@ -168,7 +168,7 @@ class FreshRSS_Feed extends Minz_Model { public function _keepHistory ($value) { $value = intval($value); $value = min($value, 1000000); - $value = max($value, -1); + $value = max($value, -2); $this->keep_history = $value; } public function _nbNotRead ($value) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 7d91a032a..c1d1f24e8 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -2,7 +2,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { public function addFeed ($valuesTmp) { - $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, 0)'; + $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2)'; $stm = $this->bd->prepare ($sql); $values = array ( @@ -326,7 +326,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $myFeed->_pathEntries (isset($dao['pathEntries']) ? $dao['pathEntries'] : ''); $myFeed->_httpAuth (isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : ''); $myFeed->_error ($dao['error']); - $myFeed->_keepHistory (isset($dao['keep_history']) ? $dao['keep_history'] : 0); + $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : -2); $myFeed->_nbNotRead ($dao['cache_nbUnreads']); $myFeed->_nbEntries ($dao['cache_nbEntries']); if (isset ($dao['id'])) { diff --git a/app/i18n/en.php b/app/i18n/en.php index b6417d8db..ca72d885c 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -137,8 +137,9 @@ return array ( 'feed_url' => 'Feed URL', 'articles' => 'articles', 'number_articles' => 'Number of articles', + 'by_feed' => 'by feed', + 'by_default' => 'By default', 'keep_history' => 'Minimum number of articles to keep', - 'keep_history_help' => 'Set to -1 to keep everything', 'categorize' => 'Store in a category', 'truncate' => 'Delete all articles', 'advanced' => 'Advanced', @@ -164,10 +165,11 @@ return array ( 'allow_anonymous' => 'Allow anonymous reading', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output without authentication.
%s?token=%s', - 'archiving_configuration' => 'Archiving configuration', + 'login_configuration' => 'Login', + 'archiving_configuration' => 'Archiving', 'delete_articles_every' => 'Remove articles after', 'archiving_configuration_help' => 'More options are available in the individual stream settings', - 'reading_configuration' => 'Reading configuration', + 'reading_configuration' => 'Reading', 'articles_per_page' => 'Number of articles per page', 'default_view' => 'Default view', 'sort_order' => 'Sort order', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index b27f29940..053a97c8a 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -137,8 +137,9 @@ return array ( 'feed_url' => 'URL du flux', 'articles' => 'articles', 'number_articles' => 'Nombre d’articles', + 'by_feed' => 'par flux', + 'by_default' => 'Par défaut', 'keep_history' => 'Nombre minimum d’articles à conserver', - 'keep_history_help' => 'Mettre à -1 pour tout conserver', 'categorize' => 'Ranger dans une catégorie', 'truncate' => 'Supprimer tous les articles', 'advanced' => 'Avancé', @@ -165,10 +166,11 @@ return array ( 'allow_anonymous' => 'Autoriser la lecture anonyme', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.
%s?output=rss&token=%s', - 'archiving_configuration' => 'Configuration de l’archivage', + 'login_configuration' => 'Identification', + 'archiving_configuration' => 'Archivage', 'delete_articles_every' => 'Supprimer les articles après', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux', - 'reading_configuration' => 'Configuration de lecture', + 'reading_configuration' => 'Lecture', 'articles_per_page' => 'Nombre d’articles par page', 'default_view' => 'Vue par défaut', 'sort_order' => 'Ordre de tri', diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 8995dc839..3280f657f 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -31,6 +31,15 @@ +
+
+ + +
+
+ + +
conf->mailLogin (); ?> @@ -61,22 +70,22 @@
- +

+
- - - - - - - - - - -
- + +
+
+
+ +
+
diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index 5940055ed..e738ab64f 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -52,6 +52,15 @@ +
+ +
+ +
+
@@ -78,16 +87,11 @@
- - - - - - - - - - +
@@ -97,24 +101,7 @@
- -
- -
- -
-
-
- -
- - -
-
- + flux->httpAuth (false); ?>
@@ -131,7 +118,24 @@
- + + +
+
+ + +
+ +
+ + +
+
+ +
+
+ +
diff --git a/public/install.php b/public/install.php index 3885f143e..13abb010b 100644 --- a/public/install.php +++ b/public/install.php @@ -33,7 +33,7 @@ define ('SQL_FEED', 'CREATE TABLE IF NOT EXISTS `%1$sfeed` ( `pathEntries` varchar(511) DEFAULT NULL, `httpAuth` varchar(511) DEFAULT NULL, `error` boolean DEFAULT 0, - `keep_history` MEDIUMINT NOT NULL DEFAULT 0, + `keep_history` MEDIUMINT NOT NULL DEFAULT -2, -- v0.7, -2 = default `cache_nbEntries` int DEFAULT 0, -- v0.7 `cache_nbUnreads` int DEFAULT 0, -- v0.7 PRIMARY KEY (`id`), @@ -93,7 +93,7 @@ FROM `%1$scategory006` ORDER BY id2; INSERT IGNORE INTO `%2$sfeed` (url, category, name, website, description, priority, pathEntries, httpAuth, keep_history) -SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, -1 * keep_history +SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, IF(keep_history = 1, -1, -2) FROM `%1$sfeed006` ORDER BY id2; diff --git a/public/themes/default/freshrss.css b/public/themes/default/freshrss.css index e3c4c3c3b..2b157b27a 100644 --- a/public/themes/default/freshrss.css +++ b/public/themes/default/freshrss.css @@ -667,6 +667,10 @@ padding:.5em; } +select.number option { + text-align:right; +} + @media(max-width: 840px) { .header, .aside .btn-important, diff --git a/public/themes/default/global.css b/public/themes/default/global.css index 1c554d2dc..440fc6e41 100644 --- a/public/themes/default/global.css +++ b/public/themes/default/global.css @@ -99,6 +99,9 @@ input, select, textarea { vertical-align: middle; box-shadow: 0 2px 2px #eee inset; } + option { + padding:0 .5em 0 .5em; + } input[type="radio"], input[type="checkbox"] { width: 15px !important; diff --git a/public/themes/flat-design/freshrss.css b/public/themes/flat-design/freshrss.css index fa1ed13e6..7e3f4c81a 100644 --- a/public/themes/flat-design/freshrss.css +++ b/public/themes/flat-design/freshrss.css @@ -662,6 +662,10 @@ body { padding:.5em; } +select.number option { + text-align:right; +} + @media(max-width: 840px) { .header, .aside .btn-important, diff --git a/public/themes/flat-design/global.css b/public/themes/flat-design/global.css index 8cf6412b3..90b59d002 100644 --- a/public/themes/flat-design/global.css +++ b/public/themes/flat-design/global.css @@ -101,6 +101,9 @@ input, select, textarea { vertical-align: middle; border-radius: 5px; } + option { + padding:0 .5em 0 .5em; + } input[type="radio"], input[type="checkbox"] { width: 15px !important; -- cgit v1.2.3 From c2375265c040da5b71c4acf2871f5479fab3044c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 18:18:14 +0100 Subject: Fin taille historique MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Permet d'éviter les problèmes de flux vides à l'importation https://github.com/marienfressinaud/FreshRSS/issues/332 , ou de nombre d'articles non-lus qui ne correspondent pas au nombre d'articles affichés --- app/Models/EntryDAO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 14d3ddcff..99aaf3a0d 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -307,7 +307,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR (f.keep_history <> 0'; + $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0'; if (intval($keepHistoryDefault) === 0) { $where .= ' AND f.keep_history <> -2'; //default } -- cgit v1.2.3 From 0b3d79745d7b8db5dc684f91e0bbad6c1a03d0ee Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 18:50:05 +0100 Subject: Encodage titre flux pour cas Glazman --- app/Models/Feed.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index ef554e083..dcf97d4ec 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -250,11 +250,11 @@ class FreshRSS_Feed extends Minz_Model { $this->_url ($subscribe_url); } - $title = $feed->get_title (); + $title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8'); $this->_name (!is_null ($title) ? $title : $this->url); - $this->_website ($feed->get_link ()); - $this->_description ($feed->get_description ()); + $this->_website(html_only_entity_decode($feed->get_link())); + $this->_description(html_only_entity_decode($feed->get_description())); // et on charge les articles du flux $this->loadEntries ($feed); -- cgit v1.2.3 From 7eda2793bbc3210ae37aa66511fd7ad7661c2149 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 19:53:09 +0100 Subject: Nouveau bouton pour lancer manuellement la purge des vieux articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attention, si on supprime des articles qui sont encore dans les flux RSS, ils risquent de réapparaitre en cas de date manquante ou erronée, ou si l'utilisateur augmente la date d'expiration. Ce bouton est plus strict que la purge automatique qui conserve toujours au moins le même nombre d'articles que dans le flux RSS en cours + 10. --- app/Controllers/entryController.php | 41 +++++++++++++++++++++++++++++++++++++ app/Controllers/feedController.php | 2 +- app/Models/FeedDAO.php | 27 +++++++++++++----------- app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ app/views/configure/display.phtml | 1 + 6 files changed, 62 insertions(+), 13 deletions(-) (limited to 'app') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index a332ca8a9..1c3c56c4d 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -109,4 +109,45 @@ class FreshRSS_entry_Controller extends Minz_ActionController { 'a' => 'display' ), true); } + + public function purgeAction() { + @set_time_limit(300); + + $nb_month_old = max($this->view->conf->oldEntries(), 1); + $date_min = time() - (3600 * 24 * 30 * $nb_month_old); + + $feedDAO = new FreshRSS_FeedDAO(); + $feeds = $feedDAO->listFeedsOrderUpdate(); + $nbTotal = 0; + + invalidateHttpCache(); + + foreach ($feeds as $feed) { + $feedHistory = $feed->keepHistory(); + if ($feedHistory == -2) { //default + $feedHistory = $this->view->conf->keepHistoryDefault(); + } + if ($feedHistory >= 0) { + $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feedHistory); + if ($nb > 0) { + $nbTotal += $nb; + Minz_Log::record($nb . ' old entries cleaned in feed ' . $feed->id(), Minz_Log::DEBUG); + $feedDAO->updateLastUpdate($feed->id()); + } + } + } + + invalidateHttpCache(); + + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('purge_completed', $nbTotal) + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array( + 'c' => 'configure', + 'a' => 'display' + ), true); + } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 836044da6..04d0aa98b 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -192,7 +192,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } // on calcule la date des articles les plus anciens qu'on accepte - $nb_month_old = $this->view->conf->oldEntries (); + $nb_month_old = max($this->view->conf->oldEntries(), 1); $date_min = time () - (3600 * 24 * 30 * $nb_month_old); $i = 0; diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index c1d1f24e8..d517f9580 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -315,20 +315,23 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if (isset ($dao['id'])) { $key = $dao['id']; } + if ($catID === null) { + $catID = isset($dao['category']) ? $dao['category'] : 0; + } - $myFeed = new FreshRSS_Feed (isset($dao['url']) ? $dao['url'] : '', false); - $myFeed->_category ($catID === null ? $dao['category'] : $catID); - $myFeed->_name ($dao['name']); - $myFeed->_website ($dao['website'], false); - $myFeed->_description (isset($dao['description']) ? $dao['description'] : ''); - $myFeed->_lastUpdate (isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0); - $myFeed->_priority ($dao['priority']); - $myFeed->_pathEntries (isset($dao['pathEntries']) ? $dao['pathEntries'] : ''); - $myFeed->_httpAuth (isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : ''); - $myFeed->_error ($dao['error']); + $myFeed = new FreshRSS_Feed(isset($dao['url']) ? $dao['url'] : '', false); + $myFeed->_category(intval($catID)); + $myFeed->_name($dao['name']); + $myFeed->_website(isset($dao['website']) ? $dao['website'] : '', false); + $myFeed->_description(isset($dao['description']) ? $dao['description'] : ''); + $myFeed->_lastUpdate(isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0); + $myFeed->_priority(isset($dao['priority']) ? $dao['priority'] : 10); + $myFeed->_pathEntries(isset($dao['pathEntries']) ? $dao['pathEntries'] : ''); + $myFeed->_httpAuth(isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : ''); + $myFeed->_error(isset($dao['error']) ? $dao['error'] : 0); $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : -2); - $myFeed->_nbNotRead ($dao['cache_nbUnreads']); - $myFeed->_nbEntries ($dao['cache_nbEntries']); + $myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0); + $myFeed->_nbEntries(isset($dao['cache_nbEntries']) ? $dao['cache_nbEntries'] : 0); if (isset ($dao['id'])) { $myFeed->_id ($dao['id']); } diff --git a/app/i18n/en.php b/app/i18n/en.php index ca72d885c..498fccd14 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -168,6 +168,8 @@ return array ( 'login_configuration' => 'Login', 'archiving_configuration' => 'Archiving', 'delete_articles_every' => 'Remove articles after', + 'purge_now' => 'Purge now', + 'purge_completed' => 'Purge completed (%d articles deleted)', 'archiving_configuration_help' => 'More options are available in the individual stream settings', 'reading_configuration' => 'Reading', 'articles_per_page' => 'Number of articles per page', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 053a97c8a..c918daa44 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -169,6 +169,8 @@ return array ( 'login_configuration' => 'Identification', 'archiving_configuration' => 'Archivage', 'delete_articles_every' => 'Supprimer les articles après', + 'purge_now' => 'Purger maintenant', + 'purge_completed' => 'Purge effectuée (%d articles supprimés)', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux', 'reading_configuration' => 'Lecture', 'articles_per_page' => 'Nombre d’articles par page', diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 3280f657f..fca533752 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -76,6 +76,7 @@
+  
-- cgit v1.2.3 From d24b1e963e208a03f08b1d17ed9f319bd59a36ad Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 21:46:24 +0100 Subject: Lancer automatiquement le raffraîchissement des flux après une mise à jour de FreshRSS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/330 --- app/FreshRSS.php | 2 +- app/views/helpers/javascript_vars.phtml | 7 ++++--- constants.php | 2 +- lib/Minz/Session.php | 30 ++++++++++++++++-------------- public/install.php | 4 +++- 5 files changed, 25 insertions(+), 20 deletions(-) (limited to 'app') diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 90548793d..60610e352 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -1,7 +1,7 @@ loadParamsView (); diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 0c1af45fc..d008e2e48 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -39,7 +39,8 @@ echo 'str_confirmation="', Minz_Translate::t('confirm_action'), '"', ",\n"; - echo 'auto_actualize_feeds=', Minz_Session::param('actualize_feeds', false) ? 'true' : 'false', ";\n"; - if (Minz_Session::param('actualize_feeds', false)) { - Minz_Session::_param('actualize_feeds'); + $autoActualise = Minz_Session::param('actualize_feeds', false); + echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n"; + if ($autoActualise) { + Minz_Session::_param('actualize_feeds', false); } diff --git a/constants.php b/constants.php index 272647947..c22209efe 100644 --- a/constants.php +++ b/constants.php @@ -1,5 +1,5 @@ 3 && $s3['all'] != 'ok') { header ('Location: index.php?step=3'); } + $_SESSION['actualize_feeds'] = true; } function checkStep0 () { moveOldFiles() && removeOldFiles(); -- cgit v1.2.3 From 1da74b1eddfafd9191548e0fde150690b80f694b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 25 Dec 2013 23:57:02 +0100 Subject: Affichage version dans "à propos" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/index/about.phtml | 3 +++ 3 files changed, 5 insertions(+) (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index 498fccd14..40c634f7c 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -239,6 +239,7 @@ return array ( 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', '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.', + 'version' => 'Version', 'logs' => 'Logs', 'logs_empty' => 'Log file is empty', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index c918daa44..14160bb7e 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -240,6 +240,7 @@ return array ( 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', '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.', + 'version' => 'Version', 'logs' => 'Logs', 'logs_empty' => 'Les logs sont vides', diff --git a/app/views/index/about.phtml b/app/views/index/about.phtml index b5c00a1ed..ae64727d7 100644 --- a/app/views/index/about.phtml +++ b/app/views/index/about.phtml @@ -15,6 +15,9 @@
+ +
+

-- cgit v1.2.3 From 2788aaeb1a463012cfa90bf31f5efb4bf6ca7344 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 02:50:58 +0100 Subject: Problème ctype_digit qui ne marche pas sur des variables qui sont déjà des entiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/Configuration.php | 16 +++++----------- app/Models/Entry.php | 7 ++----- app/Models/Feed.php | 7 ++++--- 3 files changed, 11 insertions(+), 19 deletions(-) (limited to 'app') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 47509636f..cb2f90655 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -220,19 +220,13 @@ class FreshRSS_Configuration extends Minz_Model { public function _sortOrder ($value) { $this->sort_order = $value === 'ASC' ? 'ASC' : 'DESC'; } - public function _oldEntries ($value) { - if (ctype_digit ($value) && $value > 0) { - $this->old_entries = intval($value); - } else { - $this->old_entries = 3; - } + public function _oldEntries($value) { + $value = intval($value); + $this->old_entries = $value > 0 ? $value : 3; } public function _keepHistoryDefault($value) { - if (ctype_digit($value) && $value >= -1) { - $this->keep_history_default = intval($value); - } else { - $this->keep_history_default = 0; - } + $value = intval($value); + $this->keep_history_default = $value >= -1 ? $value : 0; } public function _shortcuts ($values) { foreach ($values as $key => $value) { diff --git a/app/Models/Entry.php b/app/Models/Entry.php index ed31ef2b1..ab9605eb1 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -106,11 +106,8 @@ class FreshRSS_Entry extends Minz_Model { $this->link = $value; } public function _date ($value) { - if (ctype_digit ($value)) { - $this->date = intval ($value); - } else { - $this->date = time (); - } + $value = intval($value); + $this->date = $value > 1 ? $value : time(); } public function _isRead ($value) { $this->is_read = $value; diff --git a/app/Models/Feed.php b/app/Models/Feed.php index dcf97d4ec..3008e33d7 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -154,7 +154,8 @@ class FreshRSS_Feed extends Minz_Model { $this->lastUpdate = $value; } public function _priority ($value) { - $this->priority = ctype_digit ($value) ? intval ($value) : 10; + $value = intval($value); + $this->priority = $value >= 0 ? $value : 10; } public function _pathEntries ($value) { $this->pathEntries = $value; @@ -172,10 +173,10 @@ class FreshRSS_Feed extends Minz_Model { $this->keep_history = $value; } public function _nbNotRead ($value) { - $this->nbNotRead = ctype_digit ($value) ? intval ($value) : -1; + $this->nbNotRead = intval($value); } public function _nbEntries ($value) { - $this->nbEntries = ctype_digit ($value) ? intval ($value) : -1; + $this->nbEntries = intval($value); } public function load () { -- cgit v1.2.3 From 3ba5223e1350bf0c38a81722a7669871400b340a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 13:26:05 +0100 Subject: Déplacement de ./actualize_script.php sous ./app/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pour une meilleure protection par défaut --- CHANGELOG | 1 + README.md | 2 +- actualize_script.php | 15 --------------- app/.htaccess | 3 +++ app/actualize_script.php | 15 +++++++++++++++ app/index.html | 13 +++++++++++++ data/index.html | 2 +- index.html | 1 + lib/.htaccess | 3 +++ 9 files changed, 38 insertions(+), 17 deletions(-) delete mode 100755 actualize_script.php create mode 100644 app/.htaccess create mode 100755 app/actualize_script.php create mode 100644 app/index.html create mode 100644 lib/.htaccess (limited to 'app') diff --git a/CHANGELOG b/CHANGELOG index 9ae3d3f62..336245269 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,6 +53,7 @@ * Déplacement de “./public/data/Configuration.array.php” vers “./data/*_user.php” * Déplacement de “./public/index.php” vers “./p/i/index.php” (voir cookie ci-dessous) * Déplacement de “./public/” vers “./p/” + * Déplacement de “./actualize_script.php” vers “./app/actualize_script.php” * Divers : * Nouvelle politique de cookie de session (témoin de connexion) * Utilise un nom poli “FreshRSS” diff --git a/README.md b/README.md index 210ec64cc..5051a936c 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Il est recommandé de limiter l’accès à votre FreshRSS, soit : # Rafraîchissement automatique des flux * Vous pouvez ajouter une tâche CRON sur le script d’actualisation des flux. Par exemple, pour exécuter le script toutes les heures : ``` -7 * * * * php /chemin/vers/freshrss/actualize_script.php >/dev/null 2>&1 +7 * * * * php /chemin/vers/FreshRSS/app/actualize_script.php >/dev/null 2>&1 ``` # Conseils diff --git a/actualize_script.php b/actualize_script.php deleted file mode 100755 index 7986ba0b5..000000000 --- a/actualize_script.php +++ /dev/null @@ -1,15 +0,0 @@ -init (); -Minz_Session::_param('mail', true); // permet de se passer de la phase de connexion -$front_controller->run (); -invalidateHttpCache(); diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 000000000..9e768397d --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,3 @@ +Order Allow,Deny +Deny from all +Satisfy all diff --git a/app/actualize_script.php b/app/actualize_script.php new file mode 100755 index 000000000..20438128a --- /dev/null +++ b/app/actualize_script.php @@ -0,0 +1,15 @@ +init (); +Minz_Session::_param('mail', true); // permet de se passer de la phase de connexion +$front_controller->run (); +invalidateHttpCache(); diff --git a/app/index.html b/app/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/app/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/index.html b/data/index.html index 2f3b51848..85faaa37e 100644 --- a/data/index.html +++ b/data/index.html @@ -4,7 +4,7 @@ Redirection - + diff --git a/index.html b/index.html index bbea573c7..1bfdea859 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ Redirection + diff --git a/lib/.htaccess b/lib/.htaccess new file mode 100644 index 000000000..9e768397d --- /dev/null +++ b/lib/.htaccess @@ -0,0 +1,3 @@ +Order Allow,Deny +Deny from all +Satisfy all -- cgit v1.2.3 From 574d37bddc4e00ddbc6af57c28838e1dea6a730b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 19:58:17 +0100 Subject: Favicons compatibles multi-utilisateurs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/Controllers/feedController.php | 2 +- app/Models/CategoryDAO.php | 2 +- app/Models/Feed.php | 13 +++++++++---- lib/Minz/Configuration.php | 2 +- p/f.php | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 04d0aa98b..dc8a854a9 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -395,7 +395,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'type' => 'good', 'content' => Minz_Translate::t ('feed_deleted') ); - FreshRSS_Feed::faviconDelete($id); + //TODO: Delete old favicon } else { $notif = array ( 'type' => 'bad', diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 6b07ab063..1cc616ac0 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -90,7 +90,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if ($prePopulateFeeds) { $sql = 'SELECT c.id AS c_id, c.name AS c_name, ' . ($details ? 'c.color AS c_color, ' : '') - . ($details ? 'f.* ' : 'f.id, f.name, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ') + . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ') . 'FROM `' . $this->prefix . 'category` c ' . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category = c.id ' . 'GROUP BY f.id ' diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 3008e33d7..f9a586122 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -28,6 +28,11 @@ class FreshRSS_Feed extends Minz_Model { public function id () { return $this->id; } + + public function hash() { + return hash('crc32b', Minz_Configuration::salt() . $this->url); + } + public function url () { return $this->url; } @@ -96,7 +101,7 @@ class FreshRSS_Feed extends Minz_Model { return $this->nbNotRead; } public function faviconPrepare() { - $file = DATA_PATH . '/favicons/' . $this->id () . '.txt'; + $file = DATA_PATH . '/favicons/' . $this->hash() . '.txt'; if (!file_exists ($file)) { $t = $this->website; if (empty($t)) { @@ -105,13 +110,13 @@ class FreshRSS_Feed extends Minz_Model { file_put_contents($file, $t); } } - public static function faviconDelete($id) { - $path = DATA_PATH . '/favicons/' . $id; + public static function faviconDelete($hash) { + $path = DATA_PATH . '/favicons/' . $hash; @unlink($path . '.ico'); @unlink($path . '.txt'); } public function favicon () { - return Minz_Url::display ('/f.php?' . $this->id ()); + return Minz_Url::display ('/f.php?' . $this->hash()); } public function _id ($value) { diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 1b108dcdf..6c7206988 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -63,7 +63,7 @@ class Minz_Configuration { /* * Getteurs */ - public static function selApplication () { + public static function salt () { return self::$sel_application; } public static function environment () { diff --git a/p/f.php b/p/f.php index a56d58617..872b8cc2c 100644 --- a/p/f.php +++ b/p/f.php @@ -37,7 +37,7 @@ function download_favicon ($website, $dest) { } $id = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '0'; -if (!ctype_digit($id)) { +if (!ctype_xdigit($id)) { $id = '0'; } -- cgit v1.2.3 From 2c57e7254d613683ec20076d37b33ea2a7dd2d83 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 20:11:18 +0100 Subject: Favicons : test pour améliorer le cache HTTP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test d'utilisation de PATH_INFO plutôt que QUERY_STRING pour améliorer la mise en cache. À tester sur différents serveurs --- app/Models/Feed.php | 2 +- p/f.php | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index f9a586122..4f90b9872 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -116,7 +116,7 @@ class FreshRSS_Feed extends Minz_Model { @unlink($path . '.txt'); } public function favicon () { - return Minz_Url::display ('/f.php?' . $this->hash()); + return Minz_Url::display ('/f.php/' . $this->hash()); } public function _id ($value) { diff --git a/p/f.php b/p/f.php index 872b8cc2c..660128a59 100644 --- a/p/f.php +++ b/p/f.php @@ -36,7 +36,14 @@ function download_favicon ($website, $dest) { return true; } -$id = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '0'; +if (isset($_SERVER['PATH_INFO'])) { + $id = substr($_SERVER['PATH_INFO'], 1); +} elseif (isset($_SERVER['QUERY_STRING'])) { + $id = $_SERVER['QUERY_STRING']; +} else { + $id = '0'; +} + if (!ctype_xdigit($id)) { $id = '0'; } -- cgit v1.2.3 From 43fd0a543900866f4feaf0713e1726b98a60b22d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 22:20:24 +0100 Subject: Mise à jour de f.url en base de données lorsque SimplePie découvre que l'adresse a changé MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Et correction problème favicon lorsque l'adresse du flux a changé du point de vue de SimplePie. Plus petites optimisations. --- app/Controllers/entryController.php | 2 +- app/Controllers/feedController.php | 27 ++++++++++----------------- app/Models/Feed.php | 18 ++++++++++++------ 3 files changed, 23 insertions(+), 24 deletions(-) (limited to 'app') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 1c3c56c4d..26f3422ca 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -131,7 +131,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feedHistory); if ($nb > 0) { $nbTotal += $nb; - Minz_Log::record($nb . ' old entries cleaned in feed ' . $feed->id(), Minz_Log::DEBUG); + Minz_Log::record($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG); $feedDAO->updateLastUpdate($feed->id()); } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index dc8a854a9..ca230232f 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -20,15 +20,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $this->catDAO->checkDefault (); } - private static function entryDateComparer($e1, $e2) { - $d1 = $e1->date(true); - $d2 = $e2->date(true); - if ($d1 === $d2) { - return 0; - } - return ($d1 < $d2) ? -1 : 1; - } - public function addAction () { @set_time_limit(300); @@ -55,7 +46,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $feed->_httpAuth ($httpAuth); - $feed->load (); + $feed->load(true); $feedDAO = new FreshRSS_FeedDAO (); $values = array ( @@ -91,8 +82,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; $entryDAO = new FreshRSS_EntryDAO (); - $entries = $feed->entries (); - usort($entries, 'self::entryDateComparer'); + $entries = array_reverse($feed->entries()); //We want chronological order and SimplePie uses reverse order // on calcule la date des articles les plus anciens qu'on accepte $nb_month_old = $this->view->conf->oldEntries (); @@ -199,10 +189,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $flux_update = 0; foreach ($feeds as $feed) { try { - $feed->load (); - $feed->faviconPrepare(); - $entries = $feed->entries (); - usort($entries, 'self::entryDateComparer'); + $url = $feed->url(); + $feed->load(false); + $entries = array_reverse($feed->entries()); //We want chronological order and SimplePie uses reverse order $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; @@ -231,7 +220,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (($feedHistory >= 0) && (rand(0, 30) === 1)) { $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10)); if ($nb > 0) { - Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG); + Minz_Log::record ($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG); } } @@ -239,6 +228,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->updateLastUpdate ($feed->id ()); $feedDAO->commit (); $flux_update++; + if ($feed->url() !== $url) { //URL has changed (auto-discovery) + $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); + } + $feed->faviconPrepare(); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); $feedDAO->updateLastUpdate ($feed->id (), 1); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 4f90b9872..0f467f776 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -16,6 +16,7 @@ class FreshRSS_Feed extends Minz_Model { private $httpAuth = ''; private $error = false; private $keep_history = -2; + private $hash = null; public function __construct ($url, $validate=true) { if ($validate) { @@ -30,7 +31,10 @@ class FreshRSS_Feed extends Minz_Model { } public function hash() { - return hash('crc32b', Minz_Configuration::salt() . $this->url); + if ($this->hash === null) { + $this->hash = hash('crc32b', Minz_Configuration::salt() . $this->url); + } + return $this->hash; } public function url () { @@ -184,7 +188,7 @@ class FreshRSS_Feed extends Minz_Model { $this->nbEntries = intval($value); } - public function load () { + public function load ($loadDetails = false) { if (!is_null ($this->url)) { if (CACHE_PATH === false) { throw new Minz_FileNotExistException ( @@ -256,11 +260,13 @@ class FreshRSS_Feed extends Minz_Model { $this->_url ($subscribe_url); } - $title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8'); - $this->_name (!is_null ($title) ? $title : $this->url); + if ($loadDetails) { + $title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8'); + $this->_name (!is_null ($title) ? $title : $this->url); - $this->_website(html_only_entity_decode($feed->get_link())); - $this->_description(html_only_entity_decode($feed->get_description())); + $this->_website(html_only_entity_decode($feed->get_link())); + $this->_description(html_only_entity_decode($feed->get_description())); + } // et on charge les articles du flux $this->loadEntries ($feed); -- cgit v1.2.3 From 3cbcc9f1b3c7b93b85c951a005f205fdab8d475e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 26 Dec 2013 22:39:13 +0100 Subject: Problème comparaison chaîne / entier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/layout/nav_menu.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 045f391f9..1f2a7b408 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -25,7 +25,7 @@ switch ($get[0]) { case 'c': foreach ($this->cat_aside as $cat) { - if ($cat->id () === $this->get_c) { + if ($cat->id () == $this->get_c) { $foundCurrent = true; continue; } @@ -37,9 +37,9 @@ break; case 'f': foreach ($this->cat_aside as $cat) { - if ($cat->id () === $this->get_c) { + if ($cat->id () == $this->get_c) { foreach ($cat->feeds () as $feed) { - if ($feed->id () === $this->get_f) { + if ($feed->id () == $this->get_f) { $foundCurrent = true; continue; } -- cgit v1.2.3 From f8b8dc7a23f6c1d5d328c91a25c682c62d6f3649 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2013 12:30:57 +0100 Subject: Mise à jour possible depuis v0.7-beta[1-2] + correction message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Correction message lorsqu'on clique sur "enregistrer" un flux où rien n'a changé et qui disait qu'une erreur était survenue alors que simplement rien n'avait changé --- app/i18n/en.php | 2 +- app/i18n/fr.php | 2 +- p/i/install.php | 12 +++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index 40c634f7c..f74a7f198 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -60,7 +60,7 @@ return array ( 'access_denied' => 'You don’t have permission to access this page', 'page_not_found' => 'You are looking for a page which doesn’t exist', 'error_occurred' => 'An error occurred', - 'error_occurred_update' => 'An error occurred during update', + 'error_occurred_update' => 'Nothing was changed', 'default_category' => 'Uncategorized', 'categories_updated' => 'Categories have been updated', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 14160bb7e..f9c4d00cc 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -60,7 +60,7 @@ return array ( 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page', 'page_not_found' => 'La page que vous cherchez n’existe pas', 'error_occurred' => 'Une erreur est survenue', - 'error_occurred_update' => 'Une erreur est survenue lors de la mise à jour', + 'error_occurred_update' => 'Rien n’a été modifié', 'default_category' => 'Sans catégorie', 'categories_updated' => 'Les catégories ont été mises à jour', diff --git a/p/i/install.php b/p/i/install.php index fa37ae19a..8db372fef 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -117,7 +117,9 @@ WHERE e1.content_bin IS NULL'); define('SQL_CONVERT_UPDATEv006', 'UPDATE `%1$sentry` SET content_bin=COMPRESS(?) WHERE id=?;'); -define('SQL_UPDATE_CACHED_VALUESv006', ' +define('SQL_DROP_BACKUPv006', 'DROP TABLE IF EXISTS `%1$sentry006`, `%1$sfeed006`, `%1$scategory006`;'); + +define('SQL_UPDATE_CACHED_VALUES', ' UPDATE `%1$sfeed` f INNER JOIN ( SELECT e.id_feed, @@ -129,7 +131,7 @@ INNER JOIN ( SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads '); -define('SQL_DROP_BACKUPv006', 'DROP TABLE IF EXISTS `%1$sentry006`, `%1$sfeed006`, `%1$scategory006`;'); +define('SQL_UPDATE_HISTORYv007b', 'UPDATE `%1$sfeed` SET keep_history = CASE WHEN keep_history = 0 THEN -2 WHEN keep_history = 1 THEN -1 ELSE keep_history END;'); // function writeLine ($f, $line) { @@ -349,7 +351,11 @@ function updateDatabase($perform = false) { $stm->execute(); } - $sql = sprintf(SQL_UPDATE_CACHED_VALUESv006, $_SESSION['bd_prefix_user']); + $sql = sprintf(SQL_UPDATE_HISTORYv007b, $_SESSION['bd_prefix_user']); + $stm = $c->prepare($sql); + $stm->execute(); + + $sql = sprintf(SQL_UPDATE_CACHED_VALUES, $_SESSION['bd_prefix_user']); $stm = $c->prepare($sql); $stm->execute(); -- cgit v1.2.3 From b99979cef78f7cd0c1cb4ae81115d09881e85926 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2013 14:11:17 +0100 Subject: Bug affichage ID category introduit récemment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/Feed.php | 3 ++- app/Models/FeedDAO.php | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 0f467f776..32f8546dd 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -136,7 +136,8 @@ class FreshRSS_Feed extends Minz_Model { $this->url = $value; } public function _category ($value) { - $this->category = $value; + $value = intval($value); + $this->category = $value >= 0 ? $value : 0; } public function _name ($value) { if (is_null ($value)) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index d517f9580..e102da4ec 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -316,11 +316,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $key = $dao['id']; } if ($catID === null) { - $catID = isset($dao['category']) ? $dao['category'] : 0; + $category = isset($dao['category']) ? $dao['category'] : 0; + } else { + $category = $catID ; } $myFeed = new FreshRSS_Feed(isset($dao['url']) ? $dao['url'] : '', false); - $myFeed->_category(intval($catID)); + $myFeed->_category($category); $myFeed->_name($dao['name']); $myFeed->_website(isset($dao['website']) ? $dao['website'] : '', false); $myFeed->_description(isset($dao['description']) ? $dao['description'] : ''); -- cgit v1.2.3 From badc60910a21774512034027bbb394ffeb477629 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2013 15:16:53 +0100 Subject: Petites corrections et sortie 0.7-beta3 --- app/Controllers/feedController.php | 12 ++++++------ p/i/install.php | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ca230232f..a3371a43e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -198,12 +198,17 @@ class FreshRSS_feed_Controller extends Minz_ActionController { //For this feed, check last n entry GUIDs already in database $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); + $feedHistory = $feed->keepHistory(); + if ($feedHistory == -2) { //default + $feedHistory = $this->view->conf->keepHistoryDefault(); + } + // On ne vérifie pas strictement que l'article n'est pas déjà en BDD // La BDD refusera l'ajout car (id_feed, guid) doit être unique $feedDAO->beginTransaction (); foreach ($entries as $entry) { if ((!isset ($existingGuids[$entry->guid ()])) && - ($entry->date (true) >= $date_min)) { + (($feedHistory != 0) || ($entry->date (true) >= $date_min))) { $values = $entry->toArray (); //Use declared date at first import, otherwise use discovery date $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString(); @@ -212,11 +217,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - $feedHistory = $feed->keepHistory(); - if ($feedHistory == -2) { //default - $feedHistory = $this->view->conf->keepHistoryDefault(); - } - if (($feedHistory >= 0) && (rand(0, 30) === 1)) { $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10)); if ($nb > 0) { diff --git a/p/i/install.php b/p/i/install.php index 0e8a972c6..132cd5508 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -573,7 +573,7 @@ function checkStep2 () { if ($defaultUser === null) { $defaultUser = empty($_SESSION['default_user']) ? '' : $_SESSION['default_user']; } - $data = file_exists (DATA_PATH . '/' . $defaultUser . '_user.php'); + $data = is_writable(DATA_PATH . '/' . $defaultUser . '_user.php'); if ($data) { @unlink(DATA_PATH . '/Configuration.array.php'); //v0.6 } @@ -585,7 +585,7 @@ function checkStep2 () { ); } function checkStep3 () { - $conf = file_exists (DATA_PATH . '/config.php'); + $conf = is_writable(DATA_PATH . '/config.php'); $bd = isset ($_SESSION['bd_type']) && isset ($_SESSION['bd_host']) && -- cgit v1.2.3 From a1249e56a7151ea20f64ac3091c0a3383d21049c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2013 16:24:40 +0100 Subject: Petit changement utilisation de la date déclarée des articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG | 2 +- app/Controllers/feedController.php | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/CHANGELOG b/CHANGELOG index 9d91544c4..108e29195 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -62,7 +62,7 @@ * Utilise un nom poli “FreshRSS” (évite des problèmes avec certains filtres) * Se limite au répertoire “./FreshRSS/p/i/” pour de meilleures performances HTTP * Les images, CSS, scripts sont servis sans cookie - * utilise “HttpOnly” pour plus de sécurité + * Utilise “HttpOnly” pour plus de sécurité * Nouvel “agent utilisateur” exposé lors du téléchargement des flux, par exemple : * “FreshRSS/0.7 (Linux; http://freshrss.org) SimplePie/1.3.1” * Affichage du numéro de version dans "À propos" diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index a3371a43e..77d36e977 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -197,6 +197,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { //For this feed, check last n entry GUIDs already in database $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); + $useDeclaredDate = empty($existingGuids); $feedHistory = $feed->keepHistory(); if ($feedHistory == -2) { //default @@ -207,11 +208,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // La BDD refusera l'ajout car (id_feed, guid) doit être unique $feedDAO->beginTransaction (); foreach ($entries as $entry) { + $eDate = $entry->date (true); if ((!isset ($existingGuids[$entry->guid ()])) && - (($feedHistory != 0) || ($entry->date (true) >= $date_min))) { + (($feedHistory != 0) || ($eDate >= $date_min))) { $values = $entry->toArray (); //Use declared date at first import, otherwise use discovery date - $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString(); + $values['id'] = ($useDeclaredDate || $eDate < $date_min) ? + min(time(), $eDate) . uSecString() : + uTimeString(); $values['is_read'] = $is_read; $entryDAO->addEntry ($values); } -- cgit v1.2.3 From 9f52ab97cb947944546917623d8fe0999d8bda9b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2013 19:23:11 +0100 Subject: Début 0.8-dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 --- README.md | 4 +- app/Controllers/configureController.php | 93 +++++++++++++++++++++++++-------- app/i18n/en.php | 10 ++-- app/i18n/fr.php | 11 ++-- app/layout/aside_configure.phtml | 13 +++-- app/layout/header.phtml | 4 +- app/views/configure/archiving.phtml | 47 +++++++++++++++++ app/views/configure/display.phtml | 73 +------------------------- app/views/configure/users.phtml | 72 +++++++++++++++++++++++++ constants.php | 2 +- 10 files changed, 217 insertions(+), 112 deletions(-) create mode 100644 app/views/configure/archiving.phtml create mode 100644 app/views/configure/users.phtml (limited to 'app') diff --git a/README.md b/README.md index 1f1ab35c3..f20f870dd 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Il se veut léger et facile à prendre en main tout en étant un outil puissant * Site officiel : http://freshrss.org * Démo : http://marienfressinaud.fr/projets/freshrss/ * Développeur : Marien Fressinaud -* Version actuelle : 0.7-beta3 -* Date de publication 2014-01-xx +* Version actuelle : 0.8-dev +* Date de publication 2014-xx-xx * License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html) ![Logo de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 762134dd0..5fa686ccc 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -159,11 +159,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $onread_jump_next = Minz_Request::param ('onread_jump_next', 'no'); $lazyload = Minz_Request::param ('lazyload', 'no'); $sort = Minz_Request::param ('sort_order', 'DESC'); - $old = Minz_Request::param ('old_entries', 3); - $keepHistoryDefault = Minz_Request::param('keep_history_default', 0); - $mail = Minz_Request::param ('mail_login', false); - $anon = Minz_Request::param ('anon_access', 'no'); - $token = Minz_Request::param ('token', $current_token); $openArticle = Minz_Request::param ('mark_open_article', 'no'); $openSite = Minz_Request::param ('mark_open_site', 'no'); $scroll = Minz_Request::param ('mark_scroll', 'no'); @@ -189,11 +184,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_onread_jump_next ($onread_jump_next); $this->view->conf->_lazyload ($lazyload); $this->view->conf->_sortOrder ($sort); - $this->view->conf->_oldEntries ($old); - $this->view->conf->_keepHistoryDefault($keepHistoryDefault); - $this->view->conf->_mailLogin ($mail); - $this->view->conf->_anonAccess ($anon); - $this->view->conf->_token ($token); $this->view->conf->_markWhen (array ( 'article' => $openArticle, 'site' => $openSite, @@ -219,14 +209,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'default_view' => $this->view->conf->defaultView (), 'auto_load_more' => $this->view->conf->autoLoadMore (), 'display_posts' => $this->view->conf->displayPosts (), - 'onread_jump_next' => $this->view->conf->onread_jump_next (), + 'onread_jump_next' => $this->view->conf->onread_jump_next (), 'lazyload' => $this->view->conf->lazyload (), 'sort_order' => $this->view->conf->sortOrder (), - 'old_entries' => $this->view->conf->oldEntries (), - 'keep_history_default' => $this->view->conf->keepHistoryDefault(), - 'mail_login' => $this->view->conf->mailLogin (), - 'anon_access' => $this->view->conf->anonAccess (), - 'token' => $this->view->conf->token (), 'mark_when' => $this->view->conf->markWhen (), 'theme' => $this->view->conf->theme (), 'topline_read' => $this->view->conf->toplineRead () ? 'yes' : 'no', @@ -261,11 +246,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->themes = FreshRSS_Themes::get(); - Minz_View::prependTitle (Minz_Translate::t ('general_and_reading_management') . ' - '); - - $entryDAO = new FreshRSS_EntryDAO (); - $this->view->nb_total = $entryDAO->count (); - $this->view->size_total = $entryDAO->size (); + Minz_View::prependTitle (Minz_Translate::t ('reading_configuration') . ' - '); } public function sharingAction () { @@ -410,4 +391,74 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle (Minz_Translate::t ('shortcuts_management') . ' - '); } + + public function usersAction() { + if (Minz_Request::isPost()) { + $current_token = $this->view->conf->token(); + + $mail = Minz_Request::param('mail_login', false); + $anon = Minz_Request::param('anon_access', 'no'); + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_mailLogin($mail); + $this->view->conf->_anonAccess($anon); + $this->view->conf->_token($token); + + $values = array( + 'mail_login' => $this->view->conf->mailLogin(), + 'anon_access' => $this->view->conf->anonAccess(), + 'token' => $this->view->conf->token(), + ); + + $confDAO = new FreshRSS_ConfigurationDAO(); + $confDAO->update($values); + Minz_Session::_param('conf', $this->view->conf); + Minz_Session::_param('mail', $this->view->conf->mailLogin()); + + // notif + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('configuration_updated') + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + + Minz_View::prependTitle(Minz_Translate::t ('users') . ' - '); + } + + public function archivingAction () { + if (Minz_Request::isPost()) { + $old = Minz_Request::param('old_entries', 3); + $keepHistoryDefault = Minz_Request::param('keep_history_default', 0); + + $this->view->conf->_oldEntries($old); + $this->view->conf->_keepHistoryDefault($keepHistoryDefault); + + $values = array( + 'old_entries' => $this->view->conf->oldEntries(), + 'keep_history_default' => $this->view->conf->keepHistoryDefault(), + ); + + $confDAO = new FreshRSS_ConfigurationDAO(); + $confDAO->update($values); + Minz_Session::_param('conf', $this->view->conf); + Minz_Session::_param('mail', $this->view->conf->mailLogin ()); + + // notif + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('configuration_updated') + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array('c' => 'configure', 'a' => 'archiving'), true); + } + + Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' - '); + + $entryDAO = new FreshRSS_EntryDAO(); + $this->view->nb_total = $entryDAO->count(); + $this->view->size_total = $entryDAO->size(); + } } diff --git a/app/i18n/en.php b/app/i18n/en.php index f74a7f198..a1ab4a025 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -8,7 +8,7 @@ return array ( 'search_short' => 'Search', 'configuration' => 'Configuration', - 'general_and_reading' => 'General and reading', + 'users' => 'Users', 'categories' => 'Categories', 'category' => 'Category', 'shortcuts' => 'Shortcuts', @@ -68,7 +68,6 @@ return array ( 'feed_updated' => 'Feed has been updated', 'rss_feed_management' => 'RSS feeds management', 'configuration_updated' => 'Configuration has been updated', - 'general_and_reading_management'=> 'General and reading management', 'sharing_management' => 'Sharing options management', 'bad_opml_file' => 'Your OPML file is invalid', 'shortcuts_updated' => 'Shortcuts have been updated', @@ -157,15 +156,16 @@ return array ( 'no_selected_feed' => 'No feed selected.', 'think_to_add' => 'Think to add RSS feeds!', - 'general_configuration' => 'General configuration', - 'language' => 'Language', - 'month' => 'months', + 'current_user' => 'Current user', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', 'persona_connection_email' => 'Login mail address (use Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output without authentication.
%s?token=%s', 'login_configuration' => 'Login', + + 'language' => 'Language', + 'month' => 'months', 'archiving_configuration' => 'Archiving', 'delete_articles_every' => 'Remove articles after', 'purge_now' => 'Purge now', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index f9c4d00cc..f4e9d109c 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -8,7 +8,7 @@ return array ( 'search_short' => 'Rechercher', 'configuration' => 'Configuration', - 'general_and_reading' => 'Général et lecture', + 'users' => 'Utilisateurs', 'categories' => 'Catégories', 'category' => 'Catégorie', 'shortcuts' => 'Raccourcis', @@ -68,7 +68,6 @@ return array ( 'feed_updated' => 'Le flux a été mis à jour', 'rss_feed_management' => 'Gestion des flux RSS', 'configuration_updated' => 'La configuration a été mise à jour', - 'general_and_reading_management'=> 'Gestion générale et affichage', 'sharing_management' => 'Gestion des options de partage', 'bad_opml_file' => 'Votre fichier OPML n’est pas valide', 'shortcuts_updated' => 'Les raccourcis ont été mis à jour', @@ -157,16 +156,16 @@ return array ( 'no_selected_feed' => 'Aucun flux sélectionné.', 'think_to_add' => 'Pensez à en ajouter !', - 'general_configuration' => 'Configuration générale', - 'language' => 'Langue', - - 'month' => 'mois', + 'current_user' => 'Utilisateur actuel', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', 'persona_connection_email' => 'Adresse courriel de connexion (utilise Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.
%s?output=rss&token=%s', 'login_configuration' => 'Identification', + + 'language' => 'Langue', + 'month' => 'mois', 'archiving_configuration' => 'Archivage', 'delete_articles_every' => 'Supprimer les articles après', 'purge_now' => 'Purger maintenant', diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index aa46af95d..89f63e36c 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -1,8 +1,13 @@ - + diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 6cb1380a3..bba22508e 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -57,7 +57,9 @@
- - -
- - conf->mailLogin (); ?> -
- - - -
-
- -
- - conf->token (); ?> -
- - -
-
- -
-
- - -
-
- - -

- -
- -
- -   -
-
-
- -
- -
-
- -
-
- - -
-
-
@@ -246,17 +187,5 @@
- - -
- -
-

nb_total; ?> , size_total); ?>.

-

- -

- -
-
diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml new file mode 100644 index 000000000..a8e2deea1 --- /dev/null +++ b/app/views/configure/users.phtml @@ -0,0 +1,72 @@ +partial('aside_configure'); ?> + +
+ + +
+ + +
+ +
+ + $_SERVER['REMOTE_USER'] = +
+
+ +
+
+ +
+
+ +
+ +
+ + (selector not implemented yet) +
+
+ +
+
+ + +
+
+ + + +
+ + conf->mailLogin(); ?> +
+ + +
+
+ +
+ + conf->token(); ?> +
+ + +
+
+ +
+
+ + +
+
+
+
diff --git a/constants.php b/constants.php index 0c7adc57e..a7c96f47b 100644 --- a/constants.php +++ b/constants.php @@ -1,5 +1,5 @@ Date: Fri, 27 Dec 2013 22:45:26 +0100 Subject: Redirection correcte vers nouvelle vue archivage --- app/Controllers/entryController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 26f3422ca..9b5081894 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -106,7 +106,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { Minz_Request::forward(array( 'c' => 'configure', - 'a' => 'display' + 'a' => 'archiving' ), true); } @@ -147,7 +147,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { Minz_Request::forward(array( 'c' => 'configure', - 'a' => 'display' + 'a' => 'archiving' ), true); } } -- cgit v1.2.3 From 48a1a36222ddcf1cb637302bdd09e2bcf9b15844 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 00:02:55 +0100 Subject: Correction bug base_url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit À appliquer aussi à la 0.7-beta --- app/i18n/install.en.php | 2 +- app/i18n/install.fr.php | 4 ++-- lib/Minz/Request.php | 9 ++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/i18n/install.en.php b/app/i18n/install.en.php index 74245d63b..8df48989f 100644 --- a/app/i18n/install.en.php +++ b/app/i18n/install.en.php @@ -55,7 +55,7 @@ return array ( 'update_start' => 'Start update process', 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', - 'installation_is_ok' => 'The installation process was successful.
The final step will now attempt to delete the ./public/install.php file and any database backup created during the update process.
You may choose to skip this step and delete ./public/install.php manually.', + 'installation_is_ok' => 'The installation process was successful.
The final step will now attempt to delete the ./p/i/install.php file and any database backup created during the update process.
You may choose to skip this step and delete ./p/i/install.php manually.', 'finish_installation' => 'Complete installation', 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', ); diff --git a/app/i18n/install.fr.php b/app/i18n/install.fr.php index 9b7a9bdff..a1ae8fcb5 100644 --- a/app/i18n/install.fr.php +++ b/app/i18n/install.fr.php @@ -41,7 +41,7 @@ return array ( 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'random_string' => 'Chaîne aléatoire', 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', - 'base_url' => 'Base de l’url', + 'base_url' => 'Base de l’URL', 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', @@ -55,7 +55,7 @@ return array ( 'update_start' => 'Lancer la mise à jour', 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', - 'installation_is_ok' => 'L’installation s’est bien passée.
La dernière étape va maintenant tenter de supprimer le fichier /public/install.php, ainsi que d’éventuelles copies de base de données créées durant le processus de mise à jour.
Vous pouvez choisir de sauter cette étape et de supprimer /public/install.php manuellement.', + 'installation_is_ok' => 'L’installation s’est bien passée.
La dernière étape va maintenant tenter de supprimer le fichier ./p/i/install.php, ainsi que d’éventuelles copies de base de données créées durant le processus de mise à jour.
Vous pouvez choisir de sauter cette étape et de supprimer ./p/i/install.php manuellement.', 'finish_installation' => 'Terminer l’installation', 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', ); diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index fb48bd7a2..d4e1355d7 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -96,7 +96,14 @@ class Minz_Request { * @return la base de l'url */ public static function getBaseUrl () { - return Minz_Configuration::baseUrl (); + $defaultBaseUrl = Minz_Configuration::baseUrl(); + if (!empty($defaultBaseUrl)) { + return $defaultBaseUrl; + } elseif (isset($_SERVER['REQUEST_URI'])) { + return dirname($_SERVER['REQUEST_URI']) . '/'; + } else { + return '/'; + } } /** -- cgit v1.2.3 From 3273fee15e8d944debfaafd025c67c2ac514905d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 00:04:34 +0100 Subject: Un peu de configuration utilisateur Continue https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ app/views/configure/users.phtml | 22 +++++++++++++--------- lib/Minz/Configuration.php | 3 +++ 4 files changed, 20 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index a1ab4a025..7c4f090ae 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -163,6 +163,8 @@ return array ( 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output without authentication.
%s?token=%s', 'login_configuration' => 'Login', + 'is_admin' => 'is administrator', + 'auth_type' => 'Authentication method', 'language' => 'Language', 'month' => 'months', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index f4e9d109c..9dff6dd33 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -163,6 +163,8 @@ return array ( 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.
%s?output=rss&token=%s', 'login_configuration' => 'Identification', + 'is_admin' => 'est administrateur', + 'auth_type' => 'Méthode d’authentification', 'language' => 'Langue', 'month' => 'mois', diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index a8e2deea1..81e551d95 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -6,14 +6,6 @@
-
- -
- - $_SERVER['REMOTE_USER'] = -
-
-
- +
+ $_SERVER['REMOTE_USER'] = + +
+
+
diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 6c7206988..1e8058dc2 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -96,6 +96,9 @@ class Minz_Configuration { public static function currentUser () { return self::$current_user; } + public static function isAdmin () { + return self::$current_user === self::$default_user; + } /** * Initialise les variables de configuration -- cgit v1.2.3 From 2063f967c63cab8bed30c8db44490a6531d4cb5d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 00:31:52 +0100 Subject: Création de lib_opml pour alléger lib_rss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Et suppression de fonctions inutilisées --- app/Controllers/configureController.php | 1 + app/views/configure/importExport.phtml | 7 +- lib/lib_opml.php | 121 +++++++++++++++++++++++++++++ lib/lib_rss.php | 133 -------------------------------- 4 files changed, 127 insertions(+), 135 deletions(-) create mode 100644 lib/lib_opml.php (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 5fa686ccc..487f6e4ad 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -283,6 +283,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } public function importExportAction () { + require_once(LIB_PATH . '/lib_opml.php'); $catDAO = new FreshRSS_CategoryDAO (); $this->view->categories = $catDAO->listCategories (); diff --git a/app/views/configure/importExport.phtml b/app/views/configure/importExport.phtml index 29a0a682b..e2217d9ed 100644 --- a/app/views/configure/importExport.phtml +++ b/app/views/configure/importExport.phtml @@ -1,5 +1,8 @@ -req == 'export') { ?> -'; // résout bug sur certain serveur ?> +req == 'export') { + echo ''; +?> diff --git a/lib/lib_opml.php b/lib/lib_opml.php new file mode 100644 index 000000000..1b5517d7f --- /dev/null +++ b/lib/lib_opml.php @@ -0,0 +1,121 @@ +' . "\n"; + + foreach ($cat['feeds'] as $feed) { + $txt .= "\t" . '' . "\n"; + } + + $txt .= '' . "\n"; + } + + return $txt; +} + +function opml_import ($xml) { + $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 + + $dom = new DOMDocument(); + $dom->recover = true; + $dom->strictErrorChecking = false; + $dom->loadXML($xml); + $dom->encoding = 'UTF-8'; + + $opml = simplexml_import_dom($dom); + + if (!$opml) { + throw new FreshRSS_Opml_Exception (); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); + $defCat = $catDAO->getDefault(); + + $categories = array (); + $feeds = array (); + + foreach ($opml->body->outline as $outline) { + if (!isset ($outline['xmlUrl'])) { + // Catégorie + $title = ''; + + if (isset ($outline['text'])) { + $title = (string) $outline['text']; + } elseif (isset ($outline['title'])) { + $title = (string) $outline['title']; + } + + if ($title) { + // Permet d'éviter les soucis au niveau des id : + // ceux-ci sont générés en fonction de la date, + // un flux pourrait être dans une catégorie X avec l'id Y + // alors qu'il existe déjà la catégorie X mais avec l'id Z + // Y ne sera pas ajouté et le flux non plus vu que l'id + // de sa catégorie n'exisera pas + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); + $catDAO = new FreshRSS_CategoryDAO (); + $cat = $catDAO->searchByName ($title); + if ($cat === false) { + $cat = new FreshRSS_Category ($title); + $values = array ( + 'name' => $cat->name (), + 'color' => $cat->color () + ); + $cat->_id ($catDAO->addCategory ($values)); + } + + $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ())); + } + } else { + // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut + $feeds[] = getFeed ($outline, $defCat->id()); + } + } + + return array ($categories, $feeds); +} + +/** + * import all feeds of a given outline tag + */ +function getFeedsOutline ($outline, $cat_id) { + $feeds = array (); + + foreach ($outline->children () as $child) { + if (isset ($child['xmlUrl'])) { + $feeds[] = getFeed ($child, $cat_id); + } else { + $feeds = array_merge( + $feeds, + getFeedsOutline ($child, $cat_id) + ); + } + } + + return $feeds; +} + +function getFeed ($outline, $cat_id) { + $url = (string) $outline['xmlUrl']; + $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); + $title = ''; + if (isset ($outline['text'])) { + $title = (string) $outline['text']; + } elseif (isset ($outline['title'])) { + $title = (string) $outline['title']; + } + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); + $feed = new FreshRSS_Feed ($url); + $feed->_category ($cat_id); + $feed->_name ($title); + if (isset($outline['htmlUrl'])) { + $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_COMPAT, 'UTF-8')); + } + if (isset($outline['description'])) { + $feed->_description(sanitizeHTML((string)$outline['description'])); + } + return $feed; +} diff --git a/lib/lib_rss.php b/lib/lib_rss.php index a1fadcb24..160a65bbf 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -98,33 +98,6 @@ function timestamptodate ($t, $hour = true) { return @date ($date, $t); } -function sortEntriesByDate ($entry1, $entry2) { - return $entry2->date (true) - $entry1->date (true); -} -function sortReverseEntriesByDate ($entry1, $entry2) { - return $entry1->date (true) - $entry2->date (true); -} - -function get_domain ($url) { - return parse_url($url, PHP_URL_HOST); -} - -function opml_export ($cats) { - $txt = ''; - - foreach ($cats as $cat) { - $txt .= '' . "\n"; - - foreach ($cat['feeds'] as $feed) { - $txt .= "\t" . '' . "\n"; - } - - $txt .= '' . "\n"; - } - - return $txt; -} - function html_only_entity_decode($text) { static $htmlEntitiesOnly = null; if ($htmlEntitiesOnly === null) { @@ -144,112 +117,6 @@ function sanitizeHTML($data) { return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_MAYBE_HTML)); } -function opml_import ($xml) { - $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 - - $dom = new DOMDocument(); - $dom->recover = true; - $dom->strictErrorChecking = false; - $dom->loadXML($xml); - $dom->encoding = 'UTF-8'; - - $opml = simplexml_import_dom($dom); - - if (!$opml) { - throw new FreshRSS_Opml_Exception (); - } - - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - $defCat = $catDAO->getDefault(); - - $categories = array (); - $feeds = array (); - - foreach ($opml->body->outline as $outline) { - if (!isset ($outline['xmlUrl'])) { - // Catégorie - $title = ''; - - if (isset ($outline['text'])) { - $title = (string) $outline['text']; - } elseif (isset ($outline['title'])) { - $title = (string) $outline['title']; - } - - if ($title) { - // Permet d'éviter les soucis au niveau des id : - // ceux-ci sont générés en fonction de la date, - // un flux pourrait être dans une catégorie X avec l'id Y - // alors qu'il existe déjà la catégorie X mais avec l'id Z - // Y ne sera pas ajouté et le flux non plus vu que l'id - // de sa catégorie n'exisera pas - $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); - $catDAO = new FreshRSS_CategoryDAO (); - $cat = $catDAO->searchByName ($title); - if ($cat === false) { - $cat = new FreshRSS_Category ($title); - $values = array ( - 'name' => $cat->name (), - 'color' => $cat->color () - ); - $cat->_id ($catDAO->addCategory ($values)); - } - - $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ())); - } - } else { - // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut - $feeds[] = getFeed ($outline, $defCat->id()); - } - } - - return array ($categories, $feeds); -} - -/** - * import all feeds of a given outline tag - */ -function getFeedsOutline ($outline, $cat_id) { - $feeds = array (); - - foreach ($outline->children () as $child) { - if (isset ($child['xmlUrl'])) { - $feeds[] = getFeed ($child, $cat_id); - } else { - $feeds = array_merge( - $feeds, - getFeedsOutline ($child, $cat_id) - ); - } - } - - return $feeds; -} - -function getFeed ($outline, $cat_id) { - $url = (string) $outline['xmlUrl']; - $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); - $title = ''; - if (isset ($outline['text'])) { - $title = (string) $outline['text']; - } elseif (isset ($outline['title'])) { - $title = (string) $outline['title']; - } - $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); - $feed = new FreshRSS_Feed ($url); - $feed->_category ($cat_id); - $feed->_name ($title); - if (isset($outline['htmlUrl'])) { - $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_COMPAT, 'UTF-8')); - } - if (isset($outline['description'])) { - $feed->_description(sanitizeHTML((string)$outline['description'])); - } - return $feed; -} - - /* permet de récupérer le contenu d'un article pour un flux qui n'est pas complet */ function get_content_by_parsing ($url, $path) { require_once (LIB_PATH . '/lib_phpQuery.php'); -- cgit v1.2.3 From 8ffa896e68d05403cd65bd7b1ca3d4657347c10a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 01:01:31 +0100 Subject: Liste d'utilisateurs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/i18n/en.php | 7 ++++--- app/i18n/fr.php | 7 ++++--- app/views/configure/users.phtml | 16 ++++++++++++++++ lib/lib_rss.php | 12 ++++++++++++ 4 files changed, 36 insertions(+), 6 deletions(-) (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index 7c4f090ae..c7ac16ae0 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -162,9 +162,10 @@ return array ( 'allow_anonymous' => 'Allow anonymous reading', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output without authentication.
%s?token=%s', - 'login_configuration' => 'Login', - 'is_admin' => 'is administrator', - 'auth_type' => 'Authentication method', + 'login_configuration' => 'Login', + 'is_admin' => 'is administrator', + 'auth_type' => 'Authentication method', + 'users_list' => 'List of users', 'language' => 'Language', 'month' => 'months', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 9dff6dd33..e8da1c603 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -162,9 +162,10 @@ return array ( 'allow_anonymous' => 'Autoriser la lecture anonyme', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.
%s?output=rss&token=%s', - 'login_configuration' => 'Identification', - 'is_admin' => 'est administrateur', - 'auth_type' => 'Méthode d’authentification', + 'login_configuration' => 'Identification', + 'is_admin' => 'est administrateur', + 'auth_type' => 'Méthode d’authentification', + 'users_list' => 'Liste des utilisateurs', 'language' => 'Langue', 'month' => 'mois', diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 81e551d95..e6bebc77c 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -39,6 +39,22 @@
+ + +
+ +
+ + (not implemented yet) +
+
+ + +
diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 160a65bbf..c7698b5c5 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -176,3 +176,15 @@ function uSecString() { function invalidateHttpCache() { file_put_contents(DATA_PATH . '/touch.txt', uTimeString()); } + +function usernameFromPath($userPath) { + if (preg_match('%/([a-z0-9]{1,16})_user\.php$%', $userPath, $matches)) { + return $matches[1]; + } else { + return ''; + } +} + +function listUsers() { + return array_map('usernameFromPath', glob(DATA_PATH . '/*_user.php')); +} -- cgit v1.2.3 From 0842be443489690e50636b55aaceac6534645538 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 01:08:25 +0100 Subject: Zone utilisateurs limitée à l'administrateur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/configure/users.phtml | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'app') diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index e6bebc77c..3640a2ff4 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -4,28 +4,7 @@ - - -
-
- -
-
- -
- -
- - (selector not implemented yet) -
-
+
@@ -39,21 +18,23 @@
- -
- + + conf->mailLogin(); ?>
- - (not implemented yet) + +
- +
+ + conf->token(); ?> +
+ + +
+
@@ -62,23 +43,40 @@
- + + +
- - conf->mailLogin(); ?>
- - +
- - conf->token(); ?> +
- - + + (selector not implemented yet) +
+
+ +
+ +
+ + (not implemented yet)
@@ -88,5 +86,7 @@
+ +
-- cgit v1.2.3 From 45b2decce03e218fe7ad66479491123ce398ab1f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Dec 2013 01:24:54 +0100 Subject: HTTP Auth user https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/views/configure/users.phtml | 4 ++-- lib/lib_rss.php | 4 ++++ p/i/install.php | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 3640a2ff4..40cce590e 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -10,7 +10,7 @@
- $_SERVER['REMOTE_USER'] = + $_SERVER['REMOTE_USER'] =
+ + Mozilla Persona
@@ -95,4 +90,66 @@ + +
+ + +
+ +
+ +
+
+ +
+
+ +
+
+
+ +
+ + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ + conf->mail_login; ?> +
+ +
+
+ +
+
+ + +
+
+ +
+ +
diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 1513af6d0..873908ce6 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -28,7 +28,7 @@ class Minz_Configuration { /** * définition des variables de configuration - * $sel_application une chaîne de caractères aléatoires (obligatoire) + * $salt 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 @@ -42,7 +42,7 @@ class Minz_Configuration { * - password mot de passe de l'utilisateur * - base le nom de la base de données */ - private static $sel_application = ''; + private static $salt = ''; private static $environment = Minz_Configuration::PRODUCTION; private static $base_url = ''; private static $use_url_rewriting = false; @@ -55,17 +55,19 @@ class Minz_Configuration { private static $auth_type = 'none'; private static $db = array ( - 'host' => false, - 'user' => false, - 'password' => false, - 'base' => false + 'type' => 'mysql', + 'host' => '', + 'user' => '', + 'password' => '', + 'base' => '', + 'prefix' => '', ); /* * Getteurs */ public static function salt () { - return self::$sel_application; + return self::$salt; } public static function environment () { return self::$environment; @@ -145,7 +147,7 @@ class Minz_Configuration { 'general' => array( 'environment' => self::$environment, 'use_url_rewriting' => self::$use_url_rewriting, - 'sel_application' => self::$sel_application, + 'salt' => self::$salt, 'base_url' => self::$base_url, 'title' => self::$title, 'default_user' => self::$default_user, @@ -189,14 +191,18 @@ class Minz_Configuration { } $general = $ini_array['general']; - // sel_application est obligatoire - if (!isset ($general['sel_application'])) { - throw new Minz_BadConfigurationException ( - 'sel_application', - Minz_Exception::ERROR - ); + // 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::$sel_application = $general['sel_application']; + self::$salt = $general['salt']; if (isset ($general['environment'])) { switch ($general['environment']) { @@ -256,18 +262,15 @@ class Minz_Configuration { } // Base de données - $db = false; if (isset ($ini_array['db'])) { $db = $ini_array['db']; - } - if ($db) { - if (!isset ($db['host'])) { + if (empty($db['host'])) { throw new Minz_BadConfigurationException ( 'host', Minz_Exception::ERROR ); } - if (!isset ($db['user'])) { + if (empty($db['user'])) { throw new Minz_BadConfigurationException ( 'user', Minz_Exception::ERROR @@ -279,19 +282,23 @@ class Minz_Configuration { Minz_Exception::ERROR ); } - if (!isset ($db['base'])) { + if (empty($db['base'])) { throw new Minz_BadConfigurationException ( 'base', Minz_Exception::ERROR ); } - self::$db['type'] = isset ($db['type']) ? $db['type'] : 'mysql'; + if (!empty($db['type'])) { + self::$db['type'] = $db['type']; + } self::$db['host'] = $db['host']; self::$db['user'] = $db['user']; self::$db['password'] = $db['password']; self::$db['base'] = $db['base']; - self::$db['prefix'] = isset ($db['prefix']) ? $db['prefix'] : ''; + if (isset($db['prefix'])) { + self::$db['prefix'] = $db['prefix']; + } } } diff --git a/lib/Minz/FileNotExistException.php b/lib/Minz/FileNotExistException.php index df2b8ff6c..f8dfbdf66 100644 --- a/lib/Minz/FileNotExistException.php +++ b/lib/Minz/FileNotExistException.php @@ -1,7 +1,7 @@ */ @@ -23,7 +23,7 @@ class Minz_ModelPdo { protected $bd; protected $prefix; - + /** * Créé la connexion à la base de données à l'aide des variables * HOST, BASE, USER et PASS définies dans le fichier de configuration @@ -80,11 +80,15 @@ class Minz_ModelPdo { $this->bd->rollBack(); } - public function size() { + public function size($all = false) { $db = Minz_Configuration::dataBase (); $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; - $stm = $this->bd->prepare ($sql); $values = array ($db['base']); + if (!$all) { + $sql .= ' AND table_name LIKE ?'; + $values[] = $this->prefix . '%'; + } + $stm = $this->bd->prepare ($sql); $stm->execute ($values); $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); return $res[0]; diff --git a/p/i/install.php b/p/i/install.php index 672f64b94..e953cf699 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -12,6 +12,8 @@ if (isset ($_GET['step'])) { define ('STEP', 1); } +define('SQL_CREATE_DB', 'CREATE DATABASE %1$s DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;'); + include(APP_PATH . '/sql.php'); // @@ -151,7 +153,7 @@ function saveStep2 () { return false; } - $_SESSION['sel_application'] = sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__))); + $_SESSION['salt'] = sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__))); $_SESSION['title'] = substr(trim($_POST['title']), 0, 25); $_SESSION['old_entries'] = $_POST['old_entries']; if ((!ctype_digit($_SESSION['old_entries'])) || ($_SESSION['old_entries'] < 1)) { @@ -162,7 +164,7 @@ function saveStep2 () { $token = ''; if ($_SESSION['mail_login']) { - $token = sha1($_SESSION['sel_application'] . $_SESSION['mail_login']); + $token = sha1($_SESSION['salt'] . $_SESSION['mail_login']); } $config_array = array ( @@ -173,7 +175,7 @@ function saveStep2 () { ); $configPath = DATA_PATH . '/' . $_SESSION['default_user'] . '_user.php'; - @unlink(configPath); //To avoid access-rights problems + @unlink($configPath); //To avoid access-rights problems file_put_contents($configPath, " array( 'environment' => empty($_SESSION['environment']) ? 'production' : $_SESSION['environment'], 'use_url_rewriting' => false, - 'sel_application' => $_SESSION['sel_application'], + 'salt' => $_SESSION['salt'], 'base_url' => '', 'title' => $_SESSION['title'], 'default_user' => $_SESSION['default_user'], @@ -424,7 +426,7 @@ function checkStep0 () { if ($ini_array) { $ini_general = isset($ini_array['general']) ? $ini_array['general'] : null; if ($ini_general) { - $keys = array('environment', 'sel_application', 'title', 'default_user'); + $keys = array('environment', 'salt', 'title', 'default_user'); foreach ($keys as $key) { if ((empty($_SESSION[$key])) && isset($ini_general[$key])) { $_SESSION[$key] = $ini_general[$key]; @@ -496,7 +498,7 @@ function checkStep1 () { } function checkStep2 () { - $conf = !empty($_SESSION['sel_application']) && + $conf = !empty($_SESSION['salt']) && !empty($_SESSION['title']) && !empty($_SESSION['old_entries']) && isset($_SESSION['mail_login']) && @@ -537,7 +539,7 @@ function checkStep3 () { } function checkBD () { - $error = false; + $ok = false; try { $str = ''; @@ -575,35 +577,18 @@ function checkBD () { $res = $c->query($sql); //Backup tables } - $sql = sprintf (SQL_CAT, $_SESSION['bd_prefix_user']); - $res = $c->query ($sql); - - if (!$res) { - $error = true; - } - - $sql = sprintf (SQL_FEED, $_SESSION['bd_prefix_user']); - $res = $c->query ($sql); - - if (!$res) { - $error = true; - } - - $sql = sprintf (SQL_ENTRY, $_SESSION['bd_prefix_user']); - $res = $c->query ($sql); - - if (!$res) { - $error = true; - } + $sql = sprintf(SQL_CREATE_TABLES, $_SESSION['bd_prefix_user']); + $stm = $c->prepare($sql, array(PDO::ATTR_EMULATE_PREPARES => true)); + $ok = $stm->execute(); } catch (PDOException $e) { $error = true; } - if ($error && file_exists (DATA_PATH . '/config.php')) { - unlink (DATA_PATH . '/config.php'); + if (!$ok) { + @unlink(DATA_PATH . '/config.php'); } - return !$error; + return $ok; } /*** AFFICHAGE ***/ @@ -729,9 +714,6 @@ function printStep2 () {
-
-- cgit v1.2.3 From 5c9a32329ad68dc5ae8bc8a3566a0d603b80a934 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 31 Dec 2013 14:52:01 +0100 Subject: Multi-utilisateur fonctionnel avec Mozilla Persona MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il faut ré-enregistrer l'adresse courriel une fois dans l'interface de FreshRSS pour créer le fichier nécessaire. + Comparaison sans tenir compte de la casse pour les noms d'utilisateur. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 ll faudra tester la sécurité --- app/Controllers/indexController.php | 32 +++++++++++++++++++++++++++++--- app/Controllers/usersController.php | 37 ++++++++++++++++++++++++++----------- app/FreshRSS.php | 18 ++++++++++++++---- data/cache/index.html | 13 +++++++++++++ data/favicons/index.html | 13 +++++++++++++ data/log/index.html | 13 +++++++++++++ data/persona/.gitignore | 1 + data/persona/index.html | 13 +++++++++++++ p/i/install.php | 6 ++++++ 9 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 data/cache/index.html create mode 100644 data/favicons/index.html create mode 100644 data/log/index.html create mode 100644 data/persona/.gitignore create mode 100644 data/persona/index.html (limited to 'app') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 7309169a6..5b51b3e28 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -249,14 +249,40 @@ class FreshRSS_index_Controller extends Minz_ActionController { curl_close ($ch); $res = json_decode ($result, true); - if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mail_login) { - Minz_Session::_param ('mail', $res['email']); + + $loginOk = false; + $reason = ''; + if ($res['status'] === 'okay') { + $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + if (($currentUser = @file_get_contents($personaFile)) !== false) { + $currentUser = trim($currentUser); + if (ctype_alnum($currentUser)) { + try { + $this->conf = new FreshRSS_Configuration($currentUser); + $loginOk = strcasecmp($email, $this->conf->mail_login) === 0; + } catch (Minz_Exception $e) { + $reason = 'Invalid configuration for user [' . $currentUser . ']! ' . $e->getMessage(); //Permission denied or conf file does not exist + } + } else { + $reason = 'Invalid username format [' . $currentUser . ']!'; + } + } + } else { + $reason = 'Invalid email format [' . $res['email'] . ']!'; + } + } + if ($loginOk) { + Minz_Session::_param('currentUser', $currentUser); + Minz_Session::_param ('mail', $email); $this->view->loginOk = true; invalidateHttpCache(); } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = Minz_Translate::t ('invalid_login'); + $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } header('Content-Type: application/json; charset=UTF-8'); diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 7d9568083..5b3ffe81a 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -17,7 +17,14 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); + $email = $this->view->conf->mail_login; + Minz_Session::_param('mail', $email); + + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); + } //TODO: use $ok $notif = array( @@ -38,8 +45,6 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_token($token); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); - $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); @@ -69,18 +74,27 @@ class FreshRSS_users_Controller extends Minz_ActionController { } $new_user_name = Minz_Request::param('new_user_name'); - $ok = ctype_alnum($new_user_name); - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - $ok &= Minz_Configuration::authType() !== 'persona'; - } + $ok = ($new_user_name != '') && ctype_alnum($new_user_name); if ($ok) { + $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user + + $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; $ok &= !file_exists($configPath); } + if ($ok) { + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + $ok &= Minz_Configuration::authType() !== 'persona'; + } else { + $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, $new_user_name) !== false); + } + } if ($ok) { $config_array = array( 'language' => $new_user_language, @@ -110,7 +124,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok = ctype_alnum($username); if ($ok) { - $ok &= ($username !== Minz_Configuration::defaultUser()); //It is forbidden to delete the default user + $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user } if ($ok) { $configPath = DATA_PATH . '/' . $username . '_user.php'; @@ -120,6 +134,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->deleteUser($username); $ok &= unlink($configPath); + //TODO: delete Persona file } $notif = array( 'type' => $ok ? 'good' : 'bad', diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 0e166cc3b..0af0c01da 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -18,8 +18,18 @@ class FreshRSS extends Minz_FrontController { $loginOk = $currentUser != ''; break; case 'persona': - $currentUser = Minz_Configuration::defaultUser(); //TODO: Make Persona compatible with multi-user - $loginOk = Minz_Session::param('mail') != ''; + $loginOk = false; + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + if ($email != '') { //TODO: Remove redundancy with indexController + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + if (($currentUser = @file_get_contents($personaFile)) !== false) { + $currentUser = trim($currentUser); + $loginOk = true; + } + } + if (!$loginOk) { + $currentUser = Minz_Configuration::defaultUser(); + } break; case 'none': $currentUser = Minz_Configuration::defaultUser(); @@ -51,10 +61,10 @@ class FreshRSS extends Minz_FrontController { if ($loginOk) { switch (Minz_Configuration::authType()) { case 'http_auth': - $loginOk = $currentUser === httpAuthUser(); + $loginOk = strcasecmp($currentUser, httpAuthUser()) === 0; break; case 'persona': - $loginOk = Minz_Session::param('mail') === $this->conf->mail_login; + $loginOk = strcasecmp(Minz_Session::param('mail'), $this->conf->mail_login) === 0; break; case 'none': $loginOk = true; diff --git a/data/cache/index.html b/data/cache/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/cache/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/favicons/index.html b/data/favicons/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/favicons/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/log/index.html b/data/log/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/log/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/persona/.gitignore b/data/persona/.gitignore new file mode 100644 index 000000000..314f02b1b --- /dev/null +++ b/data/persona/.gitignore @@ -0,0 +1 @@ +*.txt \ No newline at end of file diff --git a/data/persona/index.html b/data/persona/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/persona/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/p/i/install.php b/p/i/install.php index e953cf699..0cd952fef 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -178,6 +178,12 @@ function saveStep2 () { @unlink($configPath); //To avoid access-rights problems file_put_contents($configPath, " Date: Tue, 31 Dec 2013 15:21:39 +0100 Subject: Ajouts de quelques invalidateHttpCache --- app/Controllers/configureController.php | 7 +++++++ app/Controllers/usersController.php | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 17abf6b89..0e4801a2d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -50,6 +50,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $catDAO->addCategory ($values); } } + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -124,6 +125,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'content' => Minz_Translate::t ('error_occurred_update') ); } + invalidateHttpCache(); Minz_Session::_param ('notification', $notif); Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); @@ -168,6 +170,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Session::_param ('language', $this->view->conf->language); Minz_Translate::reset (); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -196,6 +199,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'print' => Minz_Request::param ('print', false), )); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -235,6 +239,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->categories = $list; } elseif ($this->view->req == 'import' && Minz_Request::isPost ()) { if ($_FILES['file']['error'] == 0) { + invalidateHttpCache(); // on parse le fichier OPML pour récupérer les catégories et les flux associés try { list ($categories, $feeds) = opml_import ( @@ -295,6 +300,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_shortcuts ($shortcuts_ok); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -320,6 +326,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_old_entries($old); $this->view->conf->_keep_history_default($keepHistoryDefault); $this->view->conf->save(); + invalidateHttpCache(); $notif = array( 'type' => 'good', diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 5b3ffe81a..0ce3b3447 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -25,6 +25,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } + invalidateHttpCache(); //TODO: use $ok $notif = array( @@ -54,6 +55,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { Minz_Configuration::_authType($auth_type); $ok &= Minz_Configuration::writeFile(); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -106,6 +108,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->createUser($new_user_name); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -136,6 +139,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok &= unlink($configPath); //TODO: delete Persona file } + invalidateHttpCache(); + $notif = array( 'type' => $ok ? 'good' : 'bad', 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) -- cgit v1.2.3 From 66229a5d71b85c0a57d63fa8b1cc6e5729cabfe4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 04:39:39 +0100 Subject: Minz : bug avec OPcache de PHP 5.5+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minz ne prenait pas en charge OPcache (cache PHP) http://php.net/opcache activé par défaut depuis PHP5.5. Ce fut un peu dur d'isoler ce bug :-/ Il faut penser à appeler opcache_invalidate avant de ré-utiliser un fichier par include(). Aussi, le mécanisme de lock() n'est plus approprié ni nécessaire. Pour FreshRSS, évite l'utilisation de ModelArray car il ne restait que quelques lignes d'utiles, et évite un héritage + appel de classe, ce qui est toujours ça de gagné. --- app/Models/Configuration.php | 20 +++++++++++++++----- lib/Minz/Configuration.php | 17 +++++++---------- lib/Minz/ModelArray.php | 5 ++++- 3 files changed, 26 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index ec7daaa7d..abd874f27 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -1,6 +1,8 @@ 'en', 'old_entries' => 3, @@ -60,10 +62,12 @@ class FreshRSS_Configuration extends Minz_ModelArray { ); public function __construct ($user) { - $filename = DATA_PATH . '/' . $user . '_user.php'; + $this->filename = DATA_PATH . '/' . $user . '_user.php'; - parent::__construct($filename); - $data = parent::loadArray(); + $data = include($this->filename); + if (!is_array($data)) { + throw new Minz_PermissionDeniedException($this->filename); + } foreach ($data as $key => $value) { if (isset($this->data[$key])) { @@ -75,8 +79,14 @@ class FreshRSS_Configuration extends Minz_ModelArray { } public function save() { + if (file_put_contents($this->filename, "filename); + } + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include + } invalidateHttpCache(); - return parent::writeArray($this->data); + return true; } public function __get($name) { diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 873908ce6..fc94d9731 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -157,25 +157,22 @@ class Minz_Configuration { 'db' => self::$db, ); @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak'); - return file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "filename, "filename, "filename); } + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include + } return true; } -- cgit v1.2.3 From bc4116ea77a927683b2abe8a7b4b4fde6452f7d6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 04:54:44 +0100 Subject: Changement sauvegarde configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changement oublié dans https://github.com/marienfressinaud/FreshRSS/commit/66229a5d71b85c0a57d63fa8b1cc6e5729cabfe4 pour https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/Models/Configuration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index abd874f27..a39d47888 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -79,7 +79,8 @@ class FreshRSS_Configuration { } public function save() { - if (file_put_contents($this->filename, "filename, $this->filename . '.bak'); + if (file_put_contents($this->filename, "data, true) . ';', LOCK_EX) === false) { throw new Minz_PermissionDeniedException($this->filename); } if (function_exists('opcache_invalidate')) { -- cgit v1.2.3 From 8beb15460a3c55c37264fdf414e7dcf9ff4e2a62 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 05:06:36 +0100 Subject: Sauvegardes avec extension .bak.php pour plus de sécurité MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Évite le téléchargement --- app/Models/Configuration.php | 2 +- data/.gitignore | 2 +- lib/Minz/Configuration.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index a39d47888..e0ae3bf6b 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -79,7 +79,7 @@ class FreshRSS_Configuration { } public function save() { - @rename($this->filename, $this->filename . '.bak'); + @rename($this->filename, $this->filename . '.bak.php'); if (file_put_contents($this->filename, "data, true) . ';', LOCK_EX) === false) { throw new Minz_PermissionDeniedException($this->filename); } diff --git a/data/.gitignore b/data/.gitignore index 1d8393f3b..005982b00 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -4,4 +4,4 @@ config.php *.sqlite touch.txt no-cache.txt -*.bak +*.bak.php diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index fc94d9731..2c30661ed 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -156,7 +156,7 @@ class Minz_Configuration { ), 'db' => self::$db, ); - @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak'); + @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, " Date: Wed, 1 Jan 2014 13:48:32 +0100 Subject: Détails multi-utilisateur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/Controllers/usersController.php | 47 ++++++++++++++----------------------- app/views/configure/archiving.phtml | 4 ++-- app/views/configure/feed.phtml | 4 ++-- app/views/configure/users.phtml | 9 ++++--- p/themes/default/global.css | 2 +- p/themes/flat-design/global.css | 2 +- 6 files changed, 28 insertions(+), 40 deletions(-) (limited to 'app') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 0ce3b3447..482e35c3e 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -10,9 +10,10 @@ class FreshRSS_users_Controller extends Minz_ActionController { } } - public function idAction() { + public function authAction() { if (Minz_Request::isPost()) { $ok = true; + $mail = Minz_Request::param('mail_login', false); $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); @@ -25,36 +26,24 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } - invalidateHttpCache(); - //TODO: use $ok - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); - } - } - - public function authAction() { - if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - $ok = true; - $current_token = $this->view->conf->token; - $token = Minz_Request::param('token', $current_token); - $this->view->conf->_token($token); - $ok &= $this->view->conf->save(); - - $anon = Minz_Request::param('anon_access', false); - $anon = ((bool)$anon) && ($anon !== 'no'); - $auth_type = Minz_Request::param('auth_type', 'none'); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType()) { - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_authType($auth_type); - $ok &= Minz_Configuration::writeFile(); + if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType()) { + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_authType($auth_type); + $ok &= Minz_Configuration::writeFile(); + } } + invalidateHttpCache(); $notif = array( diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index cbe3b086c..6e26ca81e 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -17,8 +17,8 @@
- '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> () diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index e738ab64f..a0fe39f8a 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -87,8 +87,8 @@
- '', -2 => Minz_Translate::t('by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 223f81e8d..d40a3ad5b 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -3,7 +3,7 @@
- +
@@ -34,20 +34,19 @@
- -
- + - + $_SERVER['REMOTE_USER'] = ``
diff --git a/p/themes/default/global.css b/p/themes/default/global.css index 913da4b27..2cc195f90 100644 --- a/p/themes/default/global.css +++ b/p/themes/default/global.css @@ -112,7 +112,7 @@ input, select, textarea { border-color: #33BBFF; box-shadow: 0 2px 2px #DDDDFF inset; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } diff --git a/p/themes/flat-design/global.css b/p/themes/flat-design/global.css index cb9495865..c24a9f481 100644 --- a/p/themes/flat-design/global.css +++ b/p/themes/flat-design/global.css @@ -113,7 +113,7 @@ input, select, textarea { color: #333; border-color: #2980b9; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } -- cgit v1.2.3 From a08201c41486815de25c71f5497e939631ea68b4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 15:08:15 +0100 Subject: SQL : Insère la catégorie par défaut dès la création des tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/UserDAO.php | 5 ++++- app/sql.php | 2 ++ p/i/install.php | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index afa049fb9..a25b57f89 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -7,7 +7,10 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_'); $stm = $this->bd->prepare($sql, array(PDO::ATTR_EMULATE_PREPARES => true)); - if ($stm && $stm->execute()) { + $values = array( + 'catName' => Minz_Translate::t('default_category'), + ); + if ($stm && $stm->execute($values)) { return true; } else { $info = $stm->errorInfo(); diff --git a/app/sql.php b/app/sql.php index 8646b4da5..5a28858a7 100644 --- a/app/sql.php +++ b/app/sql.php @@ -52,6 +52,8 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` ( INDEX (`is_read`) -- v0.7 ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = INNODB; + +INSERT INTO `%1$scategory` (name) VALUES(:catName); '); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); diff --git a/p/i/install.php b/p/i/install.php index 0cd952fef..3316d222b 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -585,7 +585,10 @@ function checkBD () { $sql = sprintf(SQL_CREATE_TABLES, $_SESSION['bd_prefix_user']); $stm = $c->prepare($sql, array(PDO::ATTR_EMULATE_PREPARES => true)); - $ok = $stm->execute(); + $values = array( + 'catName' => _t('default_category'), + ); + $ok = $stm->execute($values); } catch (PDOException $e) { $error = true; } -- cgit v1.2.3 From 67531f796f4c273cc9b078db788fdb51ece824ee Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 17:01:09 +0100 Subject: HTTP Auth : améliorations + changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Affichage logo FreshRSS pendant la demande de nom d'utilisateur HTTP * Meilleure page d'erreur si utilisateur HTTP non-configuré dans FreshRSS + log Je recommande donc de placer le .htaccess pour le contrôle d'accès dans ./FreshRSS/p/i/.htaccess et pas plus haut pour une meilleure mise en cache et messages de connexion. --- CHANGELOG | 14 ++++++++++++++ README.md | 16 +++++++++------- app/FreshRSS.php | 23 ++++++++++++++++++----- app/Models/Configuration.php | 2 +- index.html | 6 +++--- index.php | 2 +- p/index.html | 22 ++++++++++++++++++++-- p/index.php | 3 --- 8 files changed, 66 insertions(+), 22 deletions(-) delete mode 100644 p/index.php (limited to 'app') diff --git a/CHANGELOG b/CHANGELOG index 108e29195..f4b168b41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,19 @@ # Journal des modifications +## 2014-01-xx FreshRSS 0.7.5 + +* Nouveau mode multi-utilisateur + * L’utilisateur par défaut (administrateur) peut créer et supprimer d’autres utilisateurs + * Nécessite un contrôle d’accès, soit : + * par HTTP (par exemple sous Apache en créant un fichier ./p/i/.htaccess et .htpasswd) + * le nom d’utilisateur HTTP doit correspondre au nom d’utilisateur FreshRSS + * par Mozilla Persona, en renseignant l’adresse courriel des utilisateurs +* Options + * Réorganisation des options +* PHP + * Compatibilité PHP 5.5+ avec OPcache + * Amélioration des performances + ## 2014-01-xx FreshRSS 0.7 * Installeur diff --git a/README.md b/README.md index cfef89781..cf1308c33 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # FreshRSS FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de [Leed](http://projet.idleman.fr/leed/) ou de [Kriss Feed](http://tontof.net/kriss/feed/). Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable. +Il permet de gérer plusieurs utilisateurs, et dispose d’un mode de lecture anonyme. * Site officiel : http://freshrss.org * Démo : http://marienfressinaud.fr/projets/freshrss/ @@ -21,11 +22,11 @@ Privilégiez pour cela des demandes sur GitHub # Pré-requis * Serveur Apache2 ou Nginx (non testé sur les autres) * PHP 5.2+ (PHP 5.3.3+ recommandé) - * Requis : [PDO_MySQL](http://php.net/pdo-mysql), [cURL](http://php.net/curl), [LibXML](http://php.net/xml), [PCRE](http://php.net/pcre), [ctype](http://php.net/ctype) - * Recommandés : [JSON](http://php.net/json), [zlib](http://php.net/zlib), [mbstring](http://php.net/mbstring), [iconv](http://php.net/iconv) + * Requis : [PDO_MySQL](http://php.net/pdo-mysql), [cURL](http://php.net/curl), [LibXML](http://php.net/xml), [PCRE](http://php.net/pcre), [ctype](http://php.net/ctype) + * Recommandés : [JSON](http://php.net/json), [zlib](http://php.net/zlib), [mbstring](http://php.net/mbstring), [iconv](http://php.net/iconv) * MySQL 5.0.3+ (ou SQLite 3.7.4+ à venir) * Un navigateur Web récent tel Firefox, Chrome, Opera, Safari, Internet Explorer 9+ - * Fonctionne aussi sur mobile + * Fonctionne aussi sur mobile ![Capture d’écran de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png) @@ -37,10 +38,11 @@ Privilégiez pour cela des demandes sur GitHub 5. Tout devrait fonctionner :) En cas de problème, n’hésitez pas à me contacter. # Contrôle d’accès -Il est recommandé de limiter l’accès à votre FreshRSS, soit : +Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter l’accès à votre FreshRSS : * En utilisant l’identification par [Mozilla Persona](https://login.persona.org/about) incluse dans FreshRSS -* En utilisant un contrôle d’accès défini par votre serveur Web - * Voir par exemple la [documentation d’Apache sur l’authentification](http://httpd.apache.org/docs/trunk/howto/auth.html) +* En utilisant un contrôle d’accès HTTP défini par votre serveur Web + * Voir par exemple la [documentation d’Apache sur l’authentification](http://httpd.apache.org/docs/trunk/howto/auth.html) + * Créer dans ce cas un fichier `./p/i/.htaccess` avec un fichier `.htpasswd` correspondant. # Rafraîchissement automatique des flux * Vous pouvez ajouter une tâche CRON sur le script d’actualisation des flux. Par exemple, pour exécuter le script toutes les heures : @@ -51,6 +53,6 @@ Il est recommandé de limiter l’accès à votre FreshRSS, soit : # Conseils * Pour une meilleure sécurité, faites en sorte que seul le répertoire `./p/` soit accessible depuis le Web, par exemple en faisant pointer un sous-domaine sur le répertoire `./p/`. -* Les données personnelles se trouvent dans le répertoire `./data/` (déjà protégé par un .htaccess pour Apache - vérifiez que cela fonctionne -, à protéger vous-même dans le cas d’autres serveurs Web). + * En particulier, les données personnelles se trouvent dans le répertoire `./data/`. * Le fichier `./constants.php` définit les chemins d’accès aux répertoires clés de l’application. Si vous les bougez, tout se passe ici. * En cas de problème, les logs peuvent être utile à lire, soit depuis l’interface de FreshRSS, soit manuellement depuis `./data/log/*.log`. diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 0af0c01da..4ebb6d631 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -51,12 +51,25 @@ class FreshRSS extends Minz_FrontController { try { $this->conf = new FreshRSS_Configuration($currentUser); - } catch (Minz_Exception $e) { - Minz_Session::_param('currentUser', ''); - die('Invalid configuration for user [' . $currentUser . ']! ' . $e->getMessage()); //Permission denied or conf file does not exist + Minz_View::_param ('conf', $this->conf); + Minz_Session::_param('currentUser', $currentUser); + } catch (Minz_Exception $me) { + $loginOk = false; + try { + $this->conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser()); + Minz_Session::_param('currentUser', Minz_Configuration::defaultUser()); + Minz_View::_param('conf', $this->conf); + $notif = array( + 'type' => 'bad', + 'content' => 'Invalid configuration for user [' . $currentUser . ']!', + ); + Minz_Session::_param ('notification', $notif); + Minz_Log::record ($notif['content'] . ' ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Session::_param('currentUser', ''); + } catch (Exception $e) { + die($e->getMessage()); + } } - Minz_View::_param ('conf', $this->conf); - Minz_Session::_param('currentUser', $currentUser); if ($loginOk) { switch (Minz_Configuration::authType()) { diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index e0ae3bf6b..d44420f56 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -64,7 +64,7 @@ class FreshRSS_Configuration { public function __construct ($user) { $this->filename = DATA_PATH . '/' . $user . '_user.php'; - $data = include($this->filename); + $data = @include($this->filename); if (!is_array($data)) { throw new Minz_PermissionDeniedException($this->filename); } diff --git a/index.html b/index.html index 1bfdea859..6ac025960 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,12 @@ - + Redirection - + -

FreshRSS

+

FreshRSS

diff --git a/index.php b/index.php index 3fdae4285..828cca39a 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,3 @@ + -Redirection +FreshRSS + + + -

FreshRSS

+

FreshRSS

+

diff --git a/p/index.php b/p/index.php deleted file mode 100644 index e90662078..000000000 --- a/p/index.php +++ /dev/null @@ -1,3 +0,0 @@ - Date: Thu, 2 Jan 2014 01:47:03 +0100 Subject: actualize_script compatible multi-utilisateur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Messages plus verbeux dans actualize_script * Ajout d'un message syslog lorsque SimplePie fait une requête HTTP * Minz_Session ne fermait pas les sessions complètement. * Nouvelle option dans Minz_Dispatcher et Minz_FrontController pour ne pas utiliser ob_gzhandler. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/actualize_script.php | 36 ++++++++++++++++++++++++++---------- app/views/feed/actualize.phtml | 2 +- lib/Minz/Dispatcher.php | 23 +++++++++++++++++------ lib/Minz/FrontController.php | 15 ++++++++++++++- lib/Minz/ModelPdo.php | 5 +++++ lib/Minz/Session.php | 2 +- lib/SimplePie/SimplePie/File.php | 1 + 7 files changed, 65 insertions(+), 19 deletions(-) (limited to 'app') diff --git a/app/actualize_script.php b/app/actualize_script.php index efe21fab6..e0f995afe 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -3,24 +3,40 @@ require(dirname(__FILE__) . '/../constants.php'); //TODO: check if already running -$_GET['c'] = 'feed'; -$_GET['a'] = 'actualize'; -$_GET['force'] = true; -$_SERVER['HTTP_HOST'] = ''; - require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader -$freshRSS = new FreshRSS (); +session_cache_limiter(''); +ob_implicit_flush(false); +ob_start(); +echo 'Results: ', "\n"; //Buffered $users = listUsers(); shuffle($users); -foreach ($users as $user) { +foreach ($users as $myUser) { + syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser); + fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered + echo $myUser, ' '; //Buffered + + $_GET['c'] = 'feed'; + $_GET['a'] = 'actualize'; + $_GET['ajax'] = 1; + $_GET['force'] = true; + $_SERVER['HTTP_HOST'] = ''; + + $freshRSS = new FreshRSS(); + $freshRSS->_useOb(false); + Minz_Session::init('FreshRSS'); - Minz_Session::_param('currentUser', $user); + Minz_Session::_param('currentUser', $myUser); + $freshRSS->init(); $freshRSS->run(); - //invalidateHttpCache(); - touch(LOG_PATH . '/' . $user . '.log'); + + invalidateHttpCache(); Minz_Session::unset_session(true); + Minz_ModelPdo::clean(); } +syslog(LOG_INFO, 'FreshRSS actualize done.'); +ob_end_flush(); +fwrite(STDOUT, 'Done.' . "\n"); diff --git a/app/views/feed/actualize.phtml b/app/views/feed/actualize.phtml index a0aba9318..d86bac9de 100644 --- a/app/views/feed/actualize.phtml +++ b/app/views/feed/actualize.phtml @@ -1 +1 @@ -OK \ No newline at end of file +OK diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php index c2c5e7f65..71dfe8ac6 100644 --- a/lib/Minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -40,19 +40,26 @@ class Minz_Dispatcher { * Remplit le body de Response à partir de la Vue * @exception Minz_Exception */ - public function run () { + public function run ($ob = true) { $cache = new Minz_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 ($ob) { + ob_start ('ob_gzhandler'); + } if (Minz_Cache::isEnabled () && !$cache->expired ()) { - ob_start (); + if ($ob) { + ob_start (); + } $cache->render (); - $text = ob_get_clean(); + if ($ob) { + $text = ob_get_clean(); + } } else { + $text = ''; //TODO: Clean this code while (Minz_Request::$reseted) { Minz_Request::$reseted = false; @@ -67,9 +74,13 @@ class Minz_Dispatcher { $this->controller->lastAction (); if (!Minz_Request::$reseted) { - ob_start (); + if ($ob) { + ob_start (); + } $this->controller->view ()->build (); - $text = ob_get_clean(); + if ($ob) { + $text = ob_get_clean(); + } } } catch (Minz_Exception $e) { throw $e; diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index 8e9c511a6..7b8526bc8 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -26,6 +26,8 @@ class Minz_FrontController { protected $dispatcher; protected $router; + private $useOb = true; + /** * Constructeur * Initialise le router et le dispatcher @@ -61,7 +63,7 @@ class Minz_FrontController { */ public function run () { try { - $this->dispatcher->run (); + $this->dispatcher->run ($this->useOb); Minz_Response::send (); } catch (Minz_Exception $e) { try { @@ -94,4 +96,15 @@ class Minz_FrontController { } exit ('### Application problem ###
'."\n".$txt); } + + public function useOb() { + return $this->useOb; + } + + /** + * Use ob_start('ob_gzhandler') or not. + */ + public function _useOb($ob) { + return $this->useOb = (bool)$ob; + } } diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index a643da1f0..831df13a2 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -93,6 +93,11 @@ class Minz_ModelPdo { $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); return $res[0]; } + + public static function clean() { + self::$sharedBd = null; + self::$sharedPrefix = ''; + } } class FreshPDO extends PDO { diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php index 3f6ed88a3..37faff0fb 100644 --- a/lib/Minz/Session.php +++ b/lib/Minz/Session.php @@ -60,7 +60,7 @@ class Minz_Session { public static function unset_session ($force = false) { $language = self::param ('language'); - session_unset (); + session_destroy(); self::$session = array (); if (!$force) { diff --git a/lib/SimplePie/SimplePie/File.php b/lib/SimplePie/SimplePie/File.php index 063ad955e..cf926cf5a 100644 --- a/lib/SimplePie/SimplePie/File.php +++ b/lib/SimplePie/SimplePie/File.php @@ -77,6 +77,7 @@ class SimplePie_File $this->useragent = $useragent; if (preg_match('/^http(s)?:\/\//i', $url)) { + syslog(LOG_INFO, 'SimplePie GET ' . $url); //FreshRSS if ($useragent === null) { $useragent = ini_get('user_agent'); -- cgit v1.2.3 From c3211f1b686147229b640b35feb9be49c58b1708 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 13:46:17 +0100 Subject: La fonction de partage n'était pas visible si l'utilisateur sélectionne imprimer uniquement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrige https://github.com/marienfressinaud/FreshRSS/issues/336 --- app/views/helpers/view/normal_view.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 1b4388796..ce036e281 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -25,7 +25,7 @@ if (!empty($this->entries)) { $bottomline_favorite = $this->conf->bottomline_favorite; $bottomline_sharing = $this->conf->bottomline_sharing && ( $shaarli || $poche || $diaspora || $twitter || - $google_plus || $facebook || $email); + $google_plus || $facebook || $email || $print); $bottomline_tags = $this->conf->bottomline_tags; $bottomline_date = $this->conf->bottomline_date; $bottomline_link = $this->conf->bottomline_link; -- cgit v1.2.3 From 3b23ca881c63fe6e1cc8ef98ae5a5af645d4870a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 14:38:06 +0100 Subject: Mutex pour actualize_script Nouveau fichier temporaire ./data/actualize.lock.txt --- app/Controllers/indexController.php | 2 +- app/FreshRSS.php | 2 +- app/actualize_script.php | 20 ++++++++++++++++++-- data/.gitignore | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 5b51b3e28..690ca57be 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -133,7 +133,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles - if ($state === 'not_read' && empty($entries)) { //TODO: Remove in v0.8 + if ($state === 'not_read' && empty($entries)) { Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; $entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 4ebb6d631..f9857a4cb 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,7 +6,7 @@ class FreshRSS extends Minz_FrontController { } $this->accessControl(Minz_Session::param('currentUser', '')); $this->loadParamsView(); - $this->loadStylesAndScripts(); + $this->loadStylesAndScripts(); //TODO: Do not load that when not needed, e.g. some Ajax requests $this->loadNotifications(); } diff --git a/app/actualize_script.php b/app/actualize_script.php index e0f995afe..6009ad849 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -1,7 +1,19 @@ +$lock = DATA_PATH . '/actualize.lock.txt'; +if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) { + @unlink($lock); +} +if (($handle = @fopen($lock, 'x')) === false) { + syslog(LOG_INFO, 'FreshRSS actualize already running?'); + return; +} +register_shutdown_function('unlink', $lock); +//Could use http://php.net/function.pcntl-signal.php to catch interruptions +@fclose($handle); +// require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader @@ -10,8 +22,12 @@ ob_implicit_flush(false); ob_start(); echo 'Results: ', "\n"; //Buffered +Minz_Configuration::init(); + $users = listUsers(); -shuffle($users); +shuffle($users); //Process users in random order +array_unshift($users, Minz_Configuration::defaultUser()); //But always start with admin +$users = array_unique($users); foreach ($users as $myUser) { syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser); diff --git a/data/.gitignore b/data/.gitignore index 005982b00..afb16d9aa 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -5,3 +5,4 @@ config.php touch.txt no-cache.txt *.bak.php +*.lock.txt -- cgit v1.2.3 From cd10140346ae26d9583ff341107a12406a505976 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 15:05:34 +0100 Subject: actualize_script : messages d'erreur --- app/actualize_script.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/actualize_script.php b/app/actualize_script.php index 6009ad849..9ac80a852 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -7,7 +7,8 @@ if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) { @unlink($lock); } if (($handle = @fopen($lock, 'x')) === false) { - syslog(LOG_INFO, 'FreshRSS actualize already running?'); + syslog(LOG_NOTICE, 'FreshRSS actualize already running?'); + fwrite(STDERR, 'FreshRSS actualize already running?' . "\n"); return; } register_shutdown_function('unlink', $lock); -- cgit v1.2.3 From b48b7939d78ffbd35a7efca792e2cb9897e8f160 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 19:08:21 +0100 Subject: JavaScript : Bug actualize quand il n'y a aucun flux + un peu de JSLint. --- app/views/javascript/actualize.phtml | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'app') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 69689133c..1f6072c29 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,37 +1,41 @@ -var feeds = new Array (); +"use strict"; +var feeds = []; feeds as $feed) { ?> -feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); +feeds.push(" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); -function initProgressBar (init) { +function initProgressBar(init) { if (init) { - $("body").after ("\
\ + $("body").after("\
\ 0 / " + feeds.length + "
\ \
"); } else { - window.location.reload (); + window.location.reload(); } } -function updateProgressBar (i) { +function updateProgressBar(i) { $("#actualizeProgressBar").val(i); - $("#actualizeProgress .progress").html (i + " / " + feeds.length); + $("#actualizeProgress .progress").html(i + " / " + feeds.length); } -function updateFeeds () { - initProgressBar (true); +function updateFeeds() { + if (feeds.length === 0) { + return; + } + initProgressBar(true); var i = 0; for (var f in feeds) { - $.ajax ({ + $.ajax({ type: 'POST', url: feeds[f], - }).done (function (data) { + }).done(function (data) { i++; - updateProgressBar (i); + updateProgressBar(i); - if (i == feeds.length) { - initProgressBar (false); + if (i === feeds.length) { + initProgressBar(false); } }); } -- cgit v1.2.3 From 3b5c9676589d6b4a3f97f60a8ddd62f755134367 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 20:22:26 +0100 Subject: i18n : Ajouts pour install Corrige https://github.com/marienfressinaud/FreshRSS/issues/339 --- app/i18n/install.en.php | 5 +++++ app/i18n/install.fr.php | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/i18n/install.en.php b/app/i18n/install.en.php index 8df48989f..4d8006977 100644 --- a/app/i18n/install.en.php +++ b/app/i18n/install.en.php @@ -5,6 +5,7 @@ return array ( 'installation_step' => 'Installation - step %d', 'steps' => 'Steps', 'checks' => 'Checks', + 'general_configuration' => 'General configuration', 'bdd_configuration' => 'Database configuration', 'bdd_type' => 'Type of database', 'version_update' => 'Update', @@ -31,6 +32,10 @@ return array ( 'pdomysql_is_nok' => 'You lack PDO or its driver for MySQL (php5-mysql package)', 'dom_is_ok' => 'You have the required library to browse the DOM', 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', + 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', + 'pcre_is_nok' => 'You lack a required library for regular expressions (php-pcre)', + 'ctype_is_ok' => 'You have the required library for character type checking (ctype)', + 'ctype_is_nok' => 'You lack a required library for character type checking (php-ctype)', 'cache_is_ok' => 'Permissions on cache directory are good', 'log_is_ok' => 'Permissions on logs directory are good', 'favicons_is_ok' => 'Permissions on favicons directory are good', diff --git a/app/i18n/install.fr.php b/app/i18n/install.fr.php index a1ae8fcb5..e9dba7c23 100644 --- a/app/i18n/install.fr.php +++ b/app/i18n/install.fr.php @@ -5,6 +5,7 @@ return array ( 'installation_step' => 'Installation - étape %d', 'steps' => 'Étapes', 'checks' => 'Vérifications', + 'general_configuration' => 'Configuration générale', 'bdd_configuration' => 'Base de données', 'bdd_type' => 'Type de base de données', 'version_update' => 'Mise à jour', @@ -26,11 +27,15 @@ return array ( 'minz_is_ok' => 'Vous disposez du framework Minz', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', - 'curl_is_nok' => 'Vous ne disposez pas de cURL (librairie php5-curl)', - 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL (librairie php5-mysql)', + 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', + 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL (paquet php5-mysql)', 'pdomysql_is_nok' => 'Vous ne disposez pas de PDO ou de son driver pour MySQL', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'dom_is_nok' => 'Vous ne disposez pas du nécessaire pour parcourir le DOM (librairie php-xml)', + 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', + 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', + 'pcre_is_nok' => 'Il manque une librairie pour les expressions régulières (php-pcre)', + 'ctype_is_ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype)', + 'ctype_is_nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype)', 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', -- cgit v1.2.3 From 4972d507f1d7c2a3c59d4884be891fba2ca8e5ee Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 22:21:49 +0100 Subject: Bug changement catégories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduit récemment --- app/Controllers/configureController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 0e4801a2d..0a403fc2d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -100,12 +100,14 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $httpAuth = $user . ':' . $pass; } + $cat = intval(Minz_Request::param('category', 0)); + $values = array ( 'name' => Minz_Request::param ('name', ''), 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), 'website' => Minz_Request::param('website', ''), 'url' => Minz_Request::param('url', ''), - 'category' => intval(Minz_Request::param ('category', 0)), + 'category' => $cat, 'pathEntries' => Minz_Request::param ('path_entries', ''), 'priority' => intval(Minz_Request::param ('priority', 0)), 'httpAuth' => $httpAuth, -- cgit v1.2.3 From 1d3ff88ae6cbb072f0d2a76308a42f2baf6cb84d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 3 Jan 2014 00:49:27 +0100 Subject: favicon revisité MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Après une abondante lecture sur le sujet, voici ma tentative pour apporter une meilleure qualité de favicon sur différentes plateformes et cas, sans mettre trop de code HTML. http://www.w3.org/TR/html5/links.html#rel-icon https://github.com/audreyr/favicon-cheat-sheet http://msdn.microsoft.com/en-us/library/windows/desktop/jj673981%28v=vs.85%29.aspx https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html Il y a maintenant un favicon.ico contenant les tailles 16, 32, 48, 64, et un PNG en 256 soit la première taille standard supérieure à la meilleure résolution demandée par Android, iOS, et IE. favicon.ico généré à partir de PNGs optimisés par PNGOUT, avec la commande : `icotool -c favicon-16.png favicon-32.png favicon-48.png favicon-64.png -o favicon.ico` http://manpages.ubuntu.com/manpages/hardy/man1/icotool.1.html À tester un peu. Voir aussi https://github.com/marienfressinaud/FreshRSS/issues/264#issuecomment-29618845 --- app/layout/layout.phtml | 4 +++- p/favicon.ico | Bin 1150 -> 13094 bytes p/favicon.png | Bin 694 -> 0 bytes p/index.html | 4 +++- p/themes/icons/favicon-128.png | Bin 0 -> 1608 bytes p/themes/icons/favicon-16.png | Bin 0 -> 313 bytes p/themes/icons/favicon-256.png | Bin 0 -> 3156 bytes p/themes/icons/favicon-32.png | Bin 0 -> 513 bytes p/themes/icons/favicon-48.png | Bin 0 -> 700 bytes p/themes/icons/favicon-512.png | Bin 0 -> 6394 bytes p/themes/icons/favicon-64.png | Bin 0 -> 868 bytes 11 files changed, 6 insertions(+), 2 deletions(-) delete mode 100644 p/favicon.png create mode 100644 p/themes/icons/favicon-128.png create mode 100644 p/themes/icons/favicon-16.png create mode 100644 p/themes/icons/favicon-256.png create mode 100644 p/themes/icons/favicon-32.png create mode 100644 p/themes/icons/favicon-48.png create mode 100644 p/themes/icons/favicon-512.png create mode 100644 p/themes/icons/favicon-64.png (limited to 'app') diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index ae75c9bdb..e67d8a791 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -16,7 +16,8 @@ ?> - + + rss_url)) { ?> @@ -24,6 +25,7 @@ + diff --git a/p/favicon.ico b/p/favicon.ico index f7ae0a5b9..a2c3bc84e 100644 Binary files a/p/favicon.ico and b/p/favicon.ico differ diff --git a/p/favicon.png b/p/favicon.png deleted file mode 100644 index 3038dc3d1..000000000 Binary files a/p/favicon.png and /dev/null differ diff --git a/p/index.html b/p/index.html index eaa0d71f8..5adacab2c 100644 --- a/p/index.html +++ b/p/index.html @@ -5,8 +5,10 @@ FreshRSS + + + - -- cgit v1.2.3 From cf1f9b0f79ef885e108b7704a8f31732c5506654 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 19 Jan 2014 20:38:13 +0100 Subject: i18n token anglais --- app/i18n/en.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/i18n/en.php b/app/i18n/en.php index 01d86e5da..bb983d397 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -165,7 +165,7 @@ return array ( 'persona_connection_email' => 'Login mail address
(for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'auth_token' => 'Authentication token', - 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?token=%s', + 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?output=rss&token=%s', 'login_configuration' => 'Login', 'is_admin' => 'is administrator', 'auth_type' => 'Authentication method', -- cgit v1.2.3 From 922129c4db5f507b13ff9fca03efddc704418e68 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 22 Jan 2014 20:34:00 +0100 Subject: Style formulaire connexion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/380 --- app/views/index/formLogin.phtml | 51 +++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'app') diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml index cc43bcd19..c92b5c187 100644 --- a/app/views/index/formLogin.phtml +++ b/app/views/index/formLogin.phtml @@ -1,4 +1,24 @@ -
+ -
- -
- -
-
-
- -
+

+ + +

+ - +
-

-
-
-
- -
-
+

+ +

-

-
+

-- cgit v1.2.3 From bc6aba67bbe023c461a47bdf7c0c81d061ca6b5a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 22 Jan 2014 21:34:59 +0100 Subject: Bug récupération flux tronqués MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrige https://github.com/marienfressinaud/FreshRSS/issues/381 --- app/Models/Feed.php | 44 +------------------------------------------ lib/lib_rss.php | 54 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 47 deletions(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index df762c8fa..22c019080 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -187,54 +187,12 @@ class FreshRSS_Feed extends Minz_Model { Minz_Exception::ERROR ); } else { - $feed = new SimplePie (); - $feed->set_useragent(Minz_Translate::t ('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $url = htmlspecialchars_decode ($this->url, ENT_QUOTES); if ($this->httpAuth != '') { $url = preg_replace ('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url); } - + $feed = customSimplePie(); $feed->set_feed_url ($url); - $feed->set_cache_location (CACHE_PATH); - $feed->set_cache_duration(1500); - $feed->strip_htmltags (array ( - 'base', 'blink', 'body', 'doctype', 'embed', - 'font', 'form', 'frame', 'frameset', 'html', - 'input', 'marquee', 'meta', 'noscript', - 'object', 'param', 'plaintext', 'script', 'style', - )); - $feed->strip_attributes(array_merge($feed->strip_attributes, array( - 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', - 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', - 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); - $feed->add_attributes(array( - 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/ - 'audio' => array('preload' => 'none'), - 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), - 'video' => array('postpone' => '', 'preload' => 'none'), - )); - $feed->set_url_replacements(array( - 'a' => 'href', - 'area' => 'href', - 'audio' => 'src', - 'blockquote' => 'cite', - 'del' => 'cite', - 'form' => 'action', - 'iframe' => 'src', - 'img' => array( - 'longdesc', - 'src' - ), - 'input' => 'src', - 'ins' => 'cite', - 'q' => 'cite', - 'source' => 'src', - 'track' => 'src', - 'video' => array( - 'poster', - 'src', - ), - )); $feed->init (); if ($feed->error ()) { diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 33d7ebc32..ba5b01112 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -106,13 +106,59 @@ function html_only_entity_decode($text) { return strtr($text, $htmlEntitiesOnly); } -function sanitizeHTML($data) { +function customSimplePie() { + $simplePie = new SimplePie(); + $simplePie->set_useragent(Minz_Translate::t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_cache_location(CACHE_PATH); + $simplePie->set_cache_duration(1500); + $simplePie->strip_htmltags(array( + 'base', 'blink', 'body', 'doctype', 'embed', + 'font', 'form', 'frame', 'frameset', 'html', + 'input', 'marquee', 'meta', 'noscript', + 'object', 'param', 'plaintext', 'script', 'style', + )); + $simplePie->strip_attributes(array_merge($simplePie->strip_attributes, array( + 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', + 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', + 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); + $simplePie->add_attributes(array( + 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/ + 'audio' => array('preload' => 'none'), + 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), + 'video' => array('postpone' => '', 'preload' => 'none'), + )); + $simplePie->set_url_replacements(array( + 'a' => 'href', + 'area' => 'href', + 'audio' => 'src', + 'blockquote' => 'cite', + 'del' => 'cite', + 'form' => 'action', + 'iframe' => 'src', + 'img' => array( + 'longdesc', + 'src' + ), + 'input' => 'src', + 'ins' => 'cite', + 'q' => 'cite', + 'source' => 'src', + 'track' => 'src', + 'video' => array( + 'poster', + 'src', + ), + )); + return $simplePie; +} + +function sanitizeHTML($data, $base = '') { static $simplePie = null; if ($simplePie == null) { - $simplePie = new SimplePie(); + $simplePie = customSimplePie(); $simplePie->init(); } - return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_MAYBE_HTML)); + return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_HTML, $base)); } /* permet de récupérer le contenu d'un article pour un flux qui n'est pas complet */ @@ -125,7 +171,7 @@ function get_content_by_parsing ($url, $path) { if ($html) { $doc = phpQuery::newDocument ($html); $content = $doc->find ($path); - return sanitizeHTML($content->__toString()); + return sanitizeHTML($content->__toString(), $url); } else { throw new Exception (); } -- cgit v1.2.3 From f4c8b95b831693f66d46f9ae06550b0944280ebe Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 22 Jan 2014 21:40:28 +0100 Subject: Ordre des entrées de configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente https://github.com/marienfressinaud/FreshRSS/issues/374 --- app/layout/aside_configure.phtml | 7 ++++--- app/layout/header.phtml | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 89f63e36c..27f11ab6d 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -1,8 +1,5 @@ diff --git a/app/layout/header.phtml b/app/layout/header.phtml index d43f682b0..69b9c65a1 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -67,12 +67,13 @@ if (Minz_Configuration::canLogIn()) {