From 76a027c9bbfc646c9690f00d63be49cc4287b9c3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 10 Nov 2013 22:45:58 +0100 Subject: Amélioration des performances de small_hash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/lib_rss.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 7f22c8244..2f694fc12 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -9,14 +9,10 @@ function login_is_conf ($conf) { return $conf->mailLogin () != false; } -// tiré de Shaarli de Seb Sauvage +// tiré de Shaarli de Seb Sauvage //Format RFC 4648 base64url function small_hash ($txt) { $t = rtrim (base64_encode (hash ('crc32', $txt, true)), '='); - $t = str_replace ('+', '-', $t); // Get rid of characters which need encoding in URLs. - $t = str_replace ('/', '_', $t); - $t = str_replace ('=', '@', $t); - - return $t; + return strtr ($t, '+/', '-_'); } function timestamptodate ($t, $hour = true) { -- cgit v1.2.3 From 4c5e9d0dd828ec9da44b0f178edd73b7213d6d20 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 12 Nov 2013 22:37:25 +0100 Subject: Cohérence htmlspecialchars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le texte dans la base de données est en htmlspecialchars(UTF-8) (c'est-à-dire avec `<>&'"` encodés) mais maintenant sans autre entité HTML depuis https://github.com/marienfressinaud/FreshRSS/commit/a4fc7becb8553198d132633d775989c89c8116cd Ce patch supprime les htmlspecialchars qui faisaient du double-encodage, et en modifie d'autres en entrée. --- app/layout/aside_feed.phtml | 2 +- app/layout/aside_flux.phtml | 4 ++-- app/layout/layout.phtml | 2 +- app/models/Entry.php | 2 +- app/views/helpers/view/global_view.phtml | 4 ++-- app/views/helpers/view/normal_view.phtml | 3 +-- app/views/helpers/view/reader_view.phtml | 2 +- app/views/helpers/view/rss_view.phtml | 2 +- lib/minz/Request.php | 7 +++++-- 9 files changed, 15 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 3cfce61c5..49767740b 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -54,7 +54,7 @@
  • ✇ - name (), ENT_NOQUOTES, 'UTF-8'); ?> + name (); ?>
  • diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 87e2c000d..9471f1f7e 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -35,7 +35,7 @@
  • get_c == $cat->id ()) { $c_active = true; } ?> @@ -51,7 +51,7 @@ ✇ - name(), ENT_NOQUOTES, 'UTF-8'); ?> + name(); ?>
  • diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 9d4147887..adcc74871 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -19,7 +19,7 @@ rss_url)) { ?> - + diff --git a/app/models/Entry.php b/app/models/Entry.php index 5c6b379d8..e40cb5992 100755 --- a/app/models/Entry.php +++ b/app/models/Entry.php @@ -409,7 +409,7 @@ class EntryDAO extends Model_pdo { } $sql = 'SELECT e.* FROM ' . $this->prefix . 'entry e' - . ' INNER JOIN ' . $this->prefix . 'feed f ON e.id_feed = f.id' . $where + . ' INNER JOIN ' . $this->prefix . 'feed f ON e.id_feed = f.id' . $where . ' ORDER BY e.date' . $order . ', e.id' . $order; if (empty($limitCount)) { diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index fc55ed8ba..0eb29b11a 100644 --- a/app/views/helpers/view/global_view.phtml +++ b/app/views/helpers/view/global_view.phtml @@ -10,7 +10,7 @@
    @@ -22,7 +22,7 @@ 0 ? '' : ''; ?> - name(), ENT_NOQUOTES, 'UTF-8'); ?> + name(); ?> 0 ? ' (' . $not_read . ')' : ''; ?> 0 ? '' : ''; ?> diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 173fbad9a..faa52179a 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -46,7 +46,7 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { $feed = HelperCategory::findFeed($this->cat_aside, $item->feed ()); //We most likely already have the feed object in cache if (empty($feed)) $feed = $item->feed (true); ?> -
  • ✇ name(), ENT_NOQUOTES, 'UTF-8'); ?>
  • +
  • ✇ name(); ?>
  • title (); ?>
  • conf->toplineDate ()) { ?>
  • date (); ?> 
  • conf->toplineLink ()) { ?> @@ -65,7 +65,6 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { } ?>
    -
    @@ -79,13 +79,13 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { if ($this->conf->bottomlineRead ()) { ?>
  • isRead () ? '☑' : '☐'; ?>isRead () ? 'read' : 'unread'); ?>
  • conf->bottomlineFavorite ()) { ?>
  • isFavorite () ? '★' : '☆'; ?>isFavorite () ? 'starred' : 'non-starred'); ?>
  • @@ -97,7 +97,7 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { ?> diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 33f8641e1..b968f500f 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -215,3 +215,33 @@ function lazyimg($content) { $content ); } + +function icon($name) { // '✚', + 'all' => '☰', + 'bookmark' => '★', + 'category' => '☷', + 'category-white' => '☷', + 'close' => '❌', + 'configure' => '⚙', + 'down' => '▽', + 'favorite' => '★', + 'help' => 'ⓘ', + 'link' => '↗', + 'login' => '🔒', + 'logout' => '🔓', + 'next' => '⏩', + 'non-starred' => '☆', + 'prev' => '⏪', + 'read' => '☑', + 'unread' => '☐', + 'refresh' => '🔃', //↻ + 'search' => '🔍', + 'share' => '♺', + 'starred' => '★', + 'tag' => '⚐', + 'up' => '△', + ); + return '' . $alts[$name] . ''; +} diff --git a/public/install.php b/public/install.php index 68878a5e9..2e6519bf8 100644 --- a/public/install.php +++ b/public/install.php @@ -1,5 +1,6 @@
    - +
    diff --git a/public/scripts/main.js b/public/scripts/main.js index e9d300694..8f82fc593 100644 --- a/public/scripts/main.js +++ b/public/scripts/main.js @@ -43,11 +43,11 @@ function mark_read(active, only_not_read) { $r = active.find("a.read").attr("href", res.url), inc = 0; if (active.hasClass("not_read")) { - $r.text('☑'); + $r.find('.icon').removeClass('i_unread').addClass('i_read').text('☑'); active.removeClass("not_read"); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { - $r.text('☐'); + $r.find('.icon').removeClass('i_read').addClass('i_unread').text('☐'); active.addClass("not_read"); inc++; } @@ -113,11 +113,11 @@ function mark_favorite(active) { $b = active.find("a.bookmark").attr("href", res.url), inc = 0; if (active.hasClass("favorite")) { - $b.text('☆'); + $b.find('.icon').removeClass('i_starred').addClass('i_non-starred').text('☆'); active.removeClass("favorite"); inc--; } else { - $b.text('★'); + $b.find('.icon').removeClass('i_non-starred').addClass('i_starred').text('★'); active.addClass("favorite").find('.bookmark'); inc++; } diff --git a/public/themes/default/freshrss.css b/public/themes/default/freshrss.css index 7f57cd51b..04b6c2e93 100644 --- a/public/themes/default/freshrss.css +++ b/public/themes/default/freshrss.css @@ -25,9 +25,6 @@ margin: 0; text-shadow: 1px -1px 0 #ccc; } - .header > .item.title a:hover { - text-decoration: none; - } .header > .item.search input { width: 230px; transition: width 200ms linear; @@ -39,6 +36,10 @@ width: 100px; } +.item a:hover { + text-decoration: none; +} + #global { display: table; width: 100%; @@ -70,11 +71,6 @@ right: 33px; } - .aside.aside_flux .i_category { - background-image: url("../icons/category-white.png"); - background-image: url("../icons/category-white.svg"); - } - .nav-login { display: none; } @@ -259,36 +255,6 @@ font-size: 0px; text-align: center; } - .read { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/read.png") center center no-repeat; - background: url("../icons/read.svg") center center no-repeat; - vertical-align: middle; - } - .read:hover { - text-decoration: none; - } - .flux.not_read .read { - background: url("../icons/unread.png") center center no-repeat; - background: url("../icons/unread.svg") center center no-repeat; - } - .bookmark { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/non-starred.png") center center no-repeat; - background: url("../icons/non-starred.svg") center center no-repeat; - vertical-align: middle; - } - .bookmark:hover { - text-decoration: none; - } - .flux.favorite .bookmark { - background: url("../icons/starred.png") center center no-repeat; - background: url("../icons/starred.svg") center center no-repeat; - } .flux_header .item.website { width: 200px; overflow: hidden; @@ -313,9 +279,6 @@ color: #000; outline: none; } - .flux_header .item.title a:hover { - text-decoration: none - } .flux.not_read .flux_header .item.title { font-weight: bold; } @@ -334,17 +297,6 @@ width: 40px; text-align: center; } - .link a { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/link.png") center center no-repeat; - background: url("../icons/link.svg") center center no-repeat; - vertical-align: middle; - } - .link a:hover { - text-decoration: none; - } #stream.reader .flux { padding: 0 0 30px; diff --git a/public/themes/default/global.css b/public/themes/default/global.css index 89668c393..58b4126b0 100644 --- a/public/themes/default/global.css +++ b/public/themes/default/global.css @@ -572,6 +572,10 @@ input, select, textarea { background-image: url("../icons/category.png"); background-image: url("../icons/category.svg"); } + .i_category-white { + background-image: url("../icons/category-white.png"); + background-image: url("../icons/category-white.svg"); + } .i_rss { background-image: url("../icons/rss.png"); background-image: url("../icons/rss.svg"); @@ -580,6 +584,14 @@ input, select, textarea { background-image: url("../icons/share.png"); background-image: url("../icons/share.svg"); } + .i_starred { + background-image: url("../icons/starred.png"); + background-image: url("../icons/starred.svg"); + } + .i_non-starred { + background-image: url("../icons/non-starred.png"); + background-image: url("../icons/non-starred.svg"); + } .i_tag { background-image: url("../icons/tag.png"); background-image: url("../icons/tag.svg"); diff --git a/public/themes/flat-design/freshrss.css b/public/themes/flat-design/freshrss.css index fd0cf5b00..4c15ca138 100644 --- a/public/themes/flat-design/freshrss.css +++ b/public/themes/flat-design/freshrss.css @@ -28,9 +28,6 @@ body { display: inline-block; margin: 0; } - .header > .item.title a:hover { - text-decoration: none; - } .header > .item.search input { width: 230px; transition: width 200ms linear; @@ -42,6 +39,10 @@ body { width: 100px; } +.item a:hover { + text-decoration: none; +} + #global { display: table; width: 100%; @@ -238,36 +239,6 @@ body { font-size: 0px; text-align: center; } - .read { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/read.png") center center no-repeat; - background: url("../icons/read.svg") center center no-repeat; - vertical-align: middle; - } - .read:hover { - text-decoration: none; - } - .flux.not_read .read { - background: url("../icons/unread.png") center center no-repeat; - background: url("../icons/unread.svg") center center no-repeat; - } - .bookmark { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/non-starred.png") center center no-repeat; - background: url("../icons/non-starred.svg") center center no-repeat; - vertical-align: middle; - } - .bookmark:hover { - text-decoration: none; - } - .flux.favorite .bookmark { - background: url("../icons/starred.png") center center no-repeat; - background: url("../icons/starred.svg") center center no-repeat; - } .flux_header .item.website { width: 200px; overflow: hidden; @@ -278,10 +249,6 @@ body { .flux_header .item.website .favicon { padding: 5px; } - .flux_header .item.website a { - display: block; - height: 40px; - } .flux_header .item.title { overflow: hidden; white-space: nowrap; @@ -292,9 +259,6 @@ body { color: #333; outline: none; } - .flux_header .item.title a:hover { - text-decoration: none - } .flux.not_read .flux_header .item.title { font-weight: bold; } @@ -313,17 +277,6 @@ body { width: 40px; text-align: center; } - .link a { - display: inline-block; - width: 40px; - height: 40px; - background: url("../icons/link.png") center center no-repeat; - background: url("../icons/link.svg") center center no-repeat; - vertical-align: middle; - } - .link a:hover { - text-decoration: none; - } #stream.reader .flux { position: relative; @@ -529,7 +482,6 @@ body { .pagination .item a:hover { color: #ecf0f1; background: #34495e; - text-decoration: none; } #nav_entries { diff --git a/public/themes/flat-design/global.css b/public/themes/flat-design/global.css index 7d930c066..f2957d77a 100644 --- a/public/themes/flat-design/global.css +++ b/public/themes/flat-design/global.css @@ -556,6 +556,10 @@ input, select, textarea { background-image: url("../icons/category-white.png"); background-image: url("../icons/category-white.svg"); } + .i_category-white { + background-image: url("../icons/category-white.png"); + background-image: url("../icons/category-white.svg"); + } .i_rss { background-image: url("../icons/rss.png"); background-image: url("../icons/rss.svg"); @@ -564,6 +568,14 @@ input, select, textarea { background-image: url("../icons/share.png"); background-image: url("../icons/share.svg"); } + .i_starred { + background-image: url("../icons/starred.png"); + background-image: url("../icons/starred.svg"); + } + .i_non-starred { + background-image: url("../icons/non-starred.png"); + background-image: url("../icons/non-starred.svg"); + } .i_tag { background-image: url("../icons/tag.png"); background-image: url("../icons/tag.svg"); -- cgit v1.2.3 From 632423d97ca2ebd30b1214e03592035809217197 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 23 Nov 2013 23:47:20 +0100 Subject: Améliorations suite à icon() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/284 --- app/views/entry/bookmark.phtml | 2 +- app/views/entry/read.phtml | 2 +- lib/lib_rss.php | 2 +- public/scripts/main.js | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/app/views/entry/bookmark.phtml b/app/views/entry/bookmark.phtml index 1ff1c220c..8ce39629b 100755 --- a/app/views/entry/bookmark.phtml +++ b/app/views/entry/bookmark.phtml @@ -12,4 +12,4 @@ $url = Url::display (array ( 'params' => Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => icon(Request::param ('is_favorite') ? 'non-starred' : 'starred'))); diff --git a/app/views/entry/read.phtml b/app/views/entry/read.phtml index 6d3313a89..224651e58 100755 --- a/app/views/entry/read.phtml +++ b/app/views/entry/read.phtml @@ -12,4 +12,4 @@ $url = Url::display (array ( 'params' => Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => icon(Request::param ('is_read') ? 'unread' : 'read'))); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index b968f500f..1d9d5c7e0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -216,7 +216,7 @@ function lazyimg($content) { ); } -function icon($name) { // '✚', 'all' => '☰', diff --git a/public/scripts/main.js b/public/scripts/main.js index 8f82fc593..e21483f28 100644 --- a/public/scripts/main.js +++ b/public/scripts/main.js @@ -43,14 +43,13 @@ function mark_read(active, only_not_read) { $r = active.find("a.read").attr("href", res.url), inc = 0; if (active.hasClass("not_read")) { - $r.find('.icon').removeClass('i_unread').addClass('i_read').text('☑'); active.removeClass("not_read"); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { - $r.find('.icon').removeClass('i_read').addClass('i_unread').text('☐'); active.addClass("not_read"); inc++; } + $r.find('.icon').replaceWith(res.icon); //Update unread: feed var feed_url = active.find(".website>a").attr("href"), @@ -113,14 +112,13 @@ function mark_favorite(active) { $b = active.find("a.bookmark").attr("href", res.url), inc = 0; if (active.hasClass("favorite")) { - $b.find('.icon').removeClass('i_starred').addClass('i_non-starred').text('☆'); active.removeClass("favorite"); inc--; } else { - $b.find('.icon').removeClass('i_non-starred').addClass('i_starred').text('★'); active.addClass("favorite").find('.bookmark'); inc++; } + $b.find('.icon').replaceWith(res.icon); var favourites = $('.favorites>a').contents().last().get(0); if (favourites && favourites.textContent) { -- cgit v1.2.3 From 08ff116f040f4c735722963e39fd6eb3716ef352 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 24 Nov 2013 17:08:48 +0100 Subject: OPML : corrections import/export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit À tester plus. En particulier, ne supporte pas bien les fichiers OPML qui sont à la fois avec des entités HTML et pas en UTF-8. Devrait corriger https://github.com/marienfressinaud/FreshRSS/issues/287 --- app/models/Category.php | 2 +- app/models/Entry.php | 2 +- app/models/Feed.php | 10 +++++----- lib/lib_rss.php | 25 ++++++++++++++++++++----- 4 files changed, 27 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/app/models/Category.php b/app/models/Category.php index 1ae324ace..a01034f4e 100755 --- a/app/models/Category.php +++ b/app/models/Category.php @@ -95,7 +95,7 @@ class CategoryDAO extends Model_pdo { ); if ($stm && $stm->execute ($values)) { - return $stm->rowCount(); + return $this->bd->lastInsertId(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); diff --git a/app/models/Entry.php b/app/models/Entry.php index da296227a..e2493e266 100755 --- a/app/models/Entry.php +++ b/app/models/Entry.php @@ -213,7 +213,7 @@ class EntryDAO extends Model_pdo { ); if ($stm && $stm->execute ($values)) { - return $stm->rowCount(); + return $this->bd->lastInsertId(); } else { $info = $stm->errorInfo(); if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries diff --git a/app/models/Feed.php b/app/models/Feed.php index 46ba7bd47..822f6e703 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -270,7 +270,7 @@ class Feed extends Model { $entries = array (); foreach ($feed->get_items () as $item) { - $title = self::html_only_entity_decode (strip_tags ($item->get_title ())); + $title = html_only_entity_decode (strip_tags ($item->get_title ())); $author = $item->get_author (); $link = $item->get_permalink (); $date = strtotime ($item->get_date ()); @@ -280,11 +280,11 @@ class Feed extends Model { $tags = array (); if (!is_null ($tags_tmp)) { foreach ($tags_tmp as $tag) { - $tags[] = self::html_only_entity_decode ($tag->get_label ()); + $tags[] = html_only_entity_decode ($tag->get_label ()); } } - $content = self::html_only_entity_decode ($item->get_content ()); + $content = html_only_entity_decode ($item->get_content ()); $elinks = array(); foreach ($item->get_enclosures() as $enclosure) { @@ -301,7 +301,7 @@ class Feed extends Model { $this->id (), $item->get_id (), !is_null ($title) ? $title : '', - !is_null ($author) ? self::html_only_entity_decode ($author->name) : '', + !is_null ($author) ? html_only_entity_decode ($author->name) : '', !is_null ($content) ? $content : '', !is_null ($link) ? $link : '', $date ? $date : time () @@ -333,7 +333,7 @@ class FeedDAO extends Model_pdo { ); if ($stm && $stm->execute ($values)) { - return $stm->rowCount(); + return $this->bd->lastInsertId(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 1d9d5c7e0..8e58e4048 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -44,7 +44,7 @@ function opml_export ($cats) { $txt .= '' . "\n"; foreach ($cat['feeds'] as $feed) { - $txt .= "\t" . '' . "\n"; + $txt .= "\t" . '' . "\n"; } $txt .= '' . "\n"; @@ -53,12 +53,20 @@ function opml_export ($cats) { return $txt; } -function cleanText ($text) { - return preg_replace ('/&[\w]+;/', '', $text); +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); } function opml_import ($xml) { - $opml = @simplexml_load_string ($xml); + $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 + $opml = simplexml_load_string ($xml); if (!$opml) { throw new OpmlException (); @@ -89,12 +97,17 @@ 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'); $catDAO = new CategoryDAO (); $cat = $catDAO->searchByName ($title); if ($cat === false) { $cat = new Category ($title); + $values = array ( + 'name' => $cat->name (), + 'color' => $cat->color () + ); + $cat->_id ($catDAO->addCategory ($values)); } - $categories[] = $cat; $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ())); } @@ -129,12 +142,14 @@ function getFeedsOutline ($outline, $cat_id) { function getFeed ($outline, $cat_id) { $url = (string) $outline['xmlUrl']; + $url = htmlspecialchars($url, ENT_QUOTES, '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'); $feed = new Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); -- cgit v1.2.3 From d85e6c5b83a45ac2084ac5bca75e6b8a069e07a0 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 24 Nov 2013 20:42:55 +0100 Subject: Refactorise icon() dans RSSThemes::icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/284 --- app/layout/aside_feed.phtml | 4 ++-- app/layout/aside_flux.phtml | 12 +++++------ app/layout/header.phtml | 12 +++++------ app/layout/layout.phtml | 2 +- app/layout/nav_entries.phtml | 6 +++--- app/layout/nav_menu.phtml | 8 ++++---- app/models/RSSThemes.php | 34 +++++++++++++++++++++++++++++++- app/views/configure/categorize.phtml | 2 +- app/views/configure/display.phtml | 10 +++++----- app/views/configure/feed.phtml | 10 +++++----- app/views/entry/bookmark.phtml | 2 +- app/views/entry/read.phtml | 2 +- app/views/helpers/view/global_view.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 16 +++++++-------- lib/lib_rss.php | 30 ---------------------------- 15 files changed, 77 insertions(+), 75 deletions(-) (limited to 'lib') diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 56aeee8b9..2ce0b3ba4 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -7,7 +7,7 @@ - + diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 42dc896aa..918a44e01 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,12 +1,12 @@
    - +
      conf) || is_logged ()) { ?>
    • - +
    • conf)) { ?> @@ -16,7 +16,7 @@
    • @@ -25,7 +25,7 @@
    • @@ -38,7 +38,7 @@ get_c == $cat->id ()) { $c_active = true; } ?>
        @@ -49,7 +49,7 @@
      • ✇ diff --git a/app/layout/header.phtml b/app/layout/header.phtml index a0b603523..b0eff4d8b 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,9 +1,9 @@ conf)) { ?> @@ -42,7 +42,7 @@ - +
    @@ -53,7 +53,7 @@ @@ -73,7 +73,7 @@ if (login_is_conf ($this->conf) && !is_logged ()) { ?>
    - +
    diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index eb0f8b484..ac0031355 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -36,7 +36,7 @@ ?>
    notification['content']; ?> - +
    diff --git a/app/layout/nav_entries.phtml b/app/layout/nav_entries.phtml index 306c1536d..0811fe8fa 100644 --- a/app/layout/nav_entries.phtml +++ b/app/layout/nav_entries.phtml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 38a5a14a3..890f80f64 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -1,8 +1,8 @@ diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index 8fecec36f..1fb0368de 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -29,21 +29,21 @@
    - +
    - +
    @@ -85,7 +85,7 @@
    - +
    @@ -94,7 +94,7 @@
    - +
    diff --git a/app/views/entry/bookmark.phtml b/app/views/entry/bookmark.phtml index 8ce39629b..d175e10ed 100755 --- a/app/views/entry/bookmark.phtml +++ b/app/views/entry/bookmark.phtml @@ -12,4 +12,4 @@ $url = Url::display (array ( 'params' => Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => icon(Request::param ('is_favorite') ? 'non-starred' : 'starred'))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => RSSThemes::icon(Request::param ('is_favorite') ? 'non-starred' : 'starred'))); diff --git a/app/views/entry/read.phtml b/app/views/entry/read.phtml index 224651e58..e909d47f4 100755 --- a/app/views/entry/read.phtml +++ b/app/views/entry/read.phtml @@ -12,4 +12,4 @@ $url = Url::display (array ( 'params' => Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => icon(Request::param ('is_read') ? 'unread' : 'read'))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => RSSThemes::icon(Request::param ('is_read') ? 'unread' : 'read'))); diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index f34d368f9..ac17d608a 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 033eed5b1..31bd19036 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -42,13 +42,13 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { if ($this->conf->toplineRead ()) { ?>
  • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
  • conf->toplineFavorite ()) { ?>
  • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
  • entryPaginator) && !$this->entryPaginator->isEmpty ()) {
  • ✇ name(); ?>
  • title (); ?>
  • conf->toplineDate ()) { ?>
  • date (); ?> 
  • - conf->toplineLink ()) { ?> + conf->toplineLink ()) { ?>
    @@ -79,13 +79,13 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { if ($this->conf->bottomlineRead ()) { ?>
  • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
  • conf->bottomlineFavorite ()) { ?>
  • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
  • @@ -97,7 +97,7 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { ?> diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 8e58e4048..3c03f4281 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -230,33 +230,3 @@ function lazyimg($content) { $content ); } - -function icon($name) { - static $alts = array( - 'add' => '✚', - 'all' => '☰', - 'bookmark' => '★', - 'category' => '☷', - 'category-white' => '☷', - 'close' => '❌', - 'configure' => '⚙', - 'down' => '▽', - 'favorite' => '★', - 'help' => 'ⓘ', - 'link' => '↗', - 'login' => '🔒', - 'logout' => '🔓', - 'next' => '⏩', - 'non-starred' => '☆', - 'prev' => '⏪', - 'read' => '☑', - 'unread' => '☐', - 'refresh' => '🔃', //↻ - 'search' => '🔍', - 'share' => '♺', - 'starred' => '★', - 'tag' => '⚐', - 'up' => '△', - ); - return '' . $alts[$name] . ''; -} -- cgit v1.2.3 From c8a7913f79955e284288468ef88adc90aa788c50 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 25 Nov 2013 21:31:00 +0100 Subject: Page Speed : bouge le style 'print' dans la CSS principale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bouge le petit style dédié à l'impression dans la CSS principale, pour de meilleures performances, et aussi pour permettre aux thèmes de changer le rendu à l'impression. Au passage, ajout de `@charset "UTF-8";` en tête de CSS --- app/App_FrontController.php | 1 - lib/minz/View.php | 5 +++-- public/themes/default/freshrss.css | 39 ++++++++++++++++++++++++++++++++++ public/themes/default/global.css | 2 ++ public/themes/flat-design/freshrss.css | 39 ++++++++++++++++++++++++++++++++++ public/themes/flat-design/global.css | 2 ++ public/themes/printer/style.css | 34 ----------------------------- 7 files changed, 85 insertions(+), 37 deletions(-) delete mode 100644 public/themes/printer/style.css (limited to 'lib') diff --git a/app/App_FrontController.php b/app/App_FrontController.php index 1f270c0b1..40e31f549 100644 --- a/app/App_FrontController.php +++ b/app/App_FrontController.php @@ -65,7 +65,6 @@ class App_FrontController extends FrontController { 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'); if (login_is_conf ($this->conf)) { View::appendScript ('https://login.persona.org/include.js'); diff --git a/lib/minz/View.php b/lib/minz/View.php index fd92762b3..12202542f 100755 --- a/lib/minz/View.php +++ b/lib/minz/View.php @@ -150,8 +150,9 @@ class View { $styles .= ''; diff --git a/public/themes/default/freshrss.css b/public/themes/default/freshrss.css index 7d30c1806..468f18dc8 100644 --- a/public/themes/default/freshrss.css +++ b/public/themes/default/freshrss.css @@ -1,3 +1,5 @@ +@charset "UTF-8"; + /* STRUCTURE */ .header { display: table; @@ -820,3 +822,40 @@ -ms-transition: width 200ms linear; } } + +@media print { + .header, + .aside, + .nav_menu, + .day, + .flux_header, + .flux_content .bottom, + .pagination { + display: none; + } + + html, body { + background: #fff; + color: #000; + font-family: Serif; + font-size: 12pt; + } + + #global, + .flux_content { + display: block !important; + } + + .flux_content .content { + width: 100% !important; + text-align: justify; + } + + .flux_content .content a { + color: #000; + } + .flux_content .content a:after { + content: " (" attr(href) ") "; + text-decoration: underline; + } +} diff --git a/public/themes/default/global.css b/public/themes/default/global.css index 2004a1936..1c554d2dc 100644 --- a/public/themes/default/global.css +++ b/public/themes/default/global.css @@ -1,3 +1,5 @@ +@charset "UTF-8"; + /* FONTS */ @font-face { font-family: "OpenSans"; diff --git a/public/themes/flat-design/freshrss.css b/public/themes/flat-design/freshrss.css index 04c61085b..c2e824c22 100644 --- a/public/themes/flat-design/freshrss.css +++ b/public/themes/flat-design/freshrss.css @@ -1,3 +1,5 @@ +@charset "UTF-8"; + /* STRUCTURE */ body { background: #fafafa; @@ -752,3 +754,40 @@ body { -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); } + +@media print { + .header, + .aside, + .nav_menu, + .day, + .flux_header, + .flux_content .bottom, + .pagination { + display: none; + } + + html, body { + background: #fff; + color: #000; + font-family: Serif; + font-size: 12pt; + } + + #global, + .flux_content { + display: block !important; + } + + .flux_content .content { + width: 100% !important; + text-align: justify; + } + + .flux_content .content a { + color: #000; + } + .flux_content .content a:after { + content: " (" attr(href) ") "; + text-decoration: underline; + } +} diff --git a/public/themes/flat-design/global.css b/public/themes/flat-design/global.css index c53ec863c..8cf6412b3 100644 --- a/public/themes/flat-design/global.css +++ b/public/themes/flat-design/global.css @@ -1,3 +1,5 @@ +@charset "UTF-8"; + /* FONTS */ @font-face { font-family: "OpenSans"; diff --git a/public/themes/printer/style.css b/public/themes/printer/style.css deleted file mode 100644 index 87d019c58..000000000 --- a/public/themes/printer/style.css +++ /dev/null @@ -1,34 +0,0 @@ -.header, -.aside, -.nav_menu, -.day, -.flux_header, -.flux_content .bottom, -.pagination { - display: none; -} - -html, body { - background: #fff; - color: #000; - font-family: Serif; - font-size: 12pt; -} - -#global, -.flux_content { - display: block !important; -} - -.flux_content .content { - width: 100% !important; - text-align: justify; -} - -.flux_content .content a { - color: #000; -} -.flux_content .content a:after { - content: " (" attr(href) ") "; - text-decoration: underline; -} \ No newline at end of file -- cgit v1.2.3 From b703099c1947d26764a8e936ecb9ea58e15fbd63 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 26 Nov 2013 23:25:43 +0100 Subject: Corrige bug Minz_Log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les logs de niveau ERROR n'étaient plus loggués en production (alors que c'est quand même leur but ;)) --- lib/minz/Minz_Log.php | 2 +- lib/minz/dao/Model_pdo.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/minz/Minz_Log.php b/lib/minz/Minz_Log.php index e66cc040b..12005aa88 100644 --- a/lib/minz/Minz_Log.php +++ b/lib/minz/Minz_Log.php @@ -35,7 +35,7 @@ class Minz_Log { if (! ($env === Configuration::SILENT || ($env === Configuration::PRODUCTION - && ($level <= Minz_Log::NOTICE)))) { + && ($level >= Minz_Log::NOTICE)))) { if (is_null ($file_name)) { $file_name = LOG_PATH . '/application.log'; } diff --git a/lib/minz/dao/Model_pdo.php b/lib/minz/dao/Model_pdo.php index 810e69847..545f59e81 100755 --- a/lib/minz/dao/Model_pdo.php +++ b/lib/minz/dao/Model_pdo.php @@ -66,7 +66,7 @@ class Model_pdo { } catch (Exception $e) { throw new PDOConnectionException ( $string, - $db['user'], MinzException::WARNING + $db['user'], MinzException::ERROR ); } } -- cgit v1.2.3 From 7cdc477c45a84bde56f5253ce34924f164e6ca0a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 28 Nov 2013 20:59:31 +0100 Subject: touch en microsecondes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passage en microsecondes pour le touch (gestion du cache) pour éviter les problèmes en particulier dans le cas de requêtes de moins d'une seconde. Nouvelle fonction invalidateHttpCache() pour plus facilement changer de méthode de contrôle de fraîcheur de cache. Devrait résoudre https://github.com/marienfressinaud/FreshRSS/issues/296 --- actualize_script.php | 2 +- app/controllers/entryController.php | 2 +- app/controllers/indexController.php | 4 ++-- app/layout/layout.phtml | 2 +- app/models/RSSConfiguration.php | 2 +- lib/lib_rss.php | 4 ++++ lib/minz/dao/Model_pdo.php | 2 +- public/index.php | 7 ++++--- 8 files changed, 15 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/actualize_script.php b/actualize_script.php index bc1d108bd..942070ccc 100755 --- a/actualize_script.php +++ b/actualize_script.php @@ -20,4 +20,4 @@ $front_controller = new App_FrontController (); $front_controller->init (); Session::_param('mail', true); // permet de se passer de la phase de connexion $front_controller->run (); -touch(DATA_PATH . '/touch.txt'); +invalidateHttpCache(); diff --git a/app/controllers/entryController.php b/app/controllers/entryController.php index fa34ad429..d92eb0ed3 100755 --- a/app/controllers/entryController.php +++ b/app/controllers/entryController.php @@ -84,7 +84,7 @@ class entryController extends ActionController { $entryDAO = new EntryDAO(); $entryDAO->optimizeTable(); - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); $notif = array ( 'type' => 'good', diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index e4462e543..8e6abd682 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -272,7 +272,7 @@ class indexController extends ActionController { $res = json_decode ($result, true); if ($res['status'] == 'okay' && $res['email'] == $this->view->conf->mailLogin ()) { Session::_param ('mail', $res['email']); - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); } else { $res = array (); $res['status'] = 'failure'; @@ -285,6 +285,6 @@ class indexController extends ActionController { public function logoutAction () { $this->view->_useLayout (false); Session::_param ('mail'); - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); } } diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index c53b28841..9b502275c 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -32,7 +32,7 @@ notification)) { - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); ?>
    notification['content']; ?> diff --git a/app/models/RSSConfiguration.php b/app/models/RSSConfiguration.php index c36548e6f..fe6cd48d3 100755 --- a/app/models/RSSConfiguration.php +++ b/app/models/RSSConfiguration.php @@ -473,6 +473,6 @@ class RSSConfigurationDAO extends Model_array { } $this->writeFile($this->array); - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); } } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 3c03f4281..5a74bfd0a 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -230,3 +230,7 @@ function lazyimg($content) { $content ); } + +function invalidateHttpCache() { + file_put_contents(DATA_PATH . '/touch.txt', microtime(true)); +} diff --git a/lib/minz/dao/Model_pdo.php b/lib/minz/dao/Model_pdo.php index 545f59e81..48c81d082 100755 --- a/lib/minz/dao/Model_pdo.php +++ b/lib/minz/dao/Model_pdo.php @@ -85,7 +85,7 @@ class Model_pdo { class FreshPDO extends PDO { private static function check($statement) { if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { - touch(DATA_PATH . '/touch.txt'); + invalidateHttpCache(); } } diff --git a/public/index.php b/public/index.php index 9bf4fc073..cabd836d5 100755 --- a/public/index.php +++ b/public/index.php @@ -27,10 +27,11 @@ if (file_exists ('install.php')) { if (!file_exists(DATA_PATH . '/no-cache.txt')) { require (LIB_PATH . '/http-conditional.php'); $dateLastModification = max( - @filemtime(DATA_PATH . '/touch.txt') - 1, - @filemtime(LOG_PATH . '/application.log') - 1, - @filemtime(DATA_PATH . '/application.ini') - 1 + @filemtime(DATA_PATH . '/touch.txt'), + @filemtime(LOG_PATH . '/application.log'), + @filemtime(DATA_PATH . '/application.ini') ); + $_SERVER['QUERY_STRING'] .= '&utime=' . file_get_contents(DATA_PATH . '/touch.txt'); if (httpConditional($dateLastModification, 0, 0, false, false, true)) { exit(); //No need to send anything } -- cgit v1.2.3 From dd61248d319e3f74a3670f5e15bc1e1ab2c2ae1a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 28 Nov 2013 22:50:34 +0100 Subject: Correction download_favicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En fait renvoyer l'url ne servait à rien puisque c'était la même De plus il y avait une faute de typo dans le nom de la fonction Voir #278 --- app/models/Feed.php | 3 +-- lib/lib_rss.php | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/app/models/Feed.php b/app/models/Feed.php index d4ff00e21..2260f6fdf 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -100,8 +100,7 @@ class Feed extends Model { $favicon_url = Url::display ($file); if (!file_exists (PUBLIC_PATH . $file)) { - $base_url = dowload_favicon ($this->website (), $this->id ()); - $favicon_url = Url::display ($base_url); + download_favicon ($this->website (), $this->id ()); } return $favicon_url; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 5a74bfd0a..08e65a45f 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -181,11 +181,10 @@ function get_content_by_parsing ($url, $path) { } /* Télécharge le favicon d'un site, le place sur le serveur et retourne l'URL */ -function dowload_favicon ($website, $id) { +function download_favicon ($website, $id) { $url = 'http://g.etfv.co/' . $website; $favicons_dir = PUBLIC_PATH . '/favicons'; $dest = $favicons_dir . '/' . $id . '.ico'; - $favicon_url = '/favicons/' . $id . '.ico'; if (!is_dir ($favicons_dir)) { if (!mkdir ($favicons_dir, 0755, true)) { @@ -214,8 +213,6 @@ function dowload_favicon ($website, $id) { curl_close ($c); } - - return $favicon_url; } /** -- cgit v1.2.3 From 234d1a9dca5a78980e5472d32fd8f5f458832ebd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 29 Nov 2013 11:26:23 +0100 Subject: Add stripslashes when displaying the title Fix issue #299 --- lib/minz/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php index 5be2ea63d..7d6e3743e 100755 --- a/lib/minz/Configuration.php +++ b/lib/minz/Configuration.php @@ -76,7 +76,7 @@ class Configuration { return self::$use_url_rewriting; } public static function title () { - return self::$title; + return stripslashes(self::$title); } public static function language () { return self::$language; -- cgit v1.2.3 From 85e7ac96a10ffd9277ca3b11433a69ad0588a02e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 1 Dec 2013 16:23:35 +0100 Subject: Charge lib_phpQuery uniquement au besoin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Évite de charger lib_phpQuery (170ko de code tout de même) jusqu'au moment où la librairie est éventuellement nécessaire (c'est-à-dire pour le téléchargement du contenu des articles tronqués, si cette fonctionnalité est utilisée) --- app/App_FrontController.php | 1 - lib/lib_rss.php | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/app/App_FrontController.php b/app/App_FrontController.php index 176677781..0721dba45 100644 --- a/app/App_FrontController.php +++ b/app/App_FrontController.php @@ -19,7 +19,6 @@ class App_FrontController extends FrontController { } private function loadLibs () { - require (LIB_PATH . '/lib_phpQuery.php'); require (LIB_PATH . '/lib_rss.php'); require (LIB_PATH . '/SimplePie_autoloader.php'); } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 08e65a45f..93fa48af0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -159,6 +159,8 @@ function getFeed ($outline, $cat_id) { /* 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'); + $html = file_get_contents ($url); if ($html) { -- cgit v1.2.3 From 0c6142dad2aa645aa202e72814070d1f47bd9158 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 1 Dec 2013 16:55:41 +0100 Subject: PHP : JSON alternative Utilise http://pear.php.net/package/Services_JSON si les fonctions json_* native de PHP ne sont pas disponibles Pour https://github.com/marienfressinaud/FreshRSS/issues/306 --- lib/JSON.php | 933 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/lib_rss.php | 16 + 2 files changed, 949 insertions(+) create mode 100644 lib/JSON.php (limited to 'lib') diff --git a/lib/JSON.php b/lib/JSON.php new file mode 100644 index 000000000..8dc8a6f01 --- /dev/null +++ b/lib/JSON.php @@ -0,0 +1,933 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_USE_TO_JSON', 64); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + * - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects + * It serializes the return value from the toJSON call rather + * than the object it'self, toJSON can return associative arrays, + * strings or numbers, if you return an object, make sure it does + * not have a toJSON method, otherwise an error will occur. + */ + function Services_JSON($use = 0) + { + $this->use = $use; + $this->_mb_strlen = function_exists('mb_strlen'); + $this->_mb_convert_encoding = function_exists('mb_convert_encoding'); + $this->_mb_substr = function_exists('mb_substr'); + } + // private - cache the mbstring lookup results.. + var $_mb_strlen = false; + var $_mb_substr = false; + var $_mb_convert_encoding = false; + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if($this->_mb_convert_encoding) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if($this->_mb_convert_encoding) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch($this->strlen8($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format (and sends JSON Header) + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + header('Content-type: application/json'); + return $this->encodeUnsafe($var); + } + /** + * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!) + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encodeUnsafe($var) + { + // see bug #16908 - regarding numeric locale printing + $lc = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, 'C'); + $ret = $this->_encode($var); + setlocale(LC_NUMERIC, $lc); + return $ret; + + } + /** + * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function _encode($var) + { + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = $this->strlen8($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + if ($c+1 >= $strlen_var) { + $c += 1; + $ascii .= '?'; + break; + } + + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + if ($c+2 >= $strlen_var) { + $c += 2; + $ascii .= '?'; + break; + } + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + @ord($var{$c + 1}), + @ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + if ($c+3 >= $strlen_var) { + $c += 3; + $ascii .= '?'; + break; + } + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + if ($c+4 >= $strlen_var) { + $c += 4; + $ascii .= '?'; + break; + } + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + if ($c+5 >= $strlen_var) { + $c += 5; + $ascii .= '?'; + break; + } + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, '_encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + + // support toJSON methods. + if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) { + // this may end up allowing unlimited recursion + // so we check the return value to make sure it's not got the same method. + $recode = $var->toJSON(); + + if (method_exists($recode, 'toJSON')) { + + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(class_name($var). + " toJSON returned an object with a toJSON method."); + + } + + return $this->_encode( $recode ); + } + + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->_encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = $this->substr8($str, 0, 1); + $chrs = $this->substr8($str, 1, -1); + $utf8 = ''; + $strlen_chrs = $this->strlen8($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2))) + . chr(hexdec($this->substr8($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= $this->substr8($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= $this->substr8($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= $this->substr8($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= $this->substr8($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= $this->substr8($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = $this->substr8($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = $this->strlen8($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = $this->substr8($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + (($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } + + /** + * Calculates length of string in bytes + * @param string + * @return integer length + */ + function strlen8( $str ) + { + if ( $this->_mb_strlen ) { + return mb_strlen( $str, "8bit" ); + } + return strlen( $str ); + } + + /** + * Returns part of a string, interpreting $start and $length as number of bytes. + * @param string + * @param integer start + * @param integer length + * @return integer length + */ + function substr8( $string, $start, $length=false ) + { + if ( $length === false ) { + $length = $this->strlen8( $string ) - $start; + } + if ( $this->_mb_substr ) { + return mb_substr( $string, $start, $length, "8bit" ); + } + return substr( $string, $start, $length ); + } + +} + +if (class_exists('PEAR_Error')) { + + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + +} else { + + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + +} diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 93fa48af0..e3deb9792 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -1,4 +1,20 @@ decode($var); + } +} + +if (!function_exists('json_encode')) { + require_once('JSON.php'); + function json_encode($var) { + $JSON = new Services_JSON; + return $JSON->encode($var); + } +} + // vérifie qu'on est connecté function is_logged () { return Session::param ('mail') != false; -- cgit v1.2.3 From c9c068115d17132ddcdf2194d216533823831896 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 1 Dec 2013 17:33:07 +0100 Subject: Bug JSON alternative Suite https://github.com/marienfressinaud/FreshRSS/issues/306 --- lib/lib_rss.php | 4 ++-- public/install.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index e3deb9792..46bf76d2c 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -3,7 +3,7 @@ if (!function_exists('json_decode')) { require_once('JSON.php'); function json_decode($var) { $JSON = new Services_JSON; - return $JSON->decode($var); + return (array)($JSON->decode($var)); } } @@ -11,7 +11,7 @@ if (!function_exists('json_encode')) { require_once('JSON.php'); function json_encode($var) { $JSON = new Services_JSON; - return $JSON->encode($var); + return $JSON->encodeUnsafe($var); } } diff --git a/public/install.php b/public/install.php index c4ed223de..9b7cc779f 100644 --- a/public/install.php +++ b/public/install.php @@ -599,7 +599,7 @@ function printStep3 () {
    - +
    -- cgit v1.2.3 From b0cbc6fe5da527aa2a4fedf4b138264ff983d159 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 1 Dec 2013 22:58:15 +0100 Subject: Favicons en parallèle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvelle méthode pour afficher les favicons à la demande et en parallèle. Déplacement du dossier des favicons sous /data/favicons/ Devrait permettre de fermer le problème d'import OPML https://github.com/marienfressinaud/FreshRSS/issues/228 Voir aussi https://github.com/marienfressinaud/FreshRSS/issues/290 --- app/models/Feed.php | 11 +++----- data/favicons/.gitignore | 2 ++ lib/lib_rss.php | 35 ------------------------ public/f.php | 67 ++++++++++++++++++++++++++++++++++++++++++++++ public/favicons/.gitignore | 1 - 5 files changed, 73 insertions(+), 43 deletions(-) create mode 100644 data/favicons/.gitignore create mode 100644 public/f.php delete mode 100644 public/favicons/.gitignore (limited to 'lib') diff --git a/app/models/Feed.php b/app/models/Feed.php index f183b2aa7..41eb3df23 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -96,14 +96,11 @@ class Feed extends Model { return $this->nbNotRead; } public function favicon () { - $file = '/favicons/' . $this->id () . '.ico'; - - $favicon_url = Url::display ($file); - if (!file_exists (PUBLIC_PATH . $file)) { - download_favicon ($this->website (), $this->id ()); + $file = DATA_PATH . '/favicons/' . $this->id () . '.txt'; + if (!file_exists ($file)) { + file_put_contents($file, $this->website ()); } - - return $favicon_url; + return Url::display ('/f.php?' . $this->id ()); } public function _id ($value) { diff --git a/data/favicons/.gitignore b/data/favicons/.gitignore new file mode 100644 index 000000000..5ec725522 --- /dev/null +++ b/data/favicons/.gitignore @@ -0,0 +1,2 @@ +*.ico +*.txt \ No newline at end of file diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 46bf76d2c..c4ca03165 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -198,41 +198,6 @@ function get_content_by_parsing ($url, $path) { } } -/* Télécharge le favicon d'un site, le place sur le serveur et retourne l'URL */ -function download_favicon ($website, $id) { - $url = 'http://g.etfv.co/' . $website; - $favicons_dir = PUBLIC_PATH . '/favicons'; - $dest = $favicons_dir . '/' . $id . '.ico'; - - if (!is_dir ($favicons_dir)) { - if (!mkdir ($favicons_dir, 0755, true)) { - return $url; - } - } - - if (!file_exists ($dest)) { - $c = curl_init ($url); - curl_setopt ($c, CURLOPT_HEADER, false); - curl_setopt ($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt ($c, CURLOPT_BINARYTRANSFER, true); - $imgRaw = curl_exec ($c); - - if (curl_getinfo ($c, CURLINFO_HTTP_CODE) == 200) { - $file = fopen ($dest, 'w'); - if ($file === false) { - return $url; - } - - fwrite ($file, $imgRaw); - fclose ($file); - } else { - return $url; - } - - curl_close ($c); - } -} - /** * Add support of image lazy loading * Move content from src attribute to data-original diff --git a/public/f.php b/public/f.php new file mode 100644 index 000000000..3be74776e --- /dev/null +++ b/public/f.php @@ -0,0 +1,67 @@ + $icoMTime)) { + if ($txtMTime == false) { + header('HTTP/1.1 404 Not Found'); + die(); + } + $url = file_get_contents($txt); + if (!download_favicon($url, $ico)) { + die(); + } +} + +header('Content-Type: image/x-icon'); +header('Content-Disposition: inline; filename="' . $id . '.ico"'); + +require(LIB_PATH . '/http-conditional.php'); +if (!httpConditional($icoMTime, 31557600, 2)) { + readfile($ico); +} diff --git a/public/favicons/.gitignore b/public/favicons/.gitignore deleted file mode 100644 index 29d1aae76..000000000 --- a/public/favicons/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.ico \ No newline at end of file -- cgit v1.2.3 From 97227a067ba055dd1652505ec8e4817105932d15 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 00:06:52 +0100 Subject: OPML : Import instantané MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clôture https://github.com/marienfressinaud/FreshRSS/issues/228 Nous perdons le champ description des flux, mais celui-ci pourrait par exemple être récupéré au premier rafraîchissement du flux si nécessaire --- app/controllers/feedController.php | 2 -- lib/lib_rss.php | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index d810296b0..f84a952ed 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -300,8 +300,6 @@ class feedController extends ActionController { $i = 0; foreach ($feeds as $feed) { try { - $feed->load (); - $values = array ( 'id' => $feed->id (), 'url' => $feed->url (), diff --git a/lib/lib_rss.php b/lib/lib_rss.php index c4ca03165..9726cc92b 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -169,6 +169,9 @@ function getFeed ($outline, $cat_id) { $feed = new Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); + if (isset($outline['htmlUrl'])) { + $feed->_website((string)$outline['htmlUrl']); + } return $feed; } -- cgit v1.2.3 From 1a270309a53cca0124758b026512d781a595ec70 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 18:23:57 +0100 Subject: Favicons : amélioration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Évite de faire un accès disque systématique pour vérifier si le .ico est présent, et ne le fait plus que lors d'un ajout ou rafraîchissement de flux * Corrige un bug pour les flux qui n'ont pas de site Web déclaré * Efface le favicon lorsqu'un flux est supprimé (seulement individuellement pour l'instant) Voir aussi https://github.com/marienfressinaud/FreshRSS/issues/290 --- app/controllers/feedController.php | 8 +++++++- app/models/Feed.php | 39 ++++++++++++++++++++++---------------- lib/lib_rss.php | 16 ++++++++++++++++ public/f.php | 5 +++-- 4 files changed, 49 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index f84a952ed..e0c526655 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -86,6 +86,7 @@ class feedController extends ActionController { Session::_param ('notification', $notif); } else { $feed->_id ($id); + $feed->faviconPrepare(); $entryDAO = new EntryDAO (); $entries = $feed->entries (); @@ -192,6 +193,7 @@ class feedController extends ActionController { foreach ($feeds as $feed) { try { $feed->load (); + $feed->faviconPrepare(); $entries = $feed->entries (); usort($entries, 'self::entryDateComparer'); @@ -313,7 +315,9 @@ class feedController extends ActionController { // ajout du flux que s'il n'est pas déjà en BDD if (!$feedDAO->searchByUrl ($values['url'])) { - if (!$feedDAO->addFeed ($values)) { + if ($feedDAO->addFeed ($values)) { + $feed->faviconPrepare(); + } else { $error = true; } } @@ -354,6 +358,7 @@ class feedController extends ActionController { 'type' => 'good', 'content' => Translate::t ('category_emptied') ); + //TODO: Delete old favicons } else { $notif = array ( 'type' => 'bad', @@ -366,6 +371,7 @@ class feedController extends ActionController { 'type' => 'good', 'content' => Translate::t ('feed_deleted') ); + Feed::faviconDelete($id); } else { $notif = array ( 'type' => 'bad', diff --git a/app/models/Feed.php b/app/models/Feed.php index 41eb3df23..14366c5b3 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -95,32 +95,36 @@ class Feed extends Model { return $this->nbNotRead; } - public function favicon () { + public function faviconPrepare() { $file = DATA_PATH . '/favicons/' . $this->id () . '.txt'; if (!file_exists ($file)) { - file_put_contents($file, $this->website ()); + $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 Url::display ('/f.php?' . $this->id ()); } public function _id ($value) { $this->id = $value; } - public function _url ($value) { - if (empty ($value)) { - throw new BadUrlException ($value); - } - if (!preg_match ('#^https?://#i', $value)) { - $value = 'http://' . $value; + public function _url ($value, $validate=true) { + if ($validate) { + $value = checkUrl($value); } - - if (filter_var ($value, FILTER_VALIDATE_URL)) { - $this->url = $value; - } elseif (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && ($value === filter_var($value, FILTER_SANITIZE_URL))) { //PHP bug #51192 - $this->url = $value; - } else { + if (empty ($value)) { throw new BadUrlException ($value); } + $this->url = $value; } public function _category ($value) { $this->category = $value; @@ -131,8 +135,11 @@ class Feed extends Model { } $this->name = $value; } - public function _website ($value) { - if (is_null ($value)) { + public function _website ($value, $validate=true) { + if ($validate) { + $value = checkUrl($value); + } + if (empty ($value)) { $value = ''; } $this->website = $value; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 9726cc92b..ea5a1ffd0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -15,6 +15,22 @@ if (!function_exists('json_encode')) { } } +function checkUrl($url) { + if (empty ($url)) { + return ''; + } + if (!preg_match ('#^https?://#i', $value)) { + $url = 'http://' . $url; + } + if (filter_var($url, FILTER_VALIDATE_URL) || + (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && //PHP bug #51192 + ($value === filter_var($value, FILTER_SANITIZE_URL)))) { + return url; + } else { + return false; + } +} + // vérifie qu'on est connecté function is_logged () { return Session::param ('mail') != false; diff --git a/public/f.php b/public/f.php index 48b59e1f9..85e73113a 100644 --- a/public/f.php +++ b/public/f.php @@ -2,7 +2,7 @@ require('../constants.php'); $favicons_dir = DATA_PATH . '/favicons/'; -/* Télécharge le favicon d'un site, le place sur le serveur et retourne l'URL */ +/* Télécharge le favicon d'un site et le place sur le serveur */ function download_favicon ($website, $dest) { $ok = false; $url = 'http://g.etfv.co/' . $website; @@ -60,10 +60,11 @@ if (($icoMTime == false) || ($txtMTime > $icoMTime)) { } } +require(LIB_PATH . '/http-conditional.php'); + header('Content-Type: image/x-icon'); header('Content-Disposition: inline; filename="' . $id . '.ico"'); -require(LIB_PATH . '/http-conditional.php'); if (!httpConditional($icoMTime, 31557600, 2)) { readfile($ico); } -- cgit v1.2.3 From b40783e8889b64f813c898ee2ce7e967582ef34e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 18:27:03 +0100 Subject: Affiche la taille de la base de données MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/configureController.php | 1 + app/i18n/en.php | 4 ++-- app/i18n/fr.php | 4 ++-- app/views/configure/display.phtml | 2 +- lib/lib_rss.php | 15 +++++++++++++++ lib/minz/dao/Model_pdo.php | 10 ++++++++++ 6 files changed, 31 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/app/controllers/configureController.php b/app/controllers/configureController.php index 424e3834a..68d798581 100755 --- a/app/controllers/configureController.php +++ b/app/controllers/configureController.php @@ -265,6 +265,7 @@ class configureController extends ActionController { $entryDAO = new EntryDAO (); $this->view->nb_total = $entryDAO->count (); + $this->view->size_total = $entryDAO->size (); } public function sharingAction () { diff --git a/app/i18n/en.php b/app/i18n/en.php index 669de4d42..6c6c52e43 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -132,7 +132,7 @@ return array ( 'feed_description' => 'Description', 'website_url' => 'Website URL', 'feed_url' => 'Feed URL', - 'number_articles' => 'Number of articles', + 'articles' => 'articles', 'keep_history' => 'Keep history?', 'categorize' => 'Store in a category', 'advanced' => 'Advanced', @@ -182,7 +182,7 @@ return array ( 'share' => 'Share', 'by_email' => 'By email', 'optimize_bdd' => 'Optimize database', - 'optimize_todo_sometimes' => 'To do occasionally to reduce size of database', + 'optimize_todo_sometimes' => 'To do occasionally to improve performance', 'theme' => 'Theme', 'more_information' => 'More information', 'activate_sharing' => 'Activate sharing', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index a397b4816..966708f21 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -132,7 +132,7 @@ return array ( 'feed_description' => 'Description', 'website_url' => 'URL du site', 'feed_url' => 'URL du flux', - 'number_articles' => 'Nombre d’articles', + 'articles' => 'articles', 'keep_history' => 'Garder l’historique ?', 'categorize' => 'Ranger dans une catégorie', 'advanced' => 'Avancé', @@ -182,7 +182,7 @@ return array ( 'share' => 'Partager', 'by_email' => 'Par courriel', 'optimize_bdd' => 'Optimiser la base de données', - 'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD', + 'optimize_todo_sometimes' => 'À faire de temps en temps pour améliorer les performances', 'theme' => 'Thème', 'more_information' => 'Plus d’informations', 'activate_sharing' => 'Activer le partage', diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 90416145a..e6d867ed1 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -196,7 +196,7 @@
    -

    nb_total; ?>

    +

    nb_total; ?> , size_total); ?>.

    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index ea5a1ffd0..3e23f7542 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -47,6 +47,21 @@ function small_hash ($txt) { return strtr ($t, '+/', '-_'); } +function formatBytes($bytes, $precision = 2, $system = 'IEC') { + if ($system === 'IEC') { + $base = 1024; + $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB'); + } elseif ($system === 'SI') { + $base = 1000; + $units = array('B', 'KB', 'MB', 'GB', 'TB'); + } + $bytes = max(intval($bytes), 0); + $pow = $bytes === 0 ? 0 : floor(log($bytes) / log($base)); + $pow = min($pow, count($units) - 1); + $bytes /= pow($base, $pow); + return round($bytes, $precision) . ' ' . $units[$pow]; +} + function timestamptodate ($t, $hour = true) { $month = Translate::t (date('M', $t)); if ($hour) { diff --git a/lib/minz/dao/Model_pdo.php b/lib/minz/dao/Model_pdo.php index 48c81d082..a93291fc8 100755 --- a/lib/minz/dao/Model_pdo.php +++ b/lib/minz/dao/Model_pdo.php @@ -80,6 +80,16 @@ class Model_pdo { 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 { -- cgit v1.2.3 From 65c972873bd61356defac787bfcdd2cba3323a5e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 18:31:40 +0100 Subject: OPML : améliorations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Charge et sauve la description des flux. Redirige vers la page d'accueil après une importation OPML (maintenant rapide, et pour mieux permettre le rafraîchissement des flux avec moins de risques que l'utilisateur quitte la page) Suite de https://github.com/marienfressinaud/FreshRSS/issues/228 --- app/controllers/feedController.php | 6 +++--- app/models/Feed.php | 6 ++---- lib/lib_rss.php | 7 +++++-- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index e0c526655..6d25fe092 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -340,10 +340,10 @@ class feedController extends ActionController { Session::_param ('notification', $notif); Session::_param ('actualize_feeds', true); - // et on redirige vers la page import/export + // et on redirige vers la page d'accueil Request::forward (array ( - 'c' => 'configure', - 'a' => 'importExport' + 'c' => 'index', + 'a' => 'index' ), true); } diff --git a/app/models/Feed.php b/app/models/Feed.php index 14366c5b3..c1d0379a9 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -247,10 +247,8 @@ class Feed extends Model { $this->_url ($subscribe_url); } - if (empty($this->name)) { // May come from OPML - $title = $feed->get_title (); - $this->_name (!is_null ($title) ? $title : $this->url); - } + $title = $feed->get_title (); + $this->_name (!is_null ($title) ? $title : $this->url); $this->_website ($feed->get_link ()); $this->_description ($feed->get_description ()); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 3e23f7542..9bce0760b 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -91,7 +91,7 @@ function opml_export ($cats) { $txt .= '' . "\n"; foreach ($cat['feeds'] as $feed) { - $txt .= "\t" . '' . "\n"; + $txt .= "\t" . '' . "\n"; } $txt .= '' . "\n"; @@ -201,7 +201,10 @@ function getFeed ($outline, $cat_id) { $feed->_category ($cat_id); $feed->_name ($title); if (isset($outline['htmlUrl'])) { - $feed->_website((string)$outline['htmlUrl']); + $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_QUOTES, 'UTF-8')); + } + if (isset($outline['description'])) { + $feed->_description(htmlspecialchars((string)$outline['description'], ENT_QUOTES, 'UTF-8')); } return $feed; } -- cgit v1.2.3 From ee6a1bdde381a4ac95d8c7393deda3ebbaae1ead Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 19:53:36 +0100 Subject: PHP : Alertes fonction date() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En attendant https://github.com/marienfressinaud/FreshRSS/issues/310 la fonction date() générait des alertes sur les systèmes n'ayant pas personnalisé PHP Voir http://us3.php.net/manual/en/function.date-default-timezone-set.php --- app/views/index/logs.phtml | 6 +++--- lib/lib_rss.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml index 71a55a1b7..5a0b03b98 100644 --- a/app/views/index/logs.phtml +++ b/app/views/index/logs.phtml @@ -12,11 +12,11 @@
    logsPaginator->render ('logs_pagination.phtml', 'page'); ?> - + -
    date ())); ?>info (), ENT_NOQUOTES, 'UTF-8'); ?>
    +
    date ())); ?>info (), ENT_NOQUOTES, 'UTF-8'); ?>
    - + logsPaginator->render ('logs_pagination.phtml','page'); ?>
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 9bce0760b..22e50a424 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -70,7 +70,7 @@ function timestamptodate ($t, $hour = true) { $date = Translate::t ('format_date', $month); } - return date ($date, $t); + return @date ($date, $t); } function sortEntriesByDate ($entry1, $entry2) { -- cgit v1.2.3 From 56b269cef6bc54fa8d8fc69ff0f0e8b2ffb36afb Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 20:12:55 +0100 Subject: PHP : suppression autres alertes Voir https://github.com/marienfressinaud/FreshRSS/issues/310 --- app/layout/nav_menu.phtml | 2 +- app/models/Entry.php | 2 +- app/models/Feed.php | 2 +- lib/http-conditional.php | 4 ++-- public/install.php | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 4b4945108..c71497ced 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -70,7 +70,7 @@
  • diff --git a/app/models/Entry.php b/app/models/Entry.php index 196823f67..899e98b00 100755 --- a/app/models/Entry.php +++ b/app/models/Entry.php @@ -137,7 +137,7 @@ class Entry extends Model { public function isDay ($day) { $date = $this->dateAdded(true); - $today = strtotime('today'); + $today = @strtotime('today'); $yesterday = $today - 86400; if ($day === Days::TODAY && diff --git a/app/models/Feed.php b/app/models/Feed.php index c1d0379a9..555759c9a 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -265,7 +265,7 @@ class Feed extends Model { $title = html_only_entity_decode (strip_tags ($item->get_title ())); $author = $item->get_author (); $link = $item->get_permalink (); - $date = strtotime ($item->get_date ()); + $date = @strtotime ($item->get_date ()); // gestion des tags (catégorie == tag) $tags_tmp = $item->get_categories (); diff --git a/lib/http-conditional.php b/lib/http-conditional.php index 6684fd6ac..59fbef41f 100644 --- a/lib/http-conditional.php +++ b/lib/http-conditional.php @@ -35,7 +35,7 @@ ... //Rest of the script, just as you would do normally. ?> - Version 1.7 beta, 2013-11-03, http://alexandre.alapetite.fr/doc-alex/php-http-304/ + Version 1.7 beta, 2013-12-02, http://alexandre.alapetite.fr/doc-alex/php-http-304/ ------------------------------------------------------------------ Written by Alexandre Alapetite, http://alexandre.alapetite.fr/cv/ @@ -124,7 +124,7 @@ function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMod if ($feedMode) {//Special RSS/ATOM global $clientCacheDate; - $clientCacheDate=strtotime($dateCacheClient); + $clientCacheDate=@strtotime($dateCacheClient); $cachePrivacy=0; } diff --git a/public/install.php b/public/install.php index 577714764..6765d8cd1 100644 --- a/public/install.php +++ b/public/install.php @@ -228,6 +228,7 @@ function saveStep3 () { $_SESSION['bd_error'] = true; } } + invalidateHttpCache(); } function deleteInstall () { $res = unlink (PUBLIC_PATH . '/install.php'); -- cgit v1.2.3 From 986c7297e71d926afa584c6de293794a49f69adf Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 20:57:51 +0100 Subject: OPML import plus tolérant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plus correction bug checkUrl() --- app/views/index/logs.phtml | 2 +- lib/lib_rss.php | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml index 5a0b03b98..178ff8ad3 100644 --- a/app/views/index/logs.phtml +++ b/app/views/index/logs.phtml @@ -14,7 +14,7 @@ logsPaginator->render ('logs_pagination.phtml', 'page'); ?> -
    date ())); ?>info (), ENT_NOQUOTES, 'UTF-8'); ?>
    +
    date ())); ?>info (), ENT_NOQUOTES, 'UTF-8'); ?>
    logsPaginator->render ('logs_pagination.phtml','page'); ?> diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 22e50a424..ae140827c 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -19,13 +19,13 @@ function checkUrl($url) { if (empty ($url)) { return ''; } - if (!preg_match ('#^https?://#i', $value)) { + if (!preg_match ('#^https?://#i', $url)) { $url = 'http://' . $url; } if (filter_var($url, FILTER_VALIDATE_URL) || - (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && //PHP bug #51192 - ($value === filter_var($value, FILTER_SANITIZE_URL)))) { - return url; + (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($url, '-') > 0) && //PHP bug #51192 + ($url === filter_var($url, FILTER_SANITIZE_URL)))) { + return $url; } else { return false; } @@ -113,7 +113,14 @@ function html_only_entity_decode($text) { function opml_import ($xml) { $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 - $opml = simplexml_load_string ($xml); + + $dom = new DOMDocument(); + $dom->recover = true; + $dom->strictErrorChecking = false; + $dom->loadXML($xml); + $this->encoding = 'UTF-8'; + + $opml = simplexml_import_dom($dom); if (!$opml) { throw new OpmlException (); -- cgit v1.2.3 From c1da0f731eb2b9b7b96ae8eaaa1f4e1ae4871d46 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 2 Dec 2013 21:01:10 +0100 Subject: OPML : typo --- lib/lib_rss.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index ae140827c..8d4cecf44 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -118,7 +118,7 @@ function opml_import ($xml) { $dom->recover = true; $dom->strictErrorChecking = false; $dom->loadXML($xml); - $this->encoding = 'UTF-8'; + $dom->encoding = 'UTF-8'; $opml = simplexml_import_dom($dom); -- cgit v1.2.3 From e45357a91b9aa47d5b7ead14c174dc7c98ab9926 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 4 Dec 2013 20:48:53 +0100 Subject: Support contrôlé de iframe, audio, video MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Et filtrage de object, embed https://github.com/marienfressinaud/FreshRSS/issues/188 On ajoute un paramètre preload="none" à audio et video, ainsi qu'un paramètre sandbox="allow-scripts allow-same-origin" aux iframe. On interdit les paramètres autoplay et seamless de audio et video. Ré-écriture des URLS de l'attribut poster de video, ainsi que de l'attribut src de iframe. Suite de https://github.com/marienfressinaud/FreshRSS/issues/267 Au passage, filtrage du vieil élément PLAINTEXT. Modifications dans SimplePie. --- app/models/Feed.php | 16 +++++++---- lib/SimplePie/SimplePie/Sanitize.php | 53 +++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/app/models/Feed.php b/app/models/Feed.php index 555759c9a..88833c706 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -204,15 +204,15 @@ class Feed extends Model { $feed->set_cache_location (CACHE_PATH); $feed->set_cache_duration(1500); $feed->strip_htmltags (array ( - 'base', 'blink', 'body', 'doctype', + 'base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'input', 'marquee', 'meta', 'noscript', - 'param', 'script', 'style' + 'object', 'param', 'plaintext', 'script', 'style', )); $feed->strip_attributes(array_merge($feed->strip_attributes, array( - 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', + 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', - 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange'))); + 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); $feed->set_url_replacements(array( 'a' => 'href', 'area' => 'href', @@ -220,6 +220,7 @@ class Feed extends Model { 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', + 'iframe' => 'src', 'img' => array( 'longdesc', 'src' @@ -229,7 +230,10 @@ class Feed extends Model { 'q' => 'cite', 'source' => 'src', 'track' => 'src', - 'video' => 'src', + 'video' => array( + 'poster', + 'src', + ), )); $feed->init (); @@ -581,7 +585,7 @@ class HelperFeed { $myFeed = new Feed (isset($dao['url']) ? $dao['url'] : '', false); $myFeed->_category ($catID === null ? $dao['category'] : $catID); $myFeed->_name ($dao['name']); - $myFeed->_website ($dao['website']); + $myFeed->_website ($dao['website'], false); $myFeed->_description (isset($dao['description']) ? $dao['description'] : ''); $myFeed->_lastUpdate (isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0); $myFeed->_priority ($dao['priority']); diff --git a/lib/SimplePie/SimplePie/Sanitize.php b/lib/SimplePie/SimplePie/Sanitize.php index 83a274ced..0974c150d 100644 --- a/lib/SimplePie/SimplePie/Sanitize.php +++ b/lib/SimplePie/SimplePie/Sanitize.php @@ -62,6 +62,7 @@ class SimplePie_Sanitize var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); var $encode_instead_of_strip = false; var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + var $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); //FreshRSS var $strip_comments = false; var $output_encoding = 'UTF-8'; var $enable_cache = true; @@ -179,6 +180,25 @@ class SimplePie_Sanitize } } + public function add_attributes($attribs = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none'))) + { + if ($attribs) + { + if (is_array($attribs)) + { + $this->add_attributes = $attribs; + } + else + { + $this->add_attributes = explode(',', $attribs); + } + } + else + { + $this->add_attributes = false; + } + } + public function strip_comments($strip = false) { $this->strip_comments = (bool) $strip; @@ -255,10 +275,11 @@ class SimplePie_Sanitize $document->loadHTML($data); restore_error_handler(); + $xpath = new DOMXPath($document); //FreshRSS + // Strip comments if ($this->strip_comments) { - $xpath = new DOMXPath($document); $comments = $xpath->query('//comment()'); foreach ($comments as $comment) @@ -274,7 +295,7 @@ class SimplePie_Sanitize { foreach ($this->strip_htmltags as $tag) { - $this->strip_tag($tag, $document, $type); + $this->strip_tag($tag, $document, $xpath, $type); } } @@ -282,7 +303,15 @@ class SimplePie_Sanitize { foreach ($this->strip_attributes as $attrib) { - $this->strip_attr($attrib, $document); + $this->strip_attr($attrib, $xpath); + } + } + + if ($this->add_attributes) + { + foreach ($this->add_attributes as $tag => $valuePairs) + { + $this->add_attr($tag, $valuePairs, $document); } } @@ -452,9 +481,8 @@ class SimplePie_Sanitize } } - protected function strip_tag($tag, $document, $type) + protected function strip_tag($tag, $document, $xpath, $type) { - $xpath = new DOMXPath($document); $elements = $xpath->query('body//' . $tag); if ($this->encode_instead_of_strip) { @@ -537,9 +565,8 @@ class SimplePie_Sanitize } } - protected function strip_attr($attrib, $document) + protected function strip_attr($attrib, $xpath) { - $xpath = new DOMXPath($document); $elements = $xpath->query('//*[@' . $attrib . ']'); foreach ($elements as $element) @@ -547,4 +574,16 @@ class SimplePie_Sanitize $element->removeAttribute($attrib); } } + + protected function add_attr($tag, $valuePairs, $document) + { + $elements = $document->getElementsByTagName($tag); + foreach ($elements as $element) + { + foreach ($valuePairs as $attrib => $value) + { + $element->setAttribute($attrib, $value); + } + } + } } -- cgit v1.2.3 From be3b07a374c42a7d424b6ae12fd33c70c00c91ff Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 4 Dec 2013 21:20:15 +0100 Subject: Permet les protocoles relatifs pour HTTP/HTTPS automatique MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Une vidéo telle fonctionne maintenant sur un FreshRSS hébergé en HTTPS. Cela pourrait sûrement être écrit de manière plus propre quelque part dans SimplePie_IRI::absolutize. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/188 --- lib/SimplePie/SimplePie/Misc.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/SimplePie/SimplePie/Misc.php b/lib/SimplePie/SimplePie/Misc.php index 621f2c062..347520303 100644 --- a/lib/SimplePie/SimplePie/Misc.php +++ b/lib/SimplePie/SimplePie/Misc.php @@ -79,6 +79,10 @@ class SimplePie_Misc public static function absolutize_url($relative, $base) { + if (substr($relative, 0, 2) === '//') //FreshRSS: disable absolutize_url for "//www.example.net" which will pick HTTP or HTTPS automatically + { + return $relative; + } $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); if ($iri === false) { -- cgit v1.2.3 From 25fa654529390dfc989898beb522d63cae4aed7d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 5 Dec 2013 19:18:28 +0100 Subject: Resource-priorities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prépare http://www.w3.org/TR/resource-priorities/ https://github.com/marienfressinaud/FreshRSS/issues/316 https://github.com/marienfressinaud/FreshRSS/issues/313 Continue https://github.com/marienfressinaud/FreshRSS/issues/188 https://github.com/marienfressinaud/FreshRSS/commit/e45357a91b9aa47d5b7ead14c174dc7c98ab9926 --- app/models/Feed.php | 6 ++++++ lib/SimplePie/SimplePie.php | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'lib') diff --git a/app/models/Feed.php b/app/models/Feed.php index 88833c706..1454f44d5 100644 --- a/app/models/Feed.php +++ b/app/models/Feed.php @@ -213,6 +213,12 @@ class Feed extends Model { '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', diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 9e532023a..d20ab5430 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -601,6 +601,13 @@ class SimplePie */ public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + /** + * @var array Stores the default attributes to add to differet tags by add_attributes(). + * @see SimplePie::add_attributes() + * @access private + */ + public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); //FreshRSS + /** * @var array Stores the default tags to be stripped by strip_htmltags(). * @see SimplePie::strip_htmltags() @@ -1073,6 +1080,7 @@ class SimplePie $this->strip_comments(false); $this->strip_htmltags(false); $this->strip_attributes(false); + $this->add_attributes(false); $this->set_image_handler(false); } } @@ -1119,6 +1127,15 @@ class SimplePie $this->sanitize->strip_attributes($attribs); } + public function add_attributes($attribs = '') + { + if ($attribs === '') + { + $attribs = $this->add_attributes; + } + $this->sanitize->add_attributes($attribs); + } + /** * Set the output encoding * -- cgit v1.2.3 From 97a7d7b0b2c25d573a8dac72e6183abf640c8fe4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 12 Dec 2013 19:30:19 +0100 Subject: Microtime : récupération de toutes les microsecondes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microtime(true) dépend de la précision de PHP définie dans php.ini, et par défaut, nous perdons les deux dernières décimales des microsecondes. Du coup, sur une machine très rapide, cela aurait pu poser des problèmes d'identifiants dupliqués. Patch utilisant gettimeofday() à la place. Au passage, reste en string tout le long et plus besoin de faire la conversion CAST(? * 1000000 AS SIGNED INTEGER) côté base de données. https://github.com/marienfressinaud/FreshRSS/issues/202 --- app/controllers/feedController.php | 4 ++-- app/models/Entry.php | 2 +- lib/lib_rss.php | 12 +++++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index 02647e10f..a38614b3d 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -106,7 +106,7 @@ class feedController extends ActionController { $feed->keepHistory ()) { $values = $entry->toArray (); $values['id_feed'] = $feed->id (); - $values['id'] = min(time(), $entry->date (true)) . '.' . rand(0, 999999); + $values['id'] = min(time(), $entry->date (true)) . uSecString(); $values['is_read'] = $is_read; $entryDAO->addEntry ($values); } @@ -229,7 +229,7 @@ class feedController extends ActionController { $feed->keepHistory ())) { $values = $entry->toArray (); //Use declared date at first import, otherwise use discovery date - $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . '.' . rand(0, 999999) : microtime(true); + $values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString(); $values['is_read'] = $is_read; $entryDAO->addEntry ($values); } diff --git a/app/models/Entry.php b/app/models/Entry.php index 33d0c66bb..103a90706 100755 --- a/app/models/Entry.php +++ b/app/models/Entry.php @@ -196,7 +196,7 @@ class Entry extends Model { class EntryDAO extends Model_pdo { public function addEntry ($valuesTmp) { $sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, content_bin, link, date, is_read, is_favorite, id_feed, tags) ' - . 'VALUES(CAST(? * 1000000 AS SIGNED INTEGER), ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)'; + . 'VALUES(?, ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)'; $stm = $this->bd->prepare ($sql); $values = array ( diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 8d4cecf44..4f5b90b61 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -255,6 +255,16 @@ function lazyimg($content) { ); } +function uTimeString() { + $t = @gettimeofday(); + return $t['sec'] . str_pad($t['usec'], 6, '0'); +} + +function uSecString() { + $t = @gettimeofday(); + return str_pad($t['usec'], 6, '0'); +} + function invalidateHttpCache() { - file_put_contents(DATA_PATH . '/touch.txt', microtime(true)); + file_put_contents(DATA_PATH . '/touch.txt', uTimeString()); } -- cgit v1.2.3 From 878e96202e8a22e4857b98e29b0a1fce68eccbc9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 15 Dec 2013 03:30:24 +0100 Subject: Grosse refactorisation pour permettre le chargement automatique des classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C'est parti de changements pour https://github.com/marienfressinaud/FreshRSS/issues/255 et finalement j'ai continué la refactorisation... Ajout de préfixes FreshRSS_ et Minz_ sur le modèle de SimplePie_. Toutes les classes sont maintenant en chargement automatique (devrait améliorer les performances en évitant de charger plein de classes inutilisées, et faciliter la maintenance). Suppression de set_include_path(). Si souhaité, certaines classes de Minz pourraient être déplacées dans un sous-répertoire, par exemple les exceptions. Tests et relecture nécessaires. --- app/App_FrontController.php | 84 ---- app/Exceptions/BadUrlException.php | 6 + app/Exceptions/EntriesGetterException.php | 7 + app/Exceptions/FeedException.php | 6 + app/Exceptions/OpmlException.php | 6 + app/FreshRSS.php | 58 +++ app/Models/CategoryDAO.php | 252 +++++++++++ app/Models/Configuration.php | 326 ++++++++++++++ app/Models/ConfigurationDAO.php | 156 +++++++ app/Models/EntryDAO.php | 425 ++++++++++++++++++ app/Models/FeedDAO.php | 341 +++++++++++++++ app/Models/Log.php | 26 ++ app/Models/LogDAO.php | 20 + app/Models/Themes.php | 88 ++++ app/controllers/configureController.php | 234 +++++----- app/controllers/entryController.php | 44 +- app/controllers/errorController.php | 8 +- app/controllers/feedController.php | 142 +++--- app/controllers/indexController.php | 78 ++-- app/controllers/javascriptController.php | 4 +- app/layout/aside_configure.phtml | 14 +- app/layout/aside_feed.phtml | 28 +- app/layout/aside_flux.phtml | 30 +- app/layout/header.phtml | 38 +- app/layout/layout.phtml | 18 +- app/layout/nav_entries.phtml | 6 +- app/layout/nav_menu.phtml | 68 +-- app/models/Category.php | 260 +---------- app/models/Days.php | 2 +- app/models/Entry.php | 438 +------------------ app/models/Exception/EntriesGetterException.php | 7 - app/models/Exception/FeedException.php | 19 - app/models/Feed.php | 362 +--------------- app/models/Log_Model.php | 46 -- app/models/RSSConfiguration.php | 480 --------------------- app/models/RSSThemes.php | 88 ---- app/views/configure/categorize.phtml | 22 +- app/views/configure/display.phtml | 106 ++--- app/views/configure/feed.phtml | 54 +-- app/views/configure/importExport.phtml | 18 +- app/views/configure/sharing.phtml | 30 +- app/views/configure/shortcut.phtml | 30 +- app/views/entry/bookmark.phtml | 16 +- app/views/entry/read.phtml | 16 +- app/views/error/index.phtml | 4 +- app/views/helpers/javascript_vars.phtml | 20 +- app/views/helpers/logs_pagination.phtml | 16 +- app/views/helpers/pagination.phtml | 18 +- app/views/helpers/view/global_view.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 53 ++- app/views/helpers/view/reader_view.phtml | 4 +- app/views/helpers/view/rss_view.phtml | 6 +- app/views/index/about.phtml | 24 +- app/views/index/index.phtml | 10 +- app/views/index/logs.phtml | 8 +- app/views/javascript/actualize.phtml | 4 +- lib/Minz/ActionException.php | 9 + lib/Minz/BadConfigurationException.php | 9 + lib/Minz/Cache.php | 116 +++++ .../ControllerNotActionControllerException.php | 9 + lib/Minz/ControllerNotExistException.php | 9 + lib/Minz/CurrentPagePaginationException.php | 8 + lib/Minz/Exception.php | 16 + lib/Minz/FileNotExistException.php | 8 + lib/Minz/Log.php | 94 ++++ lib/Minz/ModelArray.php | 122 ++++++ lib/Minz/ModelPdo.php | 111 +++++ lib/Minz/ModelTxt.php | 84 ++++ lib/Minz/PDOConnectionException.php | 9 + lib/Minz/PermissionDeniedException.php | 8 + lib/Minz/RouteNotFoundException.php | 16 + lib/SimplePie_autoloader.php | 86 ---- lib/lib_rss.php | 45 +- lib/minz/ActionController.php | 4 +- lib/minz/Configuration.php | 60 +-- lib/minz/Dispatcher.php | 54 +-- lib/minz/Error.php | 40 +- lib/minz/FrontController.php | 80 ++-- lib/minz/Helper.php | 2 +- lib/minz/Minz_Cache.php | 116 ----- lib/minz/Minz_Log.php | 94 ---- lib/minz/Model.php | 2 +- lib/minz/Paginator.php | 2 +- lib/minz/Request.php | 16 +- lib/minz/Response.php | 2 +- lib/minz/Router.php | 34 +- lib/minz/Session.php | 6 +- lib/minz/Translate.php | 6 +- lib/minz/Url.php | 18 +- lib/minz/View.php | 10 +- lib/minz/dao/Model_array.php | 122 ------ lib/minz/dao/Model_pdo.php | 111 ----- lib/minz/dao/Model_txt.php | 84 ---- lib/minz/exceptions/MinzException.php | 94 ---- public/index.php | 12 +- 95 files changed, 3134 insertions(+), 3270 deletions(-) delete mode 100644 app/App_FrontController.php create mode 100644 app/Exceptions/BadUrlException.php create mode 100644 app/Exceptions/EntriesGetterException.php create mode 100644 app/Exceptions/FeedException.php create mode 100644 app/Exceptions/OpmlException.php create mode 100644 app/FreshRSS.php create mode 100644 app/Models/CategoryDAO.php create mode 100644 app/Models/Configuration.php create mode 100644 app/Models/ConfigurationDAO.php create mode 100644 app/Models/EntryDAO.php create mode 100644 app/Models/FeedDAO.php create mode 100644 app/Models/Log.php create mode 100644 app/Models/LogDAO.php create mode 100644 app/Models/Themes.php delete mode 100644 app/models/Exception/EntriesGetterException.php delete mode 100644 app/models/Exception/FeedException.php delete mode 100644 app/models/Log_Model.php delete mode 100755 app/models/RSSConfiguration.php delete mode 100644 app/models/RSSThemes.php create mode 100644 lib/Minz/ActionException.php create mode 100644 lib/Minz/BadConfigurationException.php create mode 100644 lib/Minz/Cache.php create mode 100644 lib/Minz/ControllerNotActionControllerException.php create mode 100644 lib/Minz/ControllerNotExistException.php create mode 100644 lib/Minz/CurrentPagePaginationException.php create mode 100644 lib/Minz/Exception.php create mode 100644 lib/Minz/FileNotExistException.php create mode 100644 lib/Minz/Log.php create mode 100644 lib/Minz/ModelArray.php create mode 100644 lib/Minz/ModelPdo.php create mode 100644 lib/Minz/ModelTxt.php create mode 100644 lib/Minz/PDOConnectionException.php create mode 100644 lib/Minz/PermissionDeniedException.php create mode 100644 lib/Minz/RouteNotFoundException.php delete mode 100644 lib/SimplePie_autoloader.php delete mode 100644 lib/minz/Minz_Cache.php delete mode 100644 lib/minz/Minz_Log.php delete mode 100755 lib/minz/dao/Model_array.php delete mode 100755 lib/minz/dao/Model_pdo.php delete mode 100755 lib/minz/dao/Model_txt.php delete mode 100644 lib/minz/exceptions/MinzException.php (limited to 'lib') diff --git a/app/App_FrontController.php b/app/App_FrontController.php deleted file mode 100644 index 0721dba45..000000000 --- a/app/App_FrontController.php +++ /dev/null @@ -1,84 +0,0 @@ - -*/ -require ('FrontController.php'); - -class App_FrontController extends FrontController { - public function init () { - $this->loadLibs (); - $this->loadModels (); - - Session::init (); - Translate::init (); - - $this->loadParamsView (); - $this->loadStylesAndScripts (); - $this->loadNotifications (); - } - - private function loadLibs () { - require (LIB_PATH . '/lib_rss.php'); - require (LIB_PATH . '/SimplePie_autoloader.php'); - } - - private function loadModels () { - include (APP_PATH . '/models/Exception/FeedException.php'); - include (APP_PATH . '/models/Exception/EntriesGetterException.php'); - include (APP_PATH . '/models/RSSConfiguration.php'); - include (APP_PATH . '/models/RSSThemes.php'); - include (APP_PATH . '/models/Days.php'); - include (APP_PATH . '/models/Category.php'); - include (APP_PATH . '/models/Feed.php'); - include (APP_PATH . '/models/Entry.php'); - include (APP_PATH . '/models/Log_Model.php'); - } - - private function loadParamsView () { - try { - $this->conf = Session::param ('conf', new RSSConfiguration ()); - } catch(MinzException $e) { - // Permission denied or conf file does not exist - // it's critical! - print $e->getMessage(); - exit(); - } - - View::_param ('conf', $this->conf); - Session::_param ('language', $this->conf->language ()); - - $output = Request::param ('output'); - if(!$output) { - $output = $this->conf->viewMode(); - Request::_param ('output', $output); - } - } - - private function loadStylesAndScripts () { - $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))); - } - } - - if (login_is_conf ($this->conf)) { - View::appendScript ('https://login.persona.org/include.js'); - } - $includeLazyLoad = $this->conf->lazyload () === 'yes' && ($this->conf->displayPosts () === 'yes' || Request::param ('output') === 'reader'); - View::appendScript (Url::display ('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js')), false, !$includeLazyLoad, !$includeLazyLoad); - if ($includeLazyLoad) { - 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'))); - } - - private function loadNotifications () { - $notif = Session::param ('notification'); - if ($notif) { - View::_param ('notification', $notif); - Session::_param ('notification'); - } - } -} diff --git a/app/Exceptions/BadUrlException.php b/app/Exceptions/BadUrlException.php new file mode 100644 index 000000000..7d1fe110e --- /dev/null +++ b/app/Exceptions/BadUrlException.php @@ -0,0 +1,6 @@ +loadParamsView (); + $this->loadStylesAndScripts (); + $this->loadNotifications (); + } + + private function loadParamsView () { + try { + $this->conf = Minz_Session::param ('conf', new FreshRSS_Configuration ()); + } catch (Minz_Exception $e) { + // Permission denied or conf file does not exist + // it's critical! + print $e->getMessage(); + exit(); + } + + Minz_View::_param ('conf', $this->conf); + Minz_Session::_param ('language', $this->conf->language ()); + + $output = Minz_Request::param ('output'); + if(!$output) { + $output = $this->conf->viewMode(); + Minz_Request::_param ('output', $output); + } + } + + private function loadStylesAndScripts () { + $theme = FreshRSS_Themes::get_infos($this->conf->theme()); + if ($theme) { + foreach($theme["files"] as $file) { + Minz_View::appendStyle (Minz_Url::display ('/themes/' . $theme['path'] . '/' . $file . '?' . @filemtime(PUBLIC_PATH . '/themes/' . $theme['path'] . '/' . $file))); + } + } + + if (login_is_conf ($this->conf)) { + Minz_View::appendScript ('https://login.persona.org/include.js'); + } + $includeLazyLoad = $this->conf->lazyload () === 'yes' && ($this->conf->displayPosts () === 'yes' || Minz_Request::param ('output') === 'reader'); + Minz_View::appendScript (Minz_Url::display ('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js')), false, !$includeLazyLoad, !$includeLazyLoad); + if ($includeLazyLoad) { + Minz_View::appendScript (Minz_Url::display ('/scripts/jquery.lazyload.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.lazyload.min.js'))); + } + Minz_View::appendScript (Minz_Url::display ('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); + } + + private function loadNotifications () { + $notif = Minz_Session::param ('notification'); + if ($notif) { + Minz_View::_param ('notification', $notif); + Minz_Session::_param ('notification'); + } + } +} diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php new file mode 100644 index 000000000..793e593c3 --- /dev/null +++ b/app/Models/CategoryDAO.php @@ -0,0 +1,252 @@ +prefix . 'category` (name, color) VALUES(?, ?)'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + substr($valuesTmp['name'], 0, 255), + substr($valuesTmp['color'], 0, 7), + ); + + if ($stm && $stm->execute ($values)) { + return $this->bd->lastInsertId(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function updateCategory ($id, $valuesTmp) { + $sql = 'UPDATE `' . $this->prefix . 'category` SET name=?, color=? WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + $valuesTmp['name'], + $valuesTmp['color'], + $id + ); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function deleteCategory ($id) { + $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function searchById ($id) { + $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $cat = HelperCategory::daoToCategory ($res); + + if (isset ($cat[0])) { + return $cat[0]; + } else { + return false; + } + } + public function searchByName ($name) { + $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE name=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($name); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $cat = HelperCategory::daoToCategory ($res); + + if (isset ($cat[0])) { + return $cat[0]; + } else { + return false; + } + } + + public function listCategories ($prePopulateFeeds = true, $details = false) { + 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 ') + . 'FROM `' . $this->prefix . 'category` c ' + . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category = c.id ' + . 'GROUP BY f.id ' + . 'ORDER BY c.name, f.name'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + return HelperCategory::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)); + } + } + + public function getDefault () { + $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=1'; + $stm = $this->bd->prepare ($sql); + + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $cat = HelperCategory::daoToCategory ($res); + + if (isset ($cat[0])) { + return $cat[0]; + } else { + return false; + } + } + public function checkDefault () { + $def_cat = $this->searchById (1); + + if ($def_cat === false) { + $cat = new FreshRSS_Category (Minz_Translate::t ('default_category')); + $cat->_id (1); + + $values = array ( + 'id' => $cat->id (), + 'name' => $cat->name (), + 'color' => $cat->color () + ); + + $this->addCategory ($values); + } + } + + public function count () { + $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'category`'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + + return $res[0]['count']; + } + + public function countFeed ($id) { + $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'feed` WHERE category=?'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + + return $res[0]['count']; + } + + public function countNotRead ($id) { + $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE category=? AND e.is_read=0'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + + return $res[0]['count']; + } +} + +class HelperCategory { + public static function findFeed($categories, $feed_id) { + foreach ($categories as $category) { + foreach ($category->feeds () as $feed) { + if ($feed->id () === $feed_id) { + return $feed; + } + } + } + return null; + } + + public static function CountUnreads($categories, $minPriority = 0) { + $n = 0; + foreach ($categories as $category) { + foreach ($category->feeds () as $feed) { + if ($feed->priority () >= $minPriority) { + $n += $feed->nbNotRead(); + } + } + } + return $n; + } + + public static function daoToCategoryPrepopulated ($listDAO) { + $list = array (); + + if (!is_array ($listDAO)) { + $listDAO = array ($listDAO); + } + + $previousLine = null; + $feedsDao = array(); + foreach ($listDAO as $line) { + if ($previousLine['c_id'] != null && $line['c_id'] !== $previousLine['c_id']) { + // End of the current category, we add it to the $list + $cat = new FreshRSS_Category ( + $previousLine['c_name'], + isset($previousLine['c_color']) ? $previousLine['c_color'] : '', + HelperFeed::daoToFeed ($feedsDao, $previousLine['c_id']) + ); + $cat->_id ($previousLine['c_id']); + $list[$previousLine['c_id']] = $cat; + + $feedsDao = array(); //Prepare for next category + } + + $previousLine = $line; + $feedsDao[] = $line; + } + + // add the last category + if ($previousLine != null) { + $cat = new FreshRSS_Category ( + $previousLine['c_name'], + isset($previousLine['c_color']) ? $previousLine['c_color'] : '', + HelperFeed::daoToFeed ($feedsDao, $previousLine['c_id']) + ); + $cat->_id ($previousLine['c_id']); + $list[$previousLine['c_id']] = $cat; + } + + return $list; + } + + public static function daoToCategory ($listDAO) { + $list = array (); + + if (!is_array ($listDAO)) { + $listDAO = array ($listDAO); + } + + foreach ($listDAO as $key => $dao) { + $cat = new FreshRSS_Category ( + $dao['name'], + $dao['color'] + ); + $cat->_id ($dao['id']); + $list[$key] = $cat; + } + + return $list; + } +} diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php new file mode 100644 index 000000000..7ef76b522 --- /dev/null +++ b/app/Models/Configuration.php @@ -0,0 +1,326 @@ + 'English', + 'fr' => 'Français', + ); + private $language; + private $posts_per_page; + private $view_mode; + private $default_view; + private $display_posts; + private $onread_jump_next; + private $lazyload; + private $sort_order; + private $old_entries; + private $shortcuts = array (); + private $mail_login = ''; + private $mark_when = array (); + private $sharing = array (); + private $theme; + private $anon_access; + private $token; + private $auto_load_more; + private $topline_read; + private $topline_favorite; + private $topline_date; + private $topline_link; + private $bottomline_read; + private $bottomline_favorite; + private $bottomline_sharing; + private $bottomline_tags; + private $bottomline_date; + private $bottomline_link; + + public function __construct () { + $confDAO = new FreshRSS_ConfigurationDAO (); + $this->_language ($confDAO->language); + $this->_postsPerPage ($confDAO->posts_per_page); + $this->_viewMode ($confDAO->view_mode); + $this->_defaultView ($confDAO->default_view); + $this->_displayPosts ($confDAO->display_posts); + $this->_onread_jump_next ($confDAO->onread_jump_next); + $this->_lazyload ($confDAO->lazyload); + $this->_sortOrder ($confDAO->sort_order); + $this->_oldEntries ($confDAO->old_entries); + $this->_shortcuts ($confDAO->shortcuts); + $this->_mailLogin ($confDAO->mail_login); + $this->_markWhen ($confDAO->mark_when); + $this->_sharing ($confDAO->sharing); + $this->_theme ($confDAO->theme); + FreshRSS_Themes::setThemeId ($confDAO->theme); + $this->_anonAccess ($confDAO->anon_access); + $this->_token ($confDAO->token); + $this->_autoLoadMore ($confDAO->auto_load_more); + $this->_topline_read ($confDAO->topline_read); + $this->_topline_favorite ($confDAO->topline_favorite); + $this->_topline_date ($confDAO->topline_date); + $this->_topline_link ($confDAO->topline_link); + $this->_bottomline_read ($confDAO->bottomline_read); + $this->_bottomline_favorite ($confDAO->bottomline_favorite); + $this->_bottomline_sharing ($confDAO->bottomline_sharing); + $this->_bottomline_tags ($confDAO->bottomline_tags); + $this->_bottomline_date ($confDAO->bottomline_date); + $this->_bottomline_link ($confDAO->bottomline_link); + } + + public function availableLanguages () { + return $this->available_languages; + } + public function language () { + return $this->language; + } + public function postsPerPage () { + return $this->posts_per_page; + } + public function viewMode () { + return $this->view_mode; + } + public function defaultView () { + return $this->default_view; + } + public function displayPosts () { + return $this->display_posts; + } + public function onread_jump_next () { + return $this->onread_jump_next; + } + public function lazyload () { + return $this->lazyload; + } + public function sortOrder () { + return $this->sort_order; + } + public function oldEntries () { + return $this->old_entries; + } + public function shortcuts () { + return $this->shortcuts; + } + public function mailLogin () { + return $this->mail_login; + } + public function markWhen () { + return $this->mark_when; + } + public function markWhenArticle () { + return $this->mark_when['article']; + } + public function markWhenSite () { + return $this->mark_when['site']; + } + public function markWhenScroll () { + return $this->mark_when['scroll']; + } + public function markUponReception () { + return $this->mark_when['reception']; + } + public function sharing ($key = false) { + if ($key === false) { + return $this->sharing; + } elseif (isset ($this->sharing[$key])) { + return $this->sharing[$key]; + } + return false; + } + public function theme () { + return $this->theme; + } + public function anonAccess () { + return $this->anon_access; + } + public function token () { + return $this->token; + } + public function autoLoadMore () { + return $this->auto_load_more; + } + public function toplineRead () { + return $this->topline_read; + } + public function toplineFavorite () { + return $this->topline_favorite; + } + public function toplineDate () { + return $this->topline_date; + } + public function toplineLink () { + return $this->topline_link; + } + public function bottomlineRead () { + return $this->bottomline_read; + } + public function bottomlineFavorite () { + return $this->bottomline_favorite; + } + public function bottomlineSharing () { + return $this->bottomline_sharing; + } + public function bottomlineTags () { + return $this->bottomline_tags; + } + public function bottomlineDate () { + return $this->bottomline_date; + } + public function bottomlineLink () { + return $this->bottomline_link; + } + + public function _language ($value) { + if (!isset ($this->available_languages[$value])) { + $value = 'en'; + } + $this->language = $value; + } + public function _postsPerPage ($value) { + $value = intval($value); + $this->posts_per_page = $value > 0 ? $value : 10; + } + public function _viewMode ($value) { + if ($value == 'global' || $value == 'reader') { + $this->view_mode = $value; + } else { + $this->view_mode = 'normal'; + } + } + public function _defaultView ($value) { + if ($value == 'not_read') { + $this->default_view = 'not_read'; + } else { + $this->default_view = 'all'; + } + } + public function _displayPosts ($value) { + if ($value == 'yes') { + $this->display_posts = 'yes'; + } else { + $this->display_posts = 'no'; + } + } + public function _onread_jump_next ($value) { + if ($value == 'no') { + $this->onread_jump_next = 'no'; + } else { + $this->onread_jump_next = 'yes'; + } + } + public function _lazyload ($value) { + if ($value == 'no') { + $this->lazyload = 'no'; + } else { + $this->lazyload = 'yes'; + } + } + public function _sortOrder ($value) { + $this->sort_order = $value === 'ASC' ? 'ASC' : 'DESC'; + } + public function _oldEntries ($value) { + if (ctype_digit ($value) && $value > 0) { + $this->old_entries = $value; + } else { + $this->old_entries = 3; + } + } + public function _shortcuts ($values) { + foreach ($values as $key => $value) { + $this->shortcuts[$key] = $value; + } + } + public function _mailLogin ($value) { + if (filter_var ($value, FILTER_VALIDATE_EMAIL)) { + $this->mail_login = $value; + } elseif ($value == false) { + $this->mail_login = false; + } + } + public function _markWhen ($values) { + if(!isset($values['article'])) { + $values['article'] = 'yes'; + } + if(!isset($values['site'])) { + $values['site'] = 'yes'; + } + if(!isset($values['scroll'])) { + $values['scroll'] = 'yes'; + } + if(!isset($values['reception'])) { + $values['reception'] = 'no'; + } + + $this->mark_when['article'] = $values['article']; + $this->mark_when['site'] = $values['site']; + $this->mark_when['scroll'] = $values['scroll']; + $this->mark_when['reception'] = $values['reception']; + } + public function _sharing ($values) { + $are_url = array ('shaarli', 'poche', 'diaspora'); + foreach ($values as $key => $value) { + if (in_array($key, $are_url)) { + $is_url = ( + filter_var ($value, FILTER_VALIDATE_URL) || + (version_compare(PHP_VERSION, '5.3.3', '<') && + (strpos($value, '-') > 0) && + ($value === filter_var($value, FILTER_SANITIZE_URL))) + ); //PHP bug #51192 + + if (!$is_url) { + $value = ''; + } + } elseif(!is_bool ($value)) { + $value = true; + } + + $this->sharing[$key] = $value; + } + } + public function _theme ($value) { + $this->theme = $value; + } + public function _anonAccess ($value) { + if ($value == 'yes') { + $this->anon_access = 'yes'; + } else { + $this->anon_access = 'no'; + } + } + public function _token ($value) { + $this->token = $value; + } + public function _autoLoadMore ($value) { + if ($value == 'yes') { + $this->auto_load_more = 'yes'; + } else { + $this->auto_load_more = 'no'; + } + } + public function _topline_read ($value) { + $this->topline_read = $value === 'yes'; + } + public function _topline_favorite ($value) { + $this->topline_favorite = $value === 'yes'; + } + public function _topline_date ($value) { + $this->topline_date = $value === 'yes'; + } + public function _topline_link ($value) { + $this->topline_link = $value === 'yes'; + } + public function _bottomline_read ($value) { + $this->bottomline_read = $value === 'yes'; + } + public function _bottomline_favorite ($value) { + $this->bottomline_favorite = $value === 'yes'; + } + public function _bottomline_sharing ($value) { + $this->bottomline_sharing = $value === 'yes'; + } + public function _bottomline_tags ($value) { + $this->bottomline_tags = $value === 'yes'; + } + public function _bottomline_date ($value) { + $this->bottomline_date = $value === 'yes'; + } + public function _bottomline_link ($value) { + $this->bottomline_link = $value === 'yes'; + } +} diff --git a/app/Models/ConfigurationDAO.php b/app/Models/ConfigurationDAO.php new file mode 100644 index 000000000..fec58d234 --- /dev/null +++ b/app/Models/ConfigurationDAO.php @@ -0,0 +1,156 @@ + 'r', + 'mark_favorite' => 'f', + 'go_website' => 'space', + 'next_entry' => 'j', + 'prev_entry' => 'k', + 'collapse_entry' => 'c', + 'load_more' => 'm' + ); + public $mail_login = ''; + public $mark_when = array ( + 'article' => 'yes', + 'site' => 'yes', + 'scroll' => 'no', + 'reception' => 'no' + ); + public $sharing = array ( + 'shaarli' => '', + 'poche' => '', + 'diaspora' => '', + 'twitter' => true, + 'g+' => true, + 'facebook' => true, + 'email' => true, + 'print' => true + ); + public $theme = 'default'; + public $anon_access = 'no'; + public $token = ''; + public $auto_load_more = 'no'; + public $topline_read = 'yes'; + public $topline_favorite = 'yes'; + public $topline_date = 'yes'; + public $topline_link = 'yes'; + public $bottomline_read = 'yes'; + public $bottomline_favorite = 'yes'; + public $bottomline_sharing = 'yes'; + public $bottomline_tags = 'yes'; + public $bottomline_date = 'yes'; + public $bottomline_link = 'yes'; + + public function __construct ($nameFile = '') { + if (empty($nameFile)) { + $nameFile = DATA_PATH . '/' . Minz_Configuration::currentUser () . '_user.php'; + } + parent::__construct ($nameFile); + + // TODO : simplifier ce code, une boucle for() devrait suffire ! + if (isset ($this->array['language'])) { + $this->language = $this->array['language']; + } + if (isset ($this->array['posts_per_page'])) { + $this->posts_per_page = $this->array['posts_per_page']; + } + if (isset ($this->array['view_mode'])) { + $this->view_mode = $this->array['view_mode']; + } + if (isset ($this->array['default_view'])) { + $this->default_view = $this->array['default_view']; + } + if (isset ($this->array['display_posts'])) { + $this->display_posts = $this->array['display_posts']; + } + if (isset ($this->array['onread_jump_next'])) { + $this->onread_jump_next = $this->array['onread_jump_next']; + } + if (isset ($this->array['lazyload'])) { + $this->lazyload = $this->array['lazyload']; + } + if (isset ($this->array['sort_order'])) { + $this->sort_order = $this->array['sort_order']; + } + if (isset ($this->array['old_entries'])) { + $this->old_entries = $this->array['old_entries']; + } + if (isset ($this->array['shortcuts'])) { + $this->shortcuts = array_merge ( + $this->shortcuts, $this->array['shortcuts'] + ); + } + if (isset ($this->array['mail_login'])) { + $this->mail_login = $this->array['mail_login']; + } + if (isset ($this->array['mark_when'])) { + $this->mark_when = $this->array['mark_when']; + } + if (isset ($this->array['sharing'])) { + $this->sharing = array_merge ( + $this->sharing, $this->array['sharing'] + ); + } + if (isset ($this->array['theme'])) { + $this->theme = $this->array['theme']; + } + if (isset ($this->array['anon_access'])) { + $this->anon_access = $this->array['anon_access']; + } + if (isset ($this->array['token'])) { + $this->token = $this->array['token']; + } + if (isset ($this->array['auto_load_more'])) { + $this->auto_load_more = $this->array['auto_load_more']; + } + + if (isset ($this->array['topline_read'])) { + $this->topline_read = $this->array['topline_read']; + } + if (isset ($this->array['topline_favorite'])) { + $this->topline_favorite = $this->array['topline_favorite']; + } + if (isset ($this->array['topline_date'])) { + $this->topline_date = $this->array['topline_date']; + } + if (isset ($this->array['topline_link'])) { + $this->topline_link = $this->array['topline_link']; + } + if (isset ($this->array['bottomline_read'])) { + $this->bottomline_read = $this->array['bottomline_read']; + } + if (isset ($this->array['bottomline_favorite'])) { + $this->bottomline_favorite = $this->array['bottomline_favorite']; + } + if (isset ($this->array['bottomline_sharing'])) { + $this->bottomline_sharing = $this->array['bottomline_sharing']; + } + if (isset ($this->array['bottomline_tags'])) { + $this->bottomline_tags = $this->array['bottomline_tags']; + } + if (isset ($this->array['bottomline_date'])) { + $this->bottomline_date = $this->array['bottomline_date']; + } + if (isset ($this->array['bottomline_link'])) { + $this->bottomline_link = $this->array['bottomline_link']; + } + } + + public function update ($values) { + foreach ($values as $key => $value) { + $this->array[$key] = $value; + } + + $this->writeFile($this->array); + invalidateHttpCache(); + } +} diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php new file mode 100644 index 000000000..8c18150b6 --- /dev/null +++ b/app/Models/EntryDAO.php @@ -0,0 +1,425 @@ +prefix . 'entry`(id, guid, title, author, content_bin, link, date, is_read, is_favorite, id_feed, tags) ' + . 'VALUES(?, ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + $valuesTmp['id'], + substr($valuesTmp['guid'], 0, 760), + substr($valuesTmp['title'], 0, 255), + substr($valuesTmp['author'], 0, 255), + $valuesTmp['content'], + substr($valuesTmp['link'], 0, 1023), + $valuesTmp['date'], + $valuesTmp['is_read'], + $valuesTmp['is_favorite'], + $valuesTmp['id_feed'], + substr($valuesTmp['tags'], 0, 1023), + ); + + if ($stm && $stm->execute ($values)) { + return $this->bd->lastInsertId(); + } else { + $info = $stm->errorInfo(); + if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries + Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR); + } /*else { + Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::DEBUG); + }*/ + return false; + } + } + + public function markFavorite ($id, $is_favorite = true) { + $sql = 'UPDATE `' . $this->prefix . 'entry` e ' + . 'SET e.is_favorite = ? ' + . 'WHERE e.id=?'; + $values = array ($is_favorite ? 1 : 0, $id); + $stm = $this->bd->prepare ($sql); + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + public function markRead ($id, $is_read = true) { + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = ?,' + . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' + . 'WHERE e.id=?'; + $values = array ($is_read ? 1 : 0, $id); + $stm = $this->bd->prepare ($sql); + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + public function markReadEntries ($idMax = 0, $favorites = false) { + if ($idMax === 0) { + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' + . 'WHERE e.is_read = 0 AND '; + if ($favorites) { + $sql .= 'e.is_favorite = 1'; + } else { + $sql .= 'f.priority > 0'; + } + $stm = $this->bd->prepare ($sql); + if ($stm && $stm->execute ()) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } else { + $this->bd->beginTransaction (); + + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1 ' + . 'WHERE e.is_read = 0 AND e.id <= ? AND '; + if ($favorites) { + $sql .= 'e.is_favorite = 1'; + } else { + $sql .= 'f.priority > 0'; + } + $values = array ($idMax); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + $affected = $stm->rowCount(); + + if ($affected > 0) { + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' + . 'LEFT OUTER JOIN (' + . 'SELECT e.id_feed, ' + . 'COUNT(*) AS nbUnreads ' + . 'FROM `' . $this->prefix . 'entry` e ' + . 'WHERE e.is_read = 0 ' + . 'GROUP BY e.id_feed' + . ') x ON x.id_feed=f.id ' + . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0)'; + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ())) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + } + + $this->bd->commit (); + return $affected; + } + } + public function markReadCat ($id, $idMax = 0) { + if ($idMax === 0) { + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' + . 'WHERE f.category = ? AND e.is_read = 0'; + $values = array ($id); + $stm = $this->bd->prepare ($sql); + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } else { + $this->bd->beginTransaction (); + + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1 ' + . 'WHERE f.category = ? AND e.is_read = 0 AND e.id <= ?'; + $values = array ($id, $idMax); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + $affected = $stm->rowCount(); + + if ($affected > 0) { + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' + . 'LEFT OUTER JOIN (' + . 'SELECT e.id_feed, ' + . 'COUNT(*) AS nbUnreads ' + . 'FROM `' . $this->prefix . 'entry` e ' + . 'WHERE e.is_read = 0 ' + . 'GROUP BY e.id_feed' + . ') x ON x.id_feed=f.id ' + . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) ' + . 'WHERE f.category = ?'; + $values = array ($id); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + } + + $this->bd->commit (); + return $affected; + } + } + public function markReadFeed ($id, $idMax = 0) { + if ($idMax === 0) { + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' + . 'WHERE f.id=? AND e.is_read = 0'; + $values = array ($id); + $stm = $this->bd->prepare ($sql); + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } else { + $this->bd->beginTransaction (); + + $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'SET e.is_read = 1 ' + . 'WHERE f.id=? AND e.is_read = 0 AND e.id <= ?'; + $values = array ($id, $idMax); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + $affected = $stm->rowCount(); + + if ($affected > 0) { + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' + . 'SET f.cache_nbUnreads=f.cache_nbUnreads-' . $affected + . ' WHERE f.id=?'; + $values = array ($id); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + } + + $this->bd->commit (); + return $affected; + } + } + + public function searchByGuid ($feed_id, $id) { + // un guid est unique pour un flux donné + $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' + . 'FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + $feed_id, + $id + ); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $entries = HelperEntry::daoToEntry ($res); + return isset ($entries[0]) ? $entries[0] : false; + } + + public function searchById ($id) { + $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' + . 'FROM `' . $this->prefix . 'entry` WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $entries = HelperEntry::daoToEntry ($res); + return isset ($entries[0]) ? $entries[0] : false; + } + + public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = -1, $filter = '') { + $where = ''; + $values = array(); + switch ($type) { + case 'a': + $where .= 'priority > 0 '; + break; + case 's': + $where .= 'is_favorite = 1 '; + break; + case 'c': + $where .= 'category = ? '; + $values[] = intval($id); + break; + case 'f': + $where .= 'id_feed = ? '; + $values[] = intval($id); + break; + default: + throw new FreshRSS_EntriesGetter_Exception ('Bad type in Entry->listByType: [' . $type . ']!'); + } + switch ($state) { + case 'all': + break; + case 'not_read': + $where .= 'AND is_read = 0 '; + break; + case 'read': + $where .= 'AND is_read = 1 '; + break; + default: + throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!'); + } + switch ($order) { + case 'DESC': + case 'ASC': + break; + default: + throw new FreshRSS_EntriesGetter_Exception ('Bad order in Entry->listByType: [' . $order . ']!'); + } + if ($firstId > 0) { + $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; + } + $terms = array_unique(explode(' ', trim($filter))); + sort($terms); //Put #tags first + $having = ''; + foreach ($terms as $word) { + if (!empty($word)) { + if ($word[0] === '#' && isset($word[1])) { + $having .= 'AND tags LIKE ? '; + $values[] = '%' . $word .'%'; + } elseif (!empty($word)) { + $having .= 'AND (e.title LIKE ? OR content LIKE ?) '; + $values[] = '%' . $word .'%'; + $values[] = '%' . $word .'%'; + } + } + } + + $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 + . (empty($having) ? '' : 'HAVING' . substr($having, 3)) + . '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); + + return HelperEntry::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); + } + + public function listLastGuidsByFeed($id, $n) { + $sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n); + $stm = $this->bd->prepare ($sql); + $values = array ($id); + $stm->execute ($values); + return $stm->fetchAll (PDO::FETCH_COLUMN, 0); + } + + public function countUnreadRead () { + $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE priority > 0' + . ' UNION SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE priority > 0 AND is_read = 0'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); + $all = empty($res[0]) ? 0 : $res[0]; + $unread = empty($res[1]) ? 0 : $res[1]; + return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread); + } + public function count ($minPriority = null) { + $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id'; + if ($minPriority !== null) { + $sql = ' WHERE priority > ' . intval($minPriority); + } + $stm = $this->bd->prepare ($sql); + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); + return $res[0]; + } + public function countNotRead ($minPriority = null) { + $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE is_read = 0'; + if ($minPriority !== null) { + $sql = ' AND priority > ' . intval($minPriority); + } + $stm = $this->bd->prepare ($sql); + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); + return $res[0]; + } + + public function countUnreadReadFavorites () { + $sql = 'SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1' + . ' UNION SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1 AND is_read = 0'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); + $all = empty($res[0]) ? 0 : $res[0]; + $unread = empty($res[1]) ? 0 : $res[1]; + return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread); + } + + public function optimizeTable() { + $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + } +} + +class HelperEntry { + public static function daoToEntry ($listDAO) { + $list = array (); + + if (!is_array ($listDAO)) { + $listDAO = array ($listDAO); + } + + foreach ($listDAO as $key => $dao) { + $entry = new FreshRSS_Entry ( + $dao['id_feed'], + $dao['guid'], + $dao['title'], + $dao['author'], + $dao['content'], + $dao['link'], + $dao['date'], + $dao['is_read'], + $dao['is_favorite'], + $dao['tags'] + ); + if (isset ($dao['id'])) { + $entry->_id ($dao['id']); + } + $list[] = $entry; + } + + unset ($listDAO); + + return $list; + } +} diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php new file mode 100644 index 000000000..8f59b1c76 --- /dev/null +++ b/app/Models/FeedDAO.php @@ -0,0 +1,341 @@ +prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, 0)'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + substr($valuesTmp['url'], 0, 511), + $valuesTmp['category'], + substr($valuesTmp['name'], 0, 255), + substr($valuesTmp['website'], 0, 255), + substr($valuesTmp['description'], 0, 1023), + $valuesTmp['lastUpdate'], + base64_encode ($valuesTmp['httpAuth']), + ); + + if ($stm && $stm->execute ($values)) { + return $this->bd->lastInsertId(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function updateFeed ($id, $valuesTmp) { + $set = ''; + foreach ($valuesTmp as $key => $v) { + $set .= $key . '=?, '; + + if ($key == 'httpAuth') { + $valuesTmp[$key] = base64_encode ($v); + } + } + $set = substr ($set, 0, -2); + + $sql = 'UPDATE `' . $this->prefix . 'feed` SET ' . $set . ' WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + foreach ($valuesTmp as $v) { + $values[] = $v; + } + $values[] = $id; + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function updateLastUpdate ($id, $inError = 0) { + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE + . 'SET f.cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=f.id),' + . 'f.cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=f.id AND e2.is_read=0),' + . 'lastUpdate=?, error=? ' + . 'WHERE f.id=?'; + + $stm = $this->bd->prepare ($sql); + + $values = array ( + time (), + $inError, + $id, + ); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function changeCategory ($idOldCat, $idNewCat) { + $catDAO = new FreshRSS_CategoryDAO (); + $newCat = $catDAO->searchById ($idNewCat); + if (!$newCat) { + $newCat = $catDAO->getDefault (); + } + + $sql = 'UPDATE `' . $this->prefix . 'feed` SET category=? WHERE category=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ( + $newCat->id (), + $idOldCat + ); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function deleteFeed ($id) { + /*//For MYISAM (MySQL 5.5-) without FOREIGN KEY + $sql = 'DELETE FROM `' . $this->prefix . 'entry` WHERE id_feed=?'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + }*/ + + $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + public function deleteFeedByCategory ($id) { + /*//For MYISAM (MySQL 5.5-) without FOREIGN KEY + $sql = 'DELETE FROM `' . $this->prefix . 'entry` e ' + . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' + . 'WHERE f.category=?'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + }*/ + + $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE category=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function searchById ($id) { + $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE id=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($id); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $feed = HelperFeed::daoToFeed ($res); + + if (isset ($feed[$id])) { + return $feed[$id]; + } else { + return false; + } + } + public function searchByUrl ($url) { + $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE url=?'; + $stm = $this->bd->prepare ($sql); + + $values = array ($url); + + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $feed = current (HelperFeed::daoToFeed ($res)); + + if (isset ($feed)) { + return $feed; + } else { + return false; + } + } + + public function listFeeds () { + $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY name'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + + return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + } + + public function listFeedsOrderUpdate () { + $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate'; + $stm = $this->bd->prepare ($sql); + $stm->execute (); + + return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + } + + public function listByCategory ($cat) { + $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE category=? ORDER BY name'; + $stm = $this->bd->prepare ($sql); + + $values = array ($cat); + + $stm->execute ($values); + + return HelperFeed::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC)); + } + + public function countEntries ($id) { + $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=?'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + + return $res[0]['count']; + } + public function countNotRead ($id) { + $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND is_read=0'; + $stm = $this->bd->prepare ($sql); + $values = array ($id); + $stm->execute ($values); + $res = $stm->fetchAll (PDO::FETCH_ASSOC); + + return $res[0]['count']; + } + public function updateCachedValues () { //For one single feed, call updateLastUpdate($id) + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' + . 'INNER JOIN (' + . 'SELECT e.id_feed, ' + . 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, ' + . 'COUNT(e.id) AS nbEntries ' + . 'FROM `' . $this->prefix . 'entry` e ' + . 'GROUP BY e.id_feed' + . ') x ON x.id_feed=f.id ' + . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads'; + $stm = $this->bd->prepare ($sql); + + $values = array ($feed_id); + + if ($stm && $stm->execute ($values)) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } + + public function truncate ($id) { + $sql = 'DELETE e.* FROM `' . $this->prefix . 'entry` e WHERE e.id_feed=?'; + $stm = $this->bd->prepare($sql); + $values = array($id); + $this->bd->beginTransaction (); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + $affected = $stm->rowCount(); + + $sql = 'UPDATE `' . $this->prefix . 'feed` f ' + . 'SET f.cache_nbEntries=0, f.cache_nbUnreads=0 WHERE f.id=?'; + $values = array ($id); + $stm = $this->bd->prepare ($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + + $this->bd->commit (); + return $affected; + } + + public function cleanOldEntries ($id, $date_min, $keep = 15) { //Remember to call updateLastUpdate($id) just after + $sql = 'DELETE e.* FROM `' . $this->prefix . 'entry` e ' + . 'WHERE e.id_feed = :id_feed AND e.id <= :id_max AND e.is_favorite = 0 AND e.id NOT IN ' + . '(SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed = :id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select because of: MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' + $stm = $this->bd->prepare ($sql); + + $id_max = intval($date_min) . '000000'; + + $stm->bindParam(':id_feed', $id, PDO::PARAM_INT); + $stm->bindParam(':id_max', $id_max, PDO::PARAM_INT); + $stm->bindParam(':keep', $keep, PDO::PARAM_INT); + + if ($stm && $stm->execute ()) { + return $stm->rowCount(); + } else { + $info = $stm->errorInfo(); + Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + return false; + } + } +} + +class HelperFeed { + public static function daoToFeed ($listDAO, $catID = null) { + $list = array (); + + if (!is_array ($listDAO)) { + $listDAO = array ($listDAO); + } + + foreach ($listDAO as $key => $dao) { + if (!isset ($dao['name'])) { + continue; + } + if (isset ($dao['id'])) { + $key = $dao['id']; + } + + $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->_keepHistory (isset($dao['keep_history']) ? $dao['keep_history'] : ''); + $myFeed->_nbNotRead ($dao['cache_nbUnreads']); + $myFeed->_nbEntries ($dao['cache_nbEntries']); + if (isset ($dao['id'])) { + $myFeed->_id ($dao['id']); + } + $list[$key] = $myFeed; + } + + return $list; + } +} diff --git a/app/Models/Log.php b/app/Models/Log.php new file mode 100644 index 000000000..d2794458b --- /dev/null +++ b/app/Models/Log.php @@ -0,0 +1,26 @@ +date; + } + public function level () { + return $this->level; + } + public function info () { + return $this->information; + } + public function _date ($date) { + $this->date = $date; + } + public function _level ($level) { + $this->level = $level; + } + public function _info ($information) { + $this->information = $information; + } +} diff --git a/app/Models/LogDAO.php b/app/Models/LogDAO.php new file mode 100644 index 000000000..bf043fd6d --- /dev/null +++ b/app/Models/LogDAO.php @@ -0,0 +1,20 @@ +readLine ()) !== false) { + if (preg_match ('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) { + $myLog = new FreshRSS_Log (); + $myLog->_date ($matches[1]); + $myLog->_level ($matches[2]); + $myLog->_info ($matches[3]); + $logs[] = $myLog; + } + } + return $logs; + } +} diff --git a/app/Models/Themes.php b/app/Models/Themes.php new file mode 100644 index 000000000..a52812339 --- /dev/null +++ b/app/Models/Themes.php @@ -0,0 +1,88 @@ + '✚', + 'all' => '☰', + 'bookmark' => '★', + 'category' => '☷', + 'category-white' => '☷', + 'close' => '❌', + 'configure' => '⚙', + 'down' => '▽', + 'favorite' => '★', + 'help' => 'ⓘ', + 'link' => '↗', + 'login' => '🔒', + 'logout' => '🔓', + 'next' => '⏩', + 'non-starred' => '☆', + 'prev' => '⏪', + 'read' => '☑', + 'unread' => '☐', + 'refresh' => '🔃', //↻ + 'search' => '🔍', + 'share' => '♺', + 'starred' => '★', + 'tag' => '⚐', + 'up' => '△', + ); + if (!isset($alts[$name])) { + return ''; + } + + $url = $name . '.svg'; + $url = isset(self::$themeIcons[$url]) ? (self::$themeIconsUrl . $url) : + (self::$defaultIconsUrl . $url); + + return $urlOnly ? Minz_Url::display($url) : + '' . $alts[$name] . ''; + } +} diff --git a/app/controllers/configureController.php b/app/controllers/configureController.php index deec54a2b..0e7fbbdde 100755 --- a/app/controllers/configureController.php +++ b/app/controllers/configureController.php @@ -1,33 +1,33 @@ view->conf) && !is_logged ()) { - Error::error ( + Minz_Error::error ( 403, - array ('error' => array (Translate::t ('access_denied'))) + array ('error' => array (Minz_Translate::t ('access_denied'))) ); } - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $catDAO->checkDefault (); } public function categorizeAction () { - $feedDAO = new FeedDAO (); - $catDAO = new CategoryDAO (); + $feedDAO = new FreshRSS_FeedDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $catDAO->checkDefault (); $defaultCategory = $catDAO->getDefault (); $defaultId = $defaultCategory->id (); - if (Request::isPost ()) { - $cats = Request::param ('categories', array ()); - $ids = Request::param ('ids', array ()); - $newCat = trim (Request::param ('new_category', '')); + 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 Category ($name); + $cat = new FreshRSS_Category ($name); $values = array ( 'name' => $cat->name (), 'color' => $cat->color () @@ -40,7 +40,7 @@ class configureController extends ActionController { } if ($newCat != '') { - $cat = new Category ($newCat); + $cat = new FreshRSS_Category ($newCat); $values = array ( 'id' => $cat->id (), 'name' => $cat->name (), @@ -55,11 +55,11 @@ class configureController extends ActionController { // notif $notif = array ( 'type' => 'good', - 'content' => Translate::t ('categories_updated') + 'content' => Minz_Translate::t ('categories_updated') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); } $this->view->categories = $catDAO->listCategories (false); @@ -67,17 +67,17 @@ class configureController extends ActionController { $this->view->feeds = $feedDAO->listFeeds (); $this->view->flux = false; - View::prependTitle (Translate::t ('categories_management') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('categories_management') . ' - '); } public function feedAction () { - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $this->view->categories = $catDAO->listCategories (false); - $feedDAO = new FeedDAO (); + $feedDAO = new FreshRSS_FeedDAO (); $this->view->feeds = $feedDAO->listFeeds (); - $id = Request::param ('id'); + $id = Minz_Request::param ('id'); if ($id == false && !empty ($this->view->feeds)) { $id = current ($this->view->feeds)->id (); } @@ -87,22 +87,22 @@ class configureController extends ActionController { $this->view->flux = $this->view->feeds[$id]; if (!$this->view->flux) { - Error::error ( + Minz_Error::error ( 404, - array ('error' => array (Translate::t ('page_not_found'))) + array ('error' => array (Minz_Translate::t ('page_not_found'))) ); } else { - if (Request::isPost () && $this->view->flux) { - $name = Request::param ('name', ''); - $description = Request::param('description', ''); - $website = Request::param('website', ''); - $url = Request::param('url', ''); - $hist = Request::param ('keep_history', 'no'); - $cat = Request::param ('category', 0); - $path = Request::param ('path_entries', ''); - $priority = Request::param ('priority', 0); - $user = Request::param ('http_user', ''); - $pass = Request::param ('http_pass', ''); + 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') { @@ -131,58 +131,58 @@ class configureController extends ActionController { $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feed_updated') + 'content' => Minz_Translate::t ('feed_updated') ); } else { $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('error_occurred_update') + 'content' => Minz_Translate::t ('error_occurred_update') ); } - Session::_param ('notification', $notif); - Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); + Minz_Session::_param ('notification', $notif); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); } - View::prependTitle (Translate::t ('rss_feed_management') . ' - ' . $this->view->flux->name () . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - ' . $this->view->flux->name () . ' - '); } } else { - View::prependTitle (Translate::t ('rss_feed_management') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('rss_feed_management') . ' - '); } } public function displayAction () { - if (Request::isPost ()) { + if (Minz_Request::isPost ()) { $current_token = $this->view->conf->token (); - $language = Request::param ('language', 'en'); - $nb = Request::param ('posts_per_page', 10); - $mode = Request::param ('view_mode', 'normal'); - $view = Request::param ('default_view', 'a'); - $auto_load_more = Request::param ('auto_load_more', 'no'); - $display = Request::param ('display_posts', 'no'); - $onread_jump_next = Request::param ('onread_jump_next', 'no'); - $lazyload = Request::param ('lazyload', 'no'); - $sort = Request::param ('sort_order', 'DESC'); - $old = Request::param ('old_entries', 3); - $mail = Request::param ('mail_login', false); - $anon = Request::param ('anon_access', 'no'); - $token = Request::param ('token', $current_token); - $openArticle = Request::param ('mark_open_article', 'no'); - $openSite = Request::param ('mark_open_site', 'no'); - $scroll = Request::param ('mark_scroll', 'no'); - $reception = Request::param ('mark_upon_reception', 'no'); - $theme = Request::param ('theme', 'default'); - $topline_read = Request::param ('topline_read', 'no'); - $topline_favorite = Request::param ('topline_favorite', 'no'); - $topline_date = Request::param ('topline_date', 'no'); - $topline_link = Request::param ('topline_link', 'no'); - $bottomline_read = Request::param ('bottomline_read', 'no'); - $bottomline_favorite = Request::param ('bottomline_favorite', 'no'); - $bottomline_sharing = Request::param ('bottomline_sharing', 'no'); - $bottomline_tags = Request::param ('bottomline_tags', 'no'); - $bottomline_date = Request::param ('bottomline_date', 'no'); - $bottomline_link = Request::param ('bottomline_link', 'no'); + $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)); @@ -243,81 +243,81 @@ class configureController extends ActionController { 'bottomline_link' => $this->view->conf->bottomlineLink () ? 'yes' : 'no', ); - $confDAO = new RSSConfigurationDAO (); + $confDAO = new FreshRSS_ConfigurationDAO (); $confDAO->update ($values); - Session::_param ('conf', $this->view->conf); - Session::_param ('mail', $this->view->conf->mailLogin ()); + Minz_Session::_param ('conf', $this->view->conf); + Minz_Session::_param ('mail', $this->view->conf->mailLogin ()); - Session::_param ('language', $this->view->conf->language ()); + Minz_Session::_param ('language', $this->view->conf->language ()); Translate::reset (); // notif $notif = array ( 'type' => 'good', - 'content' => Translate::t ('configuration_updated') + 'content' => Minz_Translate::t ('configuration_updated') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward (array ('c' => 'configure', 'a' => 'display'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'display'), true); } - $this->view->themes = RSSThemes::get(); + $this->view->themes = FreshRSS_Themes::get(); - View::prependTitle (Translate::t ('general_and_reading_management') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('general_and_reading_management') . ' - '); - $entryDAO = new EntryDAO (); + $entryDAO = new FreshRSS_EntryDAO (); $this->view->nb_total = $entryDAO->count (); $this->view->size_total = $entryDAO->size (); } public function sharingAction () { - if (Request::isPost ()) { + if (Minz_Request::isPost ()) { $this->view->conf->_sharing (array ( - 'shaarli' => Request::param ('shaarli', ''), - 'poche' => Request::param ('poche', ''), - 'diaspora' => Request::param ('diaspora', ''), - 'twitter' => Request::param ('twitter', 'no') === 'yes', - 'g+' => Request::param ('g+', 'no') === 'yes', - 'facebook' => Request::param ('facebook', 'no') === 'yes', - 'email' => Request::param ('email', 'no') === 'yes', - 'print' => Request::param ('print', 'no') === 'yes' + '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 RSSConfigurationDAO (); + $confDAO = new FreshRSS_ConfigurationDAO (); $confDAO->update ($this->view->conf->sharing ()); - Session::_param ('conf', $this->view->conf); + Minz_Session::_param ('conf', $this->view->conf); // notif $notif = array ( 'type' => 'good', - 'content' => Translate::t ('configuration_updated') + 'content' => Minz_Translate::t ('configuration_updated') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward (array ('c' => 'configure', 'a' => 'sharing'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'sharing'), true); } - View::prependTitle (Translate::t ('sharing_management') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('sharing_management') . ' - '); - $entryDAO = new EntryDAO (); + $entryDAO = new FreshRSS_EntryDAO (); $this->view->nb_total = $entryDAO->count (); } public function importExportAction () { - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $this->view->categories = $catDAO->listCategories (); - $this->view->req = Request::param ('q'); + $this->view->req = Minz_Request::param ('q'); if ($this->view->req == 'export') { - View::_title ('freshrss_feeds.opml'); + 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 FeedDAO (); - $catDAO = new CategoryDAO (); + $feedDAO = new FreshRSS_FeedDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $list = array (); foreach ($catDAO->listCategories () as $key => $cat) { @@ -326,7 +326,7 @@ class configureController extends ActionController { } $this->view->categories = $list; - } elseif ($this->view->req == 'import' && Request::isPost ()) { + } 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 { @@ -336,20 +336,20 @@ class configureController extends ActionController { // 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 - Request::_param ('q', 'null'); - Request::_param ('categories', $categories); - Request::_param ('feeds', $feeds); - Request::forward (array ('c' => 'feed', 'a' => 'massiveImport')); - } catch (OpmlException $e) { + 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' => Translate::t ('bad_opml_file') + 'content' => Minz_Translate::t ('bad_opml_file') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'configure', 'a' => 'importExport' ), true); @@ -357,13 +357,13 @@ class configureController extends ActionController { } } - $feedDAO = new FeedDAO (); + $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; - View::prependTitle (Translate::t ('import_export_opml') . ' - '); + Minz_View::prependTitle (Translate::t ('import_export_opml') . ' - '); } public function shortcutAction () { @@ -379,8 +379,8 @@ class configureController extends ActionController { 'prev_entry', 'next_page', 'prev_page', 'collapse_entry', 'load_more'); - if (Request::isPost ()) { - $shortcuts = Request::param ('shortcuts'); + if (Minz_Request::isPost ()) { + $shortcuts = Minz_Request::param ('shortcuts'); $shortcuts_ok = array (); foreach ($shortcuts as $key => $value) { @@ -396,20 +396,20 @@ class configureController extends ActionController { 'shortcuts' => $this->view->conf->shortcuts () ); - $confDAO = new RSSConfigurationDAO (); + $confDAO = new FreshRSS_ConfigurationDAO (); $confDAO->update ($values); - Session::_param ('conf', $this->view->conf); + Minz_Session::_param ('conf', $this->view->conf); // notif $notif = array ( 'type' => 'good', - 'content' => Translate::t ('shortcuts_updated') + 'content' => Minz_Translate::t ('shortcuts_updated') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward (array ('c' => 'configure', 'a' => 'shortcut'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'shortcut'), true); } - View::prependTitle (Translate::t ('shortcuts_management') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('shortcuts_management') . ' - '); } } diff --git a/app/controllers/entryController.php b/app/controllers/entryController.php index c01139ba4..a332ca8a9 100755 --- a/app/controllers/entryController.php +++ b/app/controllers/entryController.php @@ -1,46 +1,46 @@ view->conf) && !is_logged ()) { - Error::error ( + Minz_Error::error ( 403, - array ('error' => array (Translate::t ('access_denied'))) + array ('error' => array (Minz_Translate::t ('access_denied'))) ); } $this->params = array (); $this->redirect = false; - $ajax = Request::param ('ajax'); + $ajax = Minz_Request::param ('ajax'); if ($ajax) { $this->view->_useLayout (false); } } public function lastAction () { - $ajax = Request::param ('ajax'); + $ajax = Minz_Request::param ('ajax'); if (!$ajax && $this->redirect) { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'index', 'a' => 'index', 'params' => $this->params ), true); } else { - Request::_param ('ajax'); + Minz_Request::_param ('ajax'); } } public function readAction () { $this->redirect = true; - $id = Request::param ('id'); - $is_read = Request::param ('is_read'); - $get = Request::param ('get'); - $nextGet = Request::param ('nextGet', $get); - $idMax = Request::param ('idMax', 0); + $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 EntryDAO (); + $entryDAO = new FreshRSS_EntryDAO (); if ($id == false) { if (!$get) { $entryDAO->markReadEntries ($idMax); @@ -68,9 +68,9 @@ class entryController extends ActionController { $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feeds_marked_read') + 'content' => Minz_Translate::t ('feeds_marked_read') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); } else { $entryDAO->markRead ($id, $is_read); } @@ -79,10 +79,10 @@ class entryController extends ActionController { public function bookmarkAction () { $this->redirect = true; - $id = Request::param ('id'); + $id = Minz_Request::param ('id'); if ($id) { - $entryDAO = new EntryDAO (); - $entryDAO->markFavorite ($id, Request::param ('is_favorite')); + $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO->markFavorite ($id, Minz_Request::param ('is_favorite')); } } @@ -93,18 +93,18 @@ class entryController extends ActionController { // 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 EntryDAO(); + $entryDAO = new FreshRSS_EntryDAO(); $entryDAO->optimizeTable(); invalidateHttpCache(); $notif = array ( 'type' => 'good', - 'content' => Translate::t ('optimization_complete') + 'content' => Minz_Translate::t ('optimization_complete') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); - Request::forward(array( + Minz_Request::forward(array( 'c' => 'configure', 'a' => 'display' ), true); diff --git a/app/controllers/errorController.php b/app/controllers/errorController.php index 092609280..d1c2f8fec 100644 --- a/app/controllers/errorController.php +++ b/app/controllers/errorController.php @@ -1,8 +1,8 @@ view->code = 'Error 403 - Forbidden'; break; @@ -19,8 +19,8 @@ class ErrorController extends ActionController { $this->view->code = 'Error 404 - Not found'; } - $this->view->logs = Request::param ('logs'); + $this->view->logs = Minz_Request::param ('logs'); - View::prependTitle ($this->view->code . ' - '); + Minz_View::prependTitle ($this->view->code . ' - '); } } diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index 24b8627ff..e4014c326 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -1,22 +1,22 @@ view->conf->token(); - $token_param = Request::param ('token', ''); + $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); - $action = Request::actionName (); + $action = Minz_Request::actionName (); if (login_is_conf ($this->view->conf) && !is_logged () && !($token_is_ok && $action == 'actualize')) { - Error::error ( + Minz_Error::error ( 403, - array ('error' => array (Translate::t ('access_denied'))) + array ('error' => array (Minz_Translate::t ('access_denied'))) ); } - $this->catDAO = new CategoryDAO (); + $this->catDAO = new FreshRSS_CategoryDAO (); $this->catDAO->checkDefault (); } @@ -32,21 +32,21 @@ class feedController extends ActionController { public function addAction () { @set_time_limit(300); - if (Request::isPost ()) { - $url = Request::param ('url_rss'); - $cat = Request::param ('category', false); + 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 = Request::param ('username'); - $pass = Request::param ('password'); + $user = Minz_Request::param ('username'); + $pass = Minz_Request::param ('password'); $params = array (); $transactionStarted = false; try { - $feed = new Feed ($url); + $feed = new FreshRSS_Feed ($url); $feed->_category ($cat); $httpAuth = ''; @@ -57,7 +57,7 @@ class feedController extends ActionController { $feed->load (); - $feedDAO = new FeedDAO (); + $feedDAO = new FreshRSS_FeedDAO (); $values = array ( 'url' => $feed->url (), 'category' => $feed->category (), @@ -72,25 +72,25 @@ class feedController extends ActionController { // on est déjà abonné à ce flux $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('already_subscribed', $feed->name ()) + 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) ); - Session::_param ('notification', $notif); + 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' => Translate::t ('feed_not_added', $feed->name ()) + 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); } else { $feed->_id ($id); $feed->faviconPrepare(); $is_read = $this->view->conf->markUponReception() === 'yes' ? 1 : 0; - $entryDAO = new EntryDAO (); + $entryDAO = new FreshRSS_EntryDAO (); $entries = $feed->entries (); usort($entries, 'self::entryDateComparer'); @@ -118,68 +118,68 @@ class feedController extends ActionController { // ok, ajout terminé $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feed_added', $feed->name ()) + 'content' => Minz_Translate::t ('feed_added', $feed->name ()) ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); // permet de rediriger vers la page de conf du flux $params['id'] = $feed->id (); } } - } catch (BadUrlException $e) { + } catch (FreshRSS_BadUrl_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('invalid_url', $url) + 'content' => Minz_Translate::t ('invalid_url', $url) ); - Session::_param ('notification', $notif); - } catch (FeedException $e) { + Minz_Session::_param ('notification', $notif); + } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('internal_problem_feed') + 'content' => Minz_Translate::t ('internal_problem_feed') ); - Session::_param ('notification', $notif); - } catch (FileNotExistException $e) { + 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' => Translate::t ('internal_problem_feed') + 'content' => Minz_Translate::t ('internal_problem_feed') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); } if ($transactionStarted) { $feedDAO->rollBack (); } - Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); } } public function truncateAction () { - if (Request::isPost ()) { - $id = Request::param ('id'); - $feedDAO = new FeedDAO (); + 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' => Translate::t ('n_entries_deleted', $n) + 'content' => Minz_Translate::t ('n_entries_deleted', $n) ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); invalidateHttpCache(); - Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); } } public function actualizeAction () { @set_time_limit(300); - $feedDAO = new FeedDAO (); - $entryDAO = new EntryDAO (); + $feedDAO = new FreshRSS_FeedDAO (); + $entryDAO = new FreshRSS_EntryDAO (); - $id = Request::param ('id'); - $force = Request::param ('force', false); + $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 @@ -236,7 +236,7 @@ class feedController extends ActionController { $feedDAO->updateLastUpdate ($feed->id ()); $feedDAO->commit (); $flux_update++; - } catch (FeedException $e) { + } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); $feedDAO->updateLastUpdate ($feed->id (), 1); } @@ -254,19 +254,19 @@ class feedController extends ActionController { // on a mis un seul flux à jour $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feed_actualized', $feed->name ()) + 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) ); } elseif ($flux_update > 1) { // plusieurs flux on été mis à jour $notif = array ( 'type' => 'good', - 'content' => Translate::t ('n_feeds_actualized', $flux_update) + 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) ); } else { // aucun flux n'a été mis à jour, oups $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('no_feed_actualized') + 'content' => Minz_Translate::t ('no_feed_actualized') ); } @@ -277,9 +277,9 @@ class feedController extends ActionController { $url['params'] = array ('get' => 'f_' . $feed->id ()); } - if (Request::param ('ajax', 0) === 0) { - Session::_param ('notification', $notif); - Request::forward ($url, true); + 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, @@ -288,9 +288,9 @@ class feedController extends ActionController { // ressenti utilisateur $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feeds_actualized') + 'content' => Minz_Translate::t ('feeds_actualized') ); - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); // et on désactive le layout car ne sert à rien $this->view->_useLayout (false); } @@ -299,11 +299,11 @@ class feedController extends ActionController { public function massiveImportAction () { @set_time_limit(300); - $entryDAO = new EntryDAO (); - $feedDAO = new FeedDAO (); + $entryDAO = new FreshRSS_EntryDAO (); + $feedDAO = new FreshRSS_FeedDAO (); - $categories = Request::param ('categories', array (), true); - $feeds = Request::param ('feeds', array (), true); + $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); @@ -341,78 +341,78 @@ class feedController extends ActionController { $error = true; } } - } catch (FeedException $e) { + } catch (FreshRSS_Feed_Exception $e) { $error = true; Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); } } if ($error) { - $res = Translate::t ('feeds_imported_with_errors'); + $res = Minz_Translate::t ('feeds_imported_with_errors'); } else { - $res = Translate::t ('feeds_imported'); + $res = Minz_Translate::t ('feeds_imported'); } $notif = array ( 'type' => 'good', 'content' => $res ); - Session::_param ('notification', $notif); - Session::_param ('actualize_feeds', true); + Minz_Session::_param ('notification', $notif); + Minz_Session::_param ('actualize_feeds', true); // et on redirige vers la page d'accueil - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'index', 'a' => 'index' ), true); } public function deleteAction () { - if (Request::isPost ()) { - $type = Request::param ('type', 'feed'); - $id = Request::param ('id'); + if (Minz_Request::isPost ()) { + $type = Minz_Request::param ('type', 'feed'); + $id = Minz_Request::param ('id'); - $feedDAO = new FeedDAO (); + $feedDAO = new FreshRSS_FeedDAO (); if ($type == 'category') { if ($feedDAO->deleteFeedByCategory ($id)) { $notif = array ( 'type' => 'good', - 'content' => Translate::t ('category_emptied') + 'content' => Minz_Translate::t ('category_emptied') ); //TODO: Delete old favicons } else { $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('error_occured') + 'content' => Minz_Translate::t ('error_occured') ); } } else { if ($feedDAO->deleteFeed ($id)) { $notif = array ( 'type' => 'good', - 'content' => Translate::t ('feed_deleted') + 'content' => Minz_Translate::t ('feed_deleted') ); Feed::faviconDelete($id); } else { $notif = array ( 'type' => 'bad', - 'content' => Translate::t ('error_occured') + 'content' => Minz_Translate::t ('error_occured') ); } } - Session::_param ('notification', $notif); + Minz_Session::_param ('notification', $notif); if ($type == 'category') { - Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); } else { - Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); + Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); } } } private function addCategories ($categories) { - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); foreach ($categories as $cat) { if (!$catDAO->searchByName ($cat->name ())) { diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index 9c1e18f0b..16a053ba3 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -1,6 +1,6 @@ entryDAO = new EntryDAO (); - $this->feedDAO = new FeedDAO (); - $this->catDAO = new CategoryDAO (); + $this->entryDAO = new FreshRSS_EntryDAO (); + $this->feedDAO = new FreshRSS_FeedDAO (); + $this->catDAO = new FreshRSS_CategoryDAO (); } public function indexAction () { - $output = Request::param ('output'); + $output = Minz_Request::param ('output'); $token = $this->view->conf->token(); - $token_param = Request::param ('token', ''); + $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token === $token_param); // check if user is log in @@ -30,7 +30,7 @@ class indexController extends ActionController { } // construction of RSS url of this feed - $params = Request::params (); + $params = Minz_Request::params (); $params['output'] = 'rss'; if (isset ($params['search'])) { $params['search'] = urlencode ($params['search']); @@ -51,10 +51,10 @@ class indexController extends ActionController { $this->view->_useLayout (false); header('Content-Type: application/rss+xml; charset=utf-8'); } else { - View::appendScript (Url::display ('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); + Minz_View::appendScript (Minz_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'))); + Minz_View::appendScript (Minz_Url::display ('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); } } @@ -65,14 +65,14 @@ class indexController extends ActionController { $this->view->get_c = ''; $this->view->get_f = ''; - $get = Request::param ('get', 'a'); + $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); - Error::error ( + Minz_Error::error ( 404, - array ('error' => array (Translate::t ('page_not_found'))) + array ('error' => array (Minz_Translate::t ('page_not_found'))) ); return; } @@ -80,25 +80,25 @@ class indexController extends ActionController { $this->view->nb_not_read = HelperCategory::CountUnreads($this->view->cat_aside, 1); // mise à jour des titres - $this->view->rss_title = $this->view->currentName . ' | ' . View::title(); + $this->view->rss_title = $this->view->currentName . ' | ' . Minz_View::title(); if ($this->view->nb_not_read > 0) { - View::appendTitle (' (' . $this->view->nb_not_read . ')'); + Minz_View::appendTitle (' (' . $this->view->nb_not_read . ')'); } - View::prependTitle ( + 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 = Request::param ('state', $this->view->conf->defaultView ()); - $filter = Request::param ('search', ''); + $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 = Request::param ('order', $this->view->conf->sortOrder ()); - $nb = Request::param ('nb', $this->view->conf->postsPerPage ()); - $first = Request::param ('next', ''); + $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) { @@ -143,11 +143,11 @@ class indexController extends ActionController { } $this->view->entries = $entries; - } catch (EntriesGetterException $e) { + } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); - Error::error ( + Minz_Error::error ( 404, - array ('error' => array (Translate::t ('page_not_found'))) + array ('error' => array (Minz_Translate::t ('page_not_found'))) ); } } @@ -160,11 +160,11 @@ class indexController extends ActionController { private function checkAndProcessType ($getType, $getId) { switch ($getType) { case 'a': - $this->view->currentName = Translate::t ('your_rss_feeds'); + $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); $this->view->get_c = $getType; return true; case 's': - $this->view->currentName = Translate::t ('your_favorites'); + $this->view->currentName = Minz_Translate::t ('your_favorites'); $this->view->get_c = $getType; return true; case 'c': @@ -200,35 +200,35 @@ class indexController extends ActionController { } public function aboutAction () { - View::prependTitle (Translate::t ('about') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('about') . ' - '); } public function logsAction () { if (login_is_conf ($this->view->conf) && !is_logged ()) { - Error::error ( + Minz_Error::error ( 403, - array ('error' => array (Translate::t ('access_denied'))) + array ('error' => array (Minz_Translate::t ('access_denied'))) ); } - View::prependTitle (Translate::t ('logs') . ' - '); + Minz_View::prependTitle (Minz_Translate::t ('logs') . ' - '); - if (Request::isPost ()) { + if (Minz_Request::isPost ()) { file_put_contents(LOG_PATH . '/application.log', ''); } $logs = array(); try { - $logDAO = new LogDAO (); + $logDAO = new FreshRSS_LogDAO (); $logs = $logDAO->lister (); $logs = array_reverse ($logs); - } catch(FileNotExistException $e) { + } catch (Minz_FileNotExistException $e) { } //gestion pagination - $page = Request::param ('page', 1); - $this->view->logsPaginator = new Paginator ($logs); + $page = Minz_Request::param ('page', 1); + $this->view->logsPaginator = new Minz_Paginator ($logs); $this->view->logsPaginator->_nbItemsPerPage (50); $this->view->logsPaginator->_currentPage ($page); } @@ -237,9 +237,9 @@ class indexController extends ActionController { $this->view->_useLayout (false); $url = 'https://verifier.login.persona.org/verify'; - $assert = Request::param ('assertion'); + $assert = Minz_Request::param ('assertion'); $params = 'assertion=' . $assert . '&audience=' . - urlencode (Url::display (null, 'php', true)); + urlencode (Minz_Url::display (null, 'php', true)); $ch = curl_init (); $options = array ( CURLOPT_URL => $url, @@ -253,12 +253,12 @@ class indexController extends ActionController { $res = json_decode ($result, true); if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mailLogin ()) { - Session::_param ('mail', $res['email']); + Minz_Session::_param ('mail', $res['email']); invalidateHttpCache(); } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = Translate::t ('invalid_login'); + $res['reason'] = Minz_Translate::t ('invalid_login'); } header('Content-Type: application/json; charset=UTF-8'); @@ -267,7 +267,7 @@ class indexController extends ActionController { public function logoutAction () { $this->view->_useLayout (false); - Session::_param ('mail'); + Minz_Session::_param ('mail'); invalidateHttpCache(); } } diff --git a/app/controllers/javascriptController.php b/app/controllers/javascriptController.php index 291474130..e7e25f656 100755 --- a/app/controllers/javascriptController.php +++ b/app/controllers/javascriptController.php @@ -1,13 +1,13 @@ view->_useLayout (false); header('Content-type: text/javascript'); } public function actualizeAction () { - $feedDAO = new FeedDAO (); + $feedDAO = new FreshRSS_FeedDAO (); $this->view->feeds = $feedDAO->listFeeds (); } } diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 7dbe445b2..aa46af95d 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -1,13 +1,13 @@ diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 2ce0b3ba4..7fbccce1e 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,17 +1,17 @@ diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index ce5ded230..9a6b16d58 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,23 +1,23 @@
    - +
      conf) || is_logged ()) { ?>
    • - - + +
    • conf)) { ?> -
    • +
    • @@ -25,8 +25,8 @@
    • @@ -38,7 +38,7 @@ get_c == $cat->id ()) { $c_active = true; } ?>
        @@ -49,7 +49,7 @@
      • ✇ @@ -67,13 +67,13 @@ diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 12af6057a..6cb1380a3 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,9 +1,9 @@ conf)) { ?> @@ -12,8 +12,8 @@ @@ -24,25 +24,25 @@ $this->conf->anonAccess() == 'yes') { ?>
        - - + + - + - + - + - +
        @@ -53,19 +53,19 @@ @@ -74,7 +74,7 @@ if (login_is_conf ($this->conf) && !is_logged ()) { ?>
        - +
    diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index ac00e8fd0..b7c34f04e 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -11,19 +11,19 @@ //]]> nextId)) { - $params = Request::params (); + $params = Minz_Request::params (); $params['next'] = $this->nextId; ?> - + - + rss_url)) { ?> - + - - - - + + + + @@ -39,7 +39,7 @@ ?>
    notification['content']; ?> - +
    diff --git a/app/layout/nav_entries.phtml b/app/layout/nav_entries.phtml index 0811fe8fa..3141e92a0 100644 --- a/app/layout/nav_entries.phtml +++ b/app/layout/nav_entries.phtml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index f3e985dc0..92a987aed 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -1,22 +1,22 @@