diff options
| author | 2016-12-26 16:33:47 +0100 | |
|---|---|---|
| committer | 2016-12-26 16:33:47 +0100 | |
| commit | 5f637bd816b7323885bfe1751a1724ee59a822f6 (patch) | |
| tree | 67028e45792c575c25c92616633f64cc7a4a13eb | |
| parent | c3d2496bb3ce665faf4a0f24a4aa2ab300ab56d3 (diff) | |
| parent | 109f63be2620cf108efdfebd43f491e2720c824a (diff) | |
Merge pull request #1399 from FreshRSS/dev1.6.2
Release 1.6.2
51 files changed, 460 insertions, 148 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be6d74bd..da73c285e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 2016-12-26 FreshRSS 1.6.2 + +* Features + * Add git compatibility in Web update system [#1357](https://github.com/FreshRSS/FreshRSS/issues/1357) + * Requires that the initial installation is done with git + * New option `limits.cookie_duration` in `data/config.php` to set the login cookie duration [#1384](https://github.com/FreshRSS/FreshRSS/issues/1384) +* SQL + * More robust export function in the case of large datasets [#1372](https://github.com/FreshRSS/FreshRSS/issues/1372) +* CLI + * New command `./cli/user-info.php` to get some user information [#1345](https://github.com/FreshRSS/FreshRSS/issues/1345) +* Bug fixing + * Fix bug in estimating last user activity [#1358](https://github.com/FreshRSS/FreshRSS/issues/1358) + * PostgreSQL: fix bug when updating cached values [#1360](https://github.com/FreshRSS/FreshRSS/issues/1360) + * Fix bug in confirmation before marking as read [#1348](https://github.com/FreshRSS/FreshRSS/issues/1348) + * Fix small bugs in installer [#1363](https://github.com/FreshRSS/FreshRSS/pull/1363) + * Allow slash in database hostname, when using sockets [#1364](https://github.com/FreshRSS/FreshRSS/issues/1364) + * Add curl user-agent to retrieve favicons [#1380](https://github.com/FreshRSS/FreshRSS/issues/1380) + * Send login cookie only once [#1398](https://github.com/FreshRSS/FreshRSS/pull/1398) + * Add a check for PHP extension fileinfo [#1375](https://github.com/FreshRSS/FreshRSS/issues/1375) + + ## 2016-11-02 FreshRSS 1.6.1 * Bug fixing @@ -53,7 +74,7 @@ * Download icon 💾 for podcasts [#1236](https://github.com/FreshRSS/FreshRSS/issues/1236) * SimplePie * Fix auto-discovery of RSS feeds in Web pages served as `text/xml` [#1264](https://github.com/FreshRSS/FreshRSS/issues/1264) -* Mics. +* Misc. * Removed *resource-priorities* attributes (`defer`, `lazyload`), deprecated by W3C [#1222](https://github.com/FreshRSS/FreshRSS/pull/1222) diff --git a/CREDITS.md b/CREDITS.md index 65c1318b3..827a8cfd3 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,5 +1,5 @@ This is a credit file of people who have [contributed to FreshRSS](https://github.com/FreshRSS/FreshRSS/graphs/contributors) with, at least, -one commit on the FreshRSS repository (at https://github.com/FreshRSS/FreshRSS). +one commit on one of the FreshRSS repositories (at https://github.com/FreshRSS). Please note a commit on THIS specific file is not considered as a contribution (too easy!). Its purpose is to show that even the smallest contribution is important. People are sorted by name so please keep this order. @@ -19,15 +19,19 @@ People are sorted by name so please keep this order. * [hckweb](https://github.com/hckweb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=hckweb) * [Jaussoin Timothée](https://github.com/edhelas): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=edhelas), [Web](http://edhelas.movim.eu/) * [Julien Reichardt](https://github.com/j8r): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=j8r), [Web](https://blog.jrei.ch/) +* [Kevin Papst](https://github.com/kevinpapst): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=kevinpapst), [Web](http://www.kevinpapst.de/) * [Luc Didry](https://github.com/ldidry): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ldidry), [Web](https://www.fiat-tux.fr/) * [marcomrc](https://github.com/marcomrc): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=marcomrc) * [Marcus Rohrmoser](https://github.com/mro): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=mro), [Web](http://mro.name/~me) * [Marien Fressinaud](https://github.com/marienfressinaud): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=marienfressinaud), [Web](http://marienfressinaud.fr/) * [Melvyn Laïly](https://github.com/yaurthek): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=yaurthek), [Web](http://x2a.yt/) * [Nicolas Elie](https://github.com/nicolaselie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicolaselie) +* [Nicolas Lœuillet](https://github.com/nicosomb): [contributions](https://github.com/FreshRSS/documentation/commits?author=nicosomb), [Web](http://www.loeuillet.org/) * [plopoyop](https://github.com/plopoyop): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=plopoyop) * [purexo](https://github.com/purexo): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:purexo), [Web](https://purexo.mom/) +* [Quentin Dufour](https://github.com/superboum): [contributions](https://github.com/FreshRSS/documentation/commits?author=superboum), [Web](http://quentin.dufour.io/) * [romibi](https://github.com/romibi): [contributions](https://github.com/FreshRSS/FreshRSS/commits/dev?author=romibi) +* [subic](https://github.com/subic): [contributions](https://github.com/FreshRSS/documentation/commits?author=subic) * [Tets42](https://github.com/Tets42): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Tets42) * [tomgue](https://github.com/tomgue): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=tomgue) * [Wanabo](https://github.com/Wanabo): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Wanabo) diff --git a/README.fr.md b/README.fr.md index 8efa983e3..b0b46bf65 100644 --- a/README.fr.md +++ b/README.fr.md @@ -8,6 +8,7 @@ Il se veut léger et facile à prendre en main tout en étant un outil puissant Il permet de gérer plusieurs utilisateurs, et dispose d’un mode de lecture anonyme. Il supporte [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) pour des notifications instantanées depuis les sites compatibles. Il y a une API pour les clients (mobiles), ainsi qu’une [interface en ligne de commande](./cli/README.md). +Enfin, il permet l’ajout d’[extensions](#extensions) pour encore plus de personnalisation. * Site officiel : http://freshrss.org * Démo : http://demo.freshrss.org/ @@ -23,7 +24,7 @@ Voir la [liste des versions](../../releases). * Pour ceux qui veulent bien aider à tester ou déveloper les dernières fonctionnalités, [la branche dev](https://github.com/FreshRSS/FreshRSS/tree/dev) vous ouvre les bras ! # Avertissements -Cette application a été développée pour s’adapter principalement à des besoins personnels, et aucune garantie n'est fournie. +Cette application a été développée pour s’adapter principalement à des besoins personnels, et aucune garantie n’est fournie. Les demandes de fonctionnalités, rapports de bugs, et autres contributions sont les bienvenues. Privilégiez pour cela des [demandes sur GitHub](https://github.com/FreshRSS/FreshRSS/issues). Nous sommes une communauté amicale. @@ -85,13 +86,16 @@ sudo git checkout -b dev origin/dev # Mettre les droits d’accès pour le serveur Web sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ +# Si vous souhaitez permettre les mises à jour par l’interface Web +sudo chmod -R g+w . + # Publier FreshRSS dans votre répertoire HTML public sudo ln -s /usr/share/FreshRSS/p /var/www/html/FreshRSS # Naviguez vers http://example.net/FreshRSS pour terminer l’installation # (Si vous le faite depuis localhost, vous pourrez avoir à ajuster le réglage de votre adresse publique) # ou utilisez l’interface en ligne de commande -# Mettre à jour FreshRSS vers une nouvelle version +# Mettre à jour FreshRSS vers une nouvelle version par git cd /usr/share/FreshRSS sudo git pull sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ @@ -140,6 +144,11 @@ mysqldump -u utilisateur -p --databases freshrss > freshrss.sql ``` +# Extensions +FreshRSS permet l’ajout d’extensions en plus des fonctionnalités natives. +Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensions). + + # Bibliothèques incluses * [SimplePie](http://simplepie.org/) * [MINZ](https://github.com/marienfressinaud/MINZ) @@ -8,6 +8,7 @@ It is at the same time lightweight, easy to work with, powerful and customizable It is a multi-user application with an anonymous reading mode. It supports [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) for instant notifications from compatible Web sites. There is an API for (mobile) clients, and a [Command-Line Interface](./cli/README.md). +Finally, it supports [extensions](#extensions) for further tuning. * Official website: http://freshrss.org * Demo: http://demo.freshrss.org/ @@ -85,13 +86,16 @@ sudo git checkout -b dev origin/dev # Set the rights so that your Web server can access the files sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ +# If you would like to allow updates from the Web interface +sudo chmod -R g+w . + # Publish FreshRSS in your public HTML directory sudo ln -s /usr/share/FreshRSS/p /var/www/html/FreshRSS # Navigate to http://example.net/FreshRSS to complete the installation # (If you do it from localhost, you may have to adjust the setting of your public address later) # or use the Command-Line Interface -# Update to a newer version of FreshRSS +# Update to a newer version of FreshRSS with git cd /usr/share/FreshRSS sudo git pull sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ @@ -140,6 +144,11 @@ mysqldump -u user -p --databases freshrss > freshrss.sql ``` +# Extensions +FreshRSS supports further customizations by adding extensions on top of its core functionality. +See the [repository dedicated to those extensions](https://github.com/FreshRSS/Extensions). + + # Included libraries * [SimplePie](http://simplepie.org/) * [MINZ](https://github.com/marienfressinaud/MINZ) diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 9decba431..1398e4e49 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -113,6 +113,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + $conf = Minz_Configuration::get('system'); + $limits = $conf->limits; + $this->view->cookie_days = round($limits['cookie_duration'] / 86400, 1); + if (Minz_Request::isPost()) { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c4115584a..f71f26a4e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -27,6 +27,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public static function addFeed($url, $title = '', $cat_id = 0, $new_cat_name = '', $http_auth = '') { + FreshRSS_UserDAO::touch(); @set_time_limit(300); $catDAO = new FreshRSS_CategoryDAO(); @@ -484,6 +485,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_id <= 0 || $feed_name == '') { return false; } + FreshRSS_UserDAO::touch(); $feedDAO = FreshRSS_Factory::createFeedDao(); return $feedDAO->updateFeed($feed_id, array('name' => $feed_name)); } @@ -492,6 +494,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_id <= 0 || ($cat_id <= 0 && $new_cat_name == '')) { return false; } + FreshRSS_UserDAO::touch(); $catDAO = new FreshRSS_CategoryDAO(); if ($cat_id > 0) { @@ -540,6 +543,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public static function deleteFeed($feed_id) { + FreshRSS_UserDAO::touch(); $feedDAO = FreshRSS_Factory::createFeedDao(); if ($feedDAO->deleteFeed($feed_id)) { // TODO: Delete old favicon diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 3ba91a243..6ae89defb 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -531,6 +531,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->entryDAO = FreshRSS_Factory::createEntryDao($username); $this->feedDAO = FreshRSS_Factory::createFeedDao($username); + $this->entryDAO->disableBuffering(); + if ($export_feeds === true) { //All feeds $export_feeds = $this->feedDAO->listFeedsIds(); @@ -641,13 +643,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->list_title = _t('sub.import_export.starred_list'); $this->view->type = 'starred'; $unread_fav = $this->entryDAO->countUnreadReadFavorites(); - $this->view->entries = $this->entryDAO->listWhere( + $this->view->entriesRaw = $this->entryDAO->listWhereRaw( 's', '', FreshRSS_Entry::STATE_ALL, 'ASC', $unread_fav['all'] ); } elseif ($type === 'feed' && $feed != null) { $this->view->list_title = _t('sub.import_export.feed_list', $feed->name()); $this->view->type = 'feed/' . $feed->id(); - $this->view->entries = $this->entryDAO->listWhere( + $this->view->entriesRaw = $this->entryDAO->listWhereRaw( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $maxFeedEntries ); diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 64c984b04..8f939dbdb 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -2,6 +2,45 @@ class FreshRSS_update_Controller extends Minz_ActionController { + public static function isGit() { + return is_dir(FRESHRSS_PATH . '/.git/'); + } + + public static function hasGitUpdate() { + $cwd = getcwd(); + chdir(FRESHRSS_PATH); + $output = array(); + try { + exec('git fetch', $output, $return); + if ($return == 0) { + exec('git status -sb --porcelain remote', $output, $return); + } else { + $line = is_array($output) ? implode('; ', $output) : '' . $output; + Minz_Log::warning('git fetch warning:' . $line); + } + } catch (Exception $e) { + Minz_Log::warning('git fetch error:' . $e->getMessage()); + } + chdir($cwd); + $line = is_array($output) ? implode('; ', $output) : '' . $output; + return strpos($line, '[behind') !== false; + } + + public static function gitPull() { + $cwd = getcwd(); + chdir(FRESHRSS_PATH); + $output = array(); + $return = 1; + try { + exec('git pull --ff-only', $output, $return); + } catch (Exception $e) { + Minz_Log::warning('git pull error:' . $e->getMessage()); + } + chdir($cwd); + $line = is_array($output) ? implode('; ', $output) : '' . $output; + return $return == 0 ? true : 'Git error: ' . $line; + } + public function firstAction() { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); @@ -20,7 +59,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function indexAction() { Minz_View::prependTitle(_t('admin.update.title') . ' · '); - if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) { + if (!is_writable(FRESHRSS_PATH)) { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), @@ -53,49 +92,65 @@ class FreshRSS_update_Controller extends Minz_ActionController { return; } - $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; - $c = curl_init($auto_update_url); - curl_setopt($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); - $result = curl_exec($c); - $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); - $c_error = curl_error($c); - curl_close($c); - - if ($c_status !== 200) { - Minz_Log::warning( - 'Error during update (HTTP code ' . $c_status . '): ' . $c_error - ); + $script = ''; + $version = ''; - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.update.server_not_found', $auto_update_url) - ); - return; - } - - $res_array = explode("\n", $result, 2); - $status = $res_array[0]; - if (strpos($status, 'UPDATE') !== 0) { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.update.none') - ); + if (self::isGit()) { + if (self::hasGitUpdate()) { + $version = 'git'; + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.none') + ); + @touch(join_path(DATA_PATH, 'last_update.txt')); + return; + } + } else { + $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; + Minz_Log::debug('HTTP GET ' . $auto_update_url); + $c = curl_init($auto_update_url); + curl_setopt($c, CURLOPT_RETURNTRANSFER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); + $result = curl_exec($c); + $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); + $c_error = curl_error($c); + curl_close($c); + + if ($c_status !== 200) { + Minz_Log::warning( + 'Error during update (HTTP code ' . $c_status . '): ' . $c_error + ); + + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.server_not_found', $auto_update_url) + ); + return; + } - @touch(join_path(DATA_PATH, 'last_update.txt')); + $res_array = explode("\n", $result, 2); + $status = $res_array[0]; + if (strpos($status, 'UPDATE') !== 0) { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.none') + ); + @touch(join_path(DATA_PATH, 'last_update.txt')); + return; + } - return; + $script = $res_array[1]; + $version = explode(' ', $status, 2); + $version = $version[1]; } - $script = $res_array[1]; if (file_put_contents(UPDATE_FILENAME, $script) !== false) { - $version = explode(' ', $status, 2); - $version = $version[1]; @file_put_contents(join_path(DATA_PATH, 'last_update.txt'), $version); - Minz_Request::forward(array('c' => 'update'), true); } else { $this->view->message = array( @@ -111,10 +166,13 @@ class FreshRSS_update_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'update'), true); } - require(UPDATE_FILENAME); - if (Minz_Request::param('post_conf', false)) { - $res = do_post_update(); + if (self::isGit()) { + $res = !self::hasGitUpdate(); + } else { + require(UPDATE_FILENAME); + $res = do_post_update(); + } Minz_ExtensionManager::callHook('post_update'); @@ -126,14 +184,21 @@ class FreshRSS_update_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.update.error', $res), array('c' => 'update', 'a' => 'index')); } - } - - if (Minz_Request::isPost()) { - save_info_update(); - } + } else { + $res = false; - if (!need_info_update()) { - $res = apply_update(); + if (self::isGit()) { + $res = self::gitPull(); + } else { + if (Minz_Request::isPost()) { + save_info_update(); + } + if (!need_info_update()) { + $res = apply_update(); + } else { + return; + } + } if ($res === true) { Minz_Request::forward(array( diff --git a/app/Models/Auth.php b/app/Models/Auth.php index b93942e19..b3255cfbd 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -25,7 +25,7 @@ class FreshRSS_Auth { self::giveAccess(); } elseif (self::accessControl()) { self::giveAccess(); - FreshRSS_UserDAO::touch($current_user); + FreshRSS_UserDAO::touch(); } else { // Be sure all accesses are removed! self::removeAccess(); @@ -219,8 +219,8 @@ class FreshRSS_FormAuth { } public static function makeCookie($username, $password_hash) { + $conf = Minz_Configuration::get('system'); do { - $conf = Minz_Configuration::get('system'); $token = sha1($conf->salt . $username . uniqid(mt_rand(), true)); $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; } while (file_exists($token_file)); @@ -229,15 +229,17 @@ class FreshRSS_FormAuth { return false; } - $expire = time() + 2629744; //1 month //TODO: Use a configuration instead + $limits = $conf->limits; + $cookie_duration = empty($limits['cookie_duration']) ? 2629744 : $limits['cookie_duration']; + $expire = time() + $cookie_duration; Minz_Session::setLongTermCookie('FreshRSS_login', $token, $expire); return $token; } public static function deleteCookie() { $token = Minz_Session::getLongTermCookie('FreshRSS_login'); - Minz_Session::deleteLongTermCookie('FreshRSS_login'); if (ctype_alnum($token)) { + Minz_Session::deleteLongTermCookie('FreshRSS_login'); @unlink(DATA_PATH . '/tokens/' . $token . '.txt'); } @@ -247,7 +249,10 @@ class FreshRSS_FormAuth { } public static function purgeTokens() { - $oldest = time() - 2629744; // 1 month // TODO: Use a configuration instead + $conf = Minz_Configuration::get('system'); + $limits = $conf->limits; + $cookie_duration = empty($limits['cookie_duration']) ? 2629744 : $limits['cookie_duration']; + $oldest = time() - $cookie_duration; foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) { // $extension = $file_info->getExtension(); doesn't work in PHP < 5.3.7 $extension = pathinfo($file_info->getFilename(), PATHINFO_EXTENSION); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 58f2c1a79..397471baa 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -241,6 +241,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (count($ids) < 1) { return 0; } + FreshRSS_UserDAO::touch(); $sql = 'UPDATE `' . $this->prefix . 'entry` ' . 'SET is_favorite=? ' . 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)'; @@ -315,6 +316,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markRead($ids, $is_read = true) { + FreshRSS_UserDAO::touch(); if (is_array($ids)) { //Many IDs at once (used by API) if (count($ids) < 6) { //Speed heuristics $affected = 0; @@ -379,6 +381,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); @@ -421,6 +424,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadCat($id, $idMax = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadCat(0) is deprecated!'); @@ -458,6 +462,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadFeed($id_feed, $idMax = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); @@ -513,7 +518,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm->execute($values); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $entries = self::daoToEntry($res); + $entries = self::daoToEntries($res); return isset($entries[0]) ? $entries[0] : null; } @@ -528,7 +533,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm->execute($values); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $entries = self::daoToEntry($res); + $entries = self::daoToEntries($res); return isset($entries[0]) ? $entries[0] : null; } @@ -661,7 +666,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + public function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $sql = 'SELECT e0.id, e0.guid, e0.title, e0.author, ' @@ -675,8 +680,12 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm = $this->bd->prepare($sql); $stm->execute($values); + return $stm; + } - return self::daoToEntry($stm->fetchAll(PDO::FETCH_ASSOC)); + public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + $stm = $this->listWhereRaw($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); + return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); } public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API @@ -805,15 +814,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $res[0]; } - public static function daoToEntry($listDAO) { - $list = array(); - - if (!is_array($listDAO)) { - $listDAO = array($listDAO); - } - - foreach ($listDAO as $key => $dao) { - $entry = new FreshRSS_Entry( + public static function daoToEntry($dao) { + $entry = new FreshRSS_Entry( $dao['id_feed'], $dao['guid'], $dao['title'], @@ -825,10 +827,21 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $dao['is_favorite'], $dao['tags'] ); - if (isset($dao['id'])) { - $entry->_id($dao['id']); - } - $list[] = $entry; + if (isset($dao['id'])) { + $entry->_id($dao['id']); + } + return $entry; + } + + private static function daoToEntries($listDAO) { + $list = array(); + + if (!is_array($listDAO)) { + $listDAO = array($listDAO); + } + + foreach ($listDAO as $key => $dao) { + $list[] = self::daoToEntry($dao); } unset($listDAO); diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 764987c46..6502c38b7 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -6,6 +6,7 @@ class FreshRSS_Factory { $conf = Minz_Configuration::get('system'); switch ($conf->db['type']) { case 'sqlite': + case 'pgsql': return new FreshRSS_FeedDAOSQLite($username); default: return new FreshRSS_FeedDAO($username); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index a95ee6bc4..32bc6de2f 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -84,7 +84,10 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return is_dir(join_path(DATA_PATH , 'users', $username)); } - public static function touch($username) { + public static function touch($username = '') { + if (($username == '') || (!ctype_alnum($username))) { + $username = Minz_Session::param('currentUser', '_'); + } return touch(join_path(DATA_PATH , 'users', $username, 'config.php')); } diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 84bc58a17..63cee3cca 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Tabulka kanálů je nastavena špatně.', 'ok' => 'Tabulka kanálů je v pořádku.', ), + 'fileinfo' => array( + 'nok' => 'Nemáte PHP fileinfo (balíček fileinfo).', + 'ok' => 'Máte rozšíření fileinfo.', + ), 'files' => 'Instalace souborů', 'json' => array( 'nok' => 'Nemáte JSON (balíček php5-json).', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index e73325c55..3db3a31da 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email', - 'keep_logged_in' => 'Zapamatovat přihlášení <small>(1 měsíc)</small>', + 'keep_logged_in' => 'Zapamatovat přihlášení <small>(%s dny)</small>', 'login' => 'Login', 'logout' => 'Odhlášení', 'password' => array( diff --git a/app/i18n/cz/install.php b/app/i18n/cz/install.php index c40ae46e2..ea4812ea5 100644 --- a/app/i18n/cz/install.php +++ b/app/i18n/cz/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/favicons</em>. HTTP server musí mít do tohoto adresáře práva zápisu', 'ok' => 'Oprávnění adresáře favicons jsou v pořádku.', ), + 'fileinfo' => array( + 'nok' => 'Nemáte PHP fileinfo (balíček fileinfo).', + 'ok' => 'Máte rozšíření fileinfo.', + ), 'http_referer' => array( 'nok' => 'Zkontrolujte prosím že neměníte HTTP REFERER.', 'ok' => 'Váš HTTP REFERER je znám a odpovídá Vašemu serveru.', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index c12f32bc8..8fc43a7bb 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Die Tabelle <em>feed</em> ist schlecht konfiguriert.', 'ok' => 'Die Tabelle <em>feed</em> ist korrekt konfiguriert.', ), + 'fileinfo' => array( + 'nok' => 'Ihnen fehlt PHP fileinfo (Paket fileinfo).', + 'ok' => 'Sie haben die fileinfo-Erweiterung.', + ), 'files' => 'Datei-Installation', 'json' => array( 'nok' => 'Ihnen fehlt die JSON-Erweiterung (Paket php5-json).', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index c6e7f1ef3..c73aedbfe 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'E-Mail-Adresse', - 'keep_logged_in' => 'Eingeloggt bleiben <small>(1 Monat)</small>', + 'keep_logged_in' => 'Eingeloggt bleiben <small>(%s Tage)</small>', 'login' => 'Anmelden', 'logout' => 'Abmelden', 'password' => array( diff --git a/app/i18n/de/install.php b/app/i18n/de/install.php index 178e8ea4c..b747d1551 100644 --- a/app/i18n/de/install.php +++ b/app/i18n/de/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/favicons</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/favicons</em> sind in Ordnung.', ), + 'fileinfo' => array( + 'nok' => 'Ihnen fehlt PHP fileinfo (Paket fileinfo).', + 'ok' => 'Sie haben die fileinfo-Erweiterung.', + ), 'http_referer' => array( 'nok' => 'Bitte stellen Sie sicher, dass Sie Ihren HTTP REFERER nicht abändern.', 'ok' => 'Ihr HTTP REFERER ist bekannt und entspricht Ihrem Server.', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index e5286d948..e94d9fa80 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Feed table is bad configured.', 'ok' => 'Feed table is ok.', ), + 'fileinfo' => array( + 'nok' => 'Cannot find the PHP fileinfo library (fileinfo package).', + 'ok' => 'You have the fileinfo library.', + ), 'files' => 'File installation', 'json' => array( 'nok' => 'Cannot find JSON (php5-json package).', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 17b47ba2f..3f86cfd19 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email address', - 'keep_logged_in' => 'Keep me logged in <small>(1 month)</small>', + 'keep_logged_in' => 'Keep me logged in <small>(%s days)</small>', 'login' => 'Login', 'logout' => 'Logout', 'password' => array( diff --git a/app/i18n/en/install.php b/app/i18n/en/install.php index 63d31fe53..40fff37dd 100644 --- a/app/i18n/en/install.php +++ b/app/i18n/en/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Check permissions on <em>./data/favicons</em> directory. HTTP server must have rights to write into', 'ok' => 'Permissions on favicons directory are good.', ), + 'fileinfo' => array( + 'nok' => 'Cannot find the PHP fileinfo library (fileinfo package).', + 'ok' => 'You have the fileinfo library.', + ), 'http_referer' => array( 'nok' => 'Please check that you are not altering your HTTP REFERER.', 'ok' => 'Your HTTP REFERER is known and corresponds to your server.', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index e9263a5e2..9a13ecc21 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'La table feed est mal configurée.', 'ok' => 'La table feed est bien configurée.', ), + 'fileinfo' => array( + 'nok' => 'Impossible de trouver la librairie PHP fileinfo (paquet fileinfo).', + 'ok' => 'Vous disposez de la librairie fileinfo.', + ), 'files' => 'Installation des fichiers', 'json' => array( 'nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index d61a716a7..b5dc098ae 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Adresse courriel', - 'keep_logged_in' => 'Rester connecté <small>(1 mois)</small>', + 'keep_logged_in' => 'Rester connecté <small>(%s jours)</small>', 'login' => 'Connexion', 'logout' => 'Déconnexion', 'password' => array( diff --git a/app/i18n/fr/install.php b/app/i18n/fr/install.php index c50807107..09625de78 100644 --- a/app/i18n/fr/install.php +++ b/app/i18n/fr/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Veuillez vérifier les droits sur le répertoire <em>./data/favicons</em>. Le serveur HTTP doit être capable d’écrire dedans', 'ok' => 'Les droits sur le répertoire des favicons sont bons.', ), + 'fileinfo' => array( + 'nok' => 'Vous ne disposez pas de PHP fileinfo (paquet fileinfo).', + 'ok' => 'Vous disposez de fileinfo.', + ), 'http_referer' => array( 'nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.', 'ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index c399bc8c8..ae46818ae 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'La tabella Feed ha una configurazione errata.', 'ok' => 'Tabella Feed OK.', ), + 'fileinfo' => array( + 'nok' => 'Manca il supporto per PHP fileinfo (pacchetto fileinfo).', + 'ok' => 'Estensione fileinfo presente.', + ), 'files' => 'Installazione files', 'json' => array( 'nok' => 'Manca il supoorto a JSON (pacchetto php5-json).', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index c02ddd13a..a9a8709d3 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Indirizzo email', - 'keep_logged_in' => 'Ricorda i dati <small>(1 mese)</small>', + 'keep_logged_in' => 'Ricorda i dati <small>(%s giorni)</small>', 'login' => 'Accedi', 'logout' => 'Esci', 'password' => array( diff --git a/app/i18n/it/install.php b/app/i18n/it/install.php index 2fa298508..18f8cc337 100644 --- a/app/i18n/it/install.php +++ b/app/i18n/it/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Verifica i permessi sulla cartella <em>./data/favicons</em>. Il server HTTP deve avere i permessi per scriverci dentro', 'ok' => 'I permessi sulla cartella favicons sono corretti.', ), + 'fileinfo' => array( + 'nok' => 'Manca il supporto per PHP fileinfo (pacchetto fileinfo).', + 'ok' => 'Estensione fileinfo presente.', + ), 'http_referer' => array( 'nok' => 'Per favore verifica che non stai alterando il tuo HTTP REFERER.', 'ok' => 'Il tuo HTTP REFERER riconosciuto corrisponde al tuo server.', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index 59637bfef..607fb1892 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Feed tabel is slecht geconfigureerd.', 'ok' => 'Feed tabel is ok.', ), + 'fileinfo' => array( + 'nok' => 'U mist de PHP fileinfo (fileinfo package).', + 'ok' => 'U hebt de fileinfo uitbreiding.', + ), 'files' => 'Bestanden installatie', 'json' => array( 'nok' => 'U mist JSON (php5-json package).', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 7e03229c9..83811ce68 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email adres', - 'keep_logged_in' => 'Ingelogd blijven voor <small>(1 maand)</small>', + 'keep_logged_in' => 'Ingelogd blijven voor <small>(%s dagen)</small>', 'login' => 'Log in', 'logout' => 'Log uit', 'password' => array( diff --git a/app/i18n/nl/install.php b/app/i18n/nl/install.php index bd2ba0cce..79db9c794 100644 --- a/app/i18n/nl/install.php +++ b/app/i18n/nl/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Controleer permissies van de <em>./data/favicons</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven', 'ok' => 'Permissies van de favicons map zijn goed.', ), + 'fileinfo' => array( + 'nok' => 'U mist PHP fileinfo (fileinfo package).', + 'ok' => 'U hebt de fileinfo uitbreiding.', + ), 'http_referer' => array( 'nok' => 'Controleer a.u.b. dat u niet uw HTTP REFERER wijzigd.', 'ok' => 'Uw HTTP REFERER is bekend en komt overeen met uw server.', diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php index 355100689..f5da97371 100644 --- a/app/i18n/ru/admin.php +++ b/app/i18n/ru/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Таблица подписок (feed) неправильно настроена.', 'ok' => 'Таблица подписок (feed) настроена правильно.', ), + 'fileinfo' => array( + 'nok' => 'У вас не установлено расширение PHP fileinfo (пакет fileinfo).', + 'ok' => 'У вас установлено расширение fileinfo.', + ), 'files' => 'Установка файлов', 'json' => array( 'nok' => 'У вас не установлена библиотека для работы с JSON (пакет php5-json).', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index eecd72749..bc42afaa8 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email address', - 'keep_logged_in' => 'Keep me logged in <small>(1 month)</small>', + 'keep_logged_in' => 'Keep me logged in <small>(%s дней)</small>', 'login' => 'Login', 'logout' => 'Logout', 'password' => array( diff --git a/app/i18n/ru/install.php b/app/i18n/ru/install.php index bad59bbb3..1dea2cd66 100644 --- a/app/i18n/ru/install.php +++ b/app/i18n/ru/install.php @@ -56,6 +56,10 @@ return array( 'nok' => 'Проверьте права доступа к папке <em>./data/favicons</em> . Сервер HTTP должен иметь права на запись в эту папку.', 'ok' => 'Права на папку значков в порядке.', ), + 'fileinfo' => array( + 'nok' => 'У вас нет расширения PHP fileinfo (пакет fileinfo).', + 'ok' => 'У вас установлено расширение fileinfo.', + ), 'http_referer' => array( 'nok' => 'Убедитесь, что вы не изменяете ваш HTTP REFERER.', 'ok' => 'Ваш HTTP REFERER известен и соотвествует вашему серверу.', diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php index e0dbd288d..9d10ef9dd 100644 --- a/app/i18n/tr/admin.php +++ b/app/i18n/tr/admin.php @@ -57,6 +57,10 @@ return array( 'nok' => 'Akış tablosu kötü yapılandırılmış.', 'ok' => 'Akış tablosu sorunsuz.', ), + 'fileinfo' => array( + 'nok' => 'PHP fileinfo eksik (fileinfo package).', + 'ok' => 'fileinfo eklentisi sorunsuz.', + ), 'files' => 'Dosya kurulumu', 'json' => array( 'nok' => 'JSON eklentisi eksik (php5-json package).', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 865dbd4e2..bcc839daf 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email adresleri', - 'keep_logged_in' => '<small>(1 ay)</small> oturumu açık tut', + 'keep_logged_in' => '<small>(%s günler)</small> oturumu açık tut', 'login' => 'Giriş', 'logout' => 'Çıkış', 'password' => array( diff --git a/app/i18n/tr/install.php b/app/i18n/tr/install.php index 4daa45099..d5564297b 100644 --- a/app/i18n/tr/install.php +++ b/app/i18n/tr/install.php @@ -56,6 +56,10 @@ return array( 'nok' => '<em>./data/favicons</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı', 'ok' => 'Site ikonu klasörü yetkileri sorunsuz.', ), + 'fileinfo' => array( + 'nok' => 'PHP fileinfo eksik (fileinfo package).', + 'ok' => 'fileinfo eklentisi sorunsuz.', + ), 'http_referer' => array( 'nok' => 'Lütfen HTTP REFERER değiştirmediğinize emin olun.', 'ok' => 'HTTP REFERER ve sunucunuz arası iletişim sorunsuz.', diff --git a/app/install.php b/app/install.php index fcc901713..986a7dc60 100644 --- a/app/install.php +++ b/app/install.php @@ -230,7 +230,7 @@ function saveStep3() { $_SESSION['bd_error'] = ''; header('Location: index.php?step=4'); } else { - $_SESSION['bd_error'] = empty($config_array['db']['bd_error']) ? 'Unknown error!' : $config_array['db']['bd_error']; + $_SESSION['bd_error'] = empty($config_array['db']['error']) ? 'Unknown error!' : $config_array['db']['error']; } } invalidateHttpCache(); @@ -375,7 +375,7 @@ function checkDbUser(&$dbOptions) { } } catch (PDOException $e) { $ok = false; - $dbOptions['bd_error'] = $e->getMessage(); + $dbOptions['error'] = $e->getMessage(); } return $ok; } @@ -478,6 +478,12 @@ function printStep1() { <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.xml.nok'); ?></p> <?php } ?> + <?php if ($res['fileinfo'] == 'ok') { ?> + <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.fileinfo.ok'); ?></p> + <?php } else { ?> + <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.fileinfo.nok'); ?></p> + <?php } ?> + <?php if ($res['data'] == 'ok') { ?> <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.data.ok'); ?></p> <?php } else { ?> @@ -634,7 +640,7 @@ function printStep3() { <div class="form-group"> <label class="group-name" for="host"><?php echo _t('install.bdd.host'); ?></label> <div class="group-controls"> - <input type="text" id="host" name="host" pattern="[0-9A-Za-z_.-]{1,64}(:[0-9]{2,5})?" value="<?php echo isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : $system_default_config->db['host']; ?>" tabindex="2" /> + <input type="text" id="host" name="host" pattern="[0-9A-Z/a-z_.-]{1,64}(:[0-9]{2,5})?" value="<?php echo isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : $system_default_config->db['host']; ?>" tabindex="2" /> </div> </div> diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index 4bbc8ed55..a8213b7ae 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -20,7 +20,7 @@ <div> <label class="checkbox" for="keep_logged_in"> <input type="checkbox" name="keep_logged_in" id="keep_logged_in" value="1" /> - <?php echo _t('gen.auth.keep_logged_in'); ?> + <?php echo _t('gen.auth.keep_logged_in', $this->cookie_days); ?> </label> <br /> </div> diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index ffdca1daa..49c370023 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -1,47 +1,66 @@ <?php - $username = Minz_Session::param('currentUser', '_'); +$username = Minz_Session::param('currentUser', '_'); - $articles = array( - 'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type, - 'title' => $this->list_title, - 'author' => $username, - 'items' => array() - ); +$options = 0; +if (version_compare(PHP_VERSION, '5.4.0') >= 0) { + $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; +} - foreach ($this->entries as $entry) { - if (!isset($this->feed)) { - $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed ()); - } else { - $feed = $this->feed; - } +$articles = array( + 'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type, + 'title' => $this->list_title, + 'author' => $username, + 'items' => array(), +); - $articles['items'][] = array( - 'id' => $entry->guid(), - 'categories' => array_values($entry->tags()), - 'title' => $entry->title(), - 'author' => $entry->author(), - 'published' => $entry->date(true), - 'updated' => $entry->date(true), - 'alternate' => array(array( - 'href' => $entry->link(), - 'type' => 'text/html' - )), - 'content' => array( - 'content' => $entry->content() - ), - 'origin' => array( - 'streamId' => $feed->id(), - 'title' => $feed->name(), - 'htmlUrl' => $feed->website(), - 'feedUrl' => $feed->url() - ) - ); - } +echo rtrim(json_encode($articles, $options), " ]}\n\r\t"), "\n"; +$first = true; - $options = 0; - if (version_compare(PHP_VERSION, '5.4.0') >= 0) { - $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - } +foreach ($this->entriesRaw as $entryRaw) { + if (empty($entryRaw)) { + continue; + } + $entry = FreshRSS_EntryDAO::daoToEntry($entryRaw); + if (!isset($this->feed)) { + $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed()); + if ($feed == null) { + $feed = $entry->feed(true); + } + } else { + $feed = $this->feed; + } - echo json_encode($articles, $options); -?> + $article = array( + 'id' => $entry->guid(), + 'categories' => array_values($entry->tags()), + 'title' => $entry->title(), + 'author' => $entry->author(), + 'published' => $entry->date(true), + 'updated' => $entry->date(true), + 'alternate' => array(array( + 'href' => $entry->link(), + 'type' => 'text/html', + )), + 'content' => array( + 'content' => $entry->content(), + ), + 'origin' => array( + 'streamId' => $feed == null ? '' : $feed->id(), + 'title' => $feed == null ? '' : $feed->name(), + 'htmlUrl' => $feed == null ? '' : $feed->website(), + 'feedUrl' => $feed == null ? '' : $feed->url(), + ) + ); + + $line = json_encode($article, $options); + if ($line != '') { + if ($first) { + $first = false; + } else { + echo ",\n"; + } + echo $line; + } +} + +echo "\n]}\n"; diff --git a/cli/README.md b/cli/README.md index 444606b50..e4d3409a2 100644 --- a/cli/README.md +++ b/cli/README.md @@ -32,11 +32,11 @@ Options in parenthesis are optional. ```sh cd /usr/share/FreshRSS -./cli/do-install.php --default_user admin --auth_type form ( --environment production --base_url https://rss.example.net/ --title FreshRSS --allow_anonymous --api_enabled --db-type mysql --db-host localhost:3306 --db-user freshrss --db-password dbPassword123 --db-base freshrss --db-prefix freshrss ) -# --auth_type can be: 'form' (recommended), 'http_auth' (using the Web server access control), 'none' (dangerous) +./cli/do-install.php --default_user admin ( --auth_type form --environment production --base_url https://rss.example.net/ --title FreshRSS --allow_anonymous --api_enabled --db-type mysql --db-host localhost:3306 --db-user freshrss --db-password dbPassword123 --db-base freshrss --db-prefix freshrss ) +# --auth_type can be: 'form' (default), 'http_auth' (using the Web server access control), 'none' (dangerous) # --db-type can be: 'sqlite' (default), 'mysql' (MySQL or MariaDB), 'pgsql' (PostgreSQL) # --environment can be: 'production' (default), 'development' (for additional log messages) -# --db-prefix is an optional prefix in front of the names of the tables +# --db-prefix is an optional prefix in front of the names of the tables. We suggest using 'freshrss_' # This command does not create the default user. Do that with ./cli/create-user.php ./cli/create-user.php --user username ( --password 'password' --api-password 'api_password' --language en --email user@example.net --token 'longRandomString' --no-default-feeds ) @@ -55,4 +55,26 @@ cd /usr/share/FreshRSS ./cli/export-opml-for-user.php --user username > /path/to/file.opml.xml ./cli/export-zip-for-user.php --user username ( --max-feed-entries 100 ) > /path/to/file.zip + +./cli/user-info.php -h --user username +# -h is to use a human-readable format +# --user can be a username, or '*' to loop on all users +# Returns a * if the user is admin, the name of the user, the date/time of last action, and the size occupied +``` + + +## Unix piping + +It is possible to invoke a command multiple times, e.g. with different usernames, thanks to the `xargs -n1` command. + +Example showing user information for all users which username starts with 'a': + +```sh +./cli/list-users.php | grep '^a' | xargs -n1 ./cli/user-info.php -h --user +``` + +Example showing all users ranked by date of last activity: + +```sh +./cli/user-info.php -h --user '*' | sort -k2 -r ``` diff --git a/cli/create-user.php b/cli/create-user.php index 008b82ce3..444264cc7 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -43,6 +43,9 @@ if (!$ok) { invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); +echo '• Remember to refresh the feeds of the user: ', $username , "\n", + "\t", './cli/actualize-user.php --user ', $username, "\n"; + accessRights(); done($ok); diff --git a/cli/do-install.php b/cli/do-install.php index 667191680..100d4947f 100755 --- a/cli/do-install.php +++ b/cli/do-install.php @@ -26,12 +26,12 @@ $dBparams = array( $options = getopt('', array_merge($params, $dBparams)); -if (empty($options['default_user']) || empty($options['auth_type'])) { - fail('Usage: ' . basename(__FILE__) . " --default_user admin --auth_type form" . - " ( --environment production --base_url https://rss.example.net/" . +if (empty($options['default_user'])) { + fail('Usage: ' . basename(__FILE__) . " --default_user admin ( --auth_type form" . + " --environment production --base_url https://rss.example.net/" . " --title FreshRSS --allow_anonymous --api_enabled" . " --db-type mysql --db-host localhost:3306 --db-user freshrss --db-password dbPassword123" . - " --db-base freshrss --db-prefix freshrss )"); + " --db-base freshrss --db-prefix freshrss_ )"); } fwrite(STDERR, 'FreshRSS install…' . "\n"); @@ -51,7 +51,7 @@ if (!ctype_alnum($options['default_user'])) { fail('FreshRSS invalid default username (must be ASCII alphanumeric): ' . $options['default_user']); } -if (!in_array($options['auth_type'], array('form', 'http_auth', 'none'))) { +if (isset($options['auth_type']) && !in_array($options['auth_type'], array('form', 'http_auth', 'none'))) { fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none }: ' . $options['auth_type']); } @@ -86,11 +86,11 @@ if (file_put_contents(join_path(DATA_PATH, 'config.php'), "<?php\n return " . va $config['db']['default_user'] = $config['default_user']; if (!checkDb($config['db'])) { @unlink(join_path(DATA_PATH, 'config.php')); - fail('FreshRSS database error: ' . (empty($config['db']['bd_error']) ? 'Unknown error' : $config['db']['bd_error'])); + fail('FreshRSS database error: ' . (empty($config['db']['error']) ? 'Unknown error' : $config['db']['error'])); } echo '• Remember to create the default user: ', $config['default_user'] , "\n", - "\t", './cli/create-user.php --user ', $config['default_user'] , " --password 'password' --more-options\n"; + "\t", './cli/create-user.php --user ', $config['default_user'], " --password 'password' --more-options\n"; accessRights(); diff --git a/cli/user-info.php b/cli/user-info.php new file mode 100755 index 000000000..dd38e6c7f --- /dev/null +++ b/cli/user-info.php @@ -0,0 +1,35 @@ +#!/usr/bin/php +<?php +require('_cli.php'); + +$options = getopt('h', array( + 'user:', + )); + +if (empty($options['user'])) { + fail('Usage: ' . basename(__FILE__) . " -h --user username"); +} + +$users = $options['user'] === '*' ? listUsers() : array($options['user']); + +foreach ($users as $username) { + $username = cliInitUser($username); + + $entryDAO = FreshRSS_Factory::createEntryDao($username); + + echo $username === FreshRSS_Context::$system_conf->default_user ? '*' : ' ', "\t"; + + if (isset($options['h'])) { //Human format + echo + $username, "\t", + date('c', FreshRSS_UserDAO::mtime($username)), "\t", + format_bytes($entryDAO->size()), "\t", + "\n"; + } else { + echo + $username, "\t", + FreshRSS_UserDAO::mtime($username), "\t", + $entryDAO->size(), "\t", + "\n"; + } +} diff --git a/constants.php b/constants.php index e5ae3ff00..cb00839e2 100644 --- a/constants.php +++ b/constants.php @@ -1,5 +1,5 @@ <?php -define('FRESHRSS_VERSION', '1.6.1'); +define('FRESHRSS_VERSION', '1.6.2'); define('FRESHRSS_WEBSITE', 'http://freshrss.org'); define('FRESHRSS_WIKI', 'http://doc.freshrss.org'); diff --git a/data/config.default.php b/data/config.default.php index d3cd3bf22..433207a9c 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -46,7 +46,7 @@ return array( # `http_auth` is an access controled by the HTTP Web server (e.g. `/FreshRSS/p/i/.htaccess` for Apache) # if you use `http_auth`, remember to protect only `/FreshRSS/p/i/`, # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). - 'auth_type' => 'none', + 'auth_type' => 'form', # Allow or not the use of the API, used for mobile apps. # End-point is http://example.net/FreshRSS/p/api/greader.php @@ -74,6 +74,9 @@ return array( 'limits' => array( + # Duration in seconds of the login cookie. + 'cookie_duration' => 2592000, + # Duration in seconds of the SimplePie cache, # during which a query to the RSS feed will return the local cached version. # Especially important for multi-user setups. diff --git a/extensions/README.md b/extensions/README.md index 4c1a81f5c..62766d6f2 100644 --- a/extensions/README.md +++ b/extensions/README.md @@ -1,3 +1,5 @@ # FreshRSS extensions -You may place in this directory some custom extensions for FreshRSS. +You may place custom extensions for FreshRSS in this directory. + +You can find some extensions in our [GitHub repository](https://github.com/FreshRSS/Extensions). diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 6e8d60bc9..caab1d114 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -116,6 +116,12 @@ class Minz_ModelPdo { self::$sharedBd = null; self::$sharedPrefix = ''; } + + public function disableBuffering() { + if ((self::$sharedDbType === 'mysql') && defined('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY')) { + $this->bd->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + } + } } class MinzPDO extends PDO { diff --git a/lib/favicons.php b/lib/favicons.php index 6709f6745..d8c97964e 100644 --- a/lib/favicons.php +++ b/lib/favicons.php @@ -9,7 +9,7 @@ $default_favicon = PUBLIC_PATH . '/themes/icons/default_favicon.ico'; function download_favicon($website, $dest) { global $favicons_dir, $default_favicon; - syslog(LOG_DEBUG, 'FreshRSS Favicon discovery GET ' . $website); + syslog(LOG_INFO, 'FreshRSS Favicon discovery GET ' . $website); $favicon_getter = new \Favicon\Favicon(); $favicon_getter->setCacheDir($favicons_dir); $favicon_url = $favicon_getter->get($website); @@ -18,11 +18,12 @@ function download_favicon($website, $dest) { return @copy($default_favicon, $dest); } - syslog(LOG_DEBUG, 'FreshRSS Favicon GET ' . $favicon_url); + syslog(LOG_INFO, 'FreshRSS Favicon GET ' . $favicon_url); $c = curl_init($favicon_url); curl_setopt($c, CURLOPT_HEADER, false); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_BINARYTRANSFER, true); + curl_setopt($c, CURLOPT_USERAGENT, 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')'); $img_raw = curl_exec($c); $status_code = curl_getinfo($c, CURLINFO_HTTP_CODE); curl_close($c); @@ -34,6 +35,8 @@ function download_favicon($website, $dest) { fclose($file); return true; } + } else { + syslog(LOG_WARNING, 'FreshRSS Favicon GET ' . $favicon_url . ' error ' . $status_code); } return false; diff --git a/lib/lib_install.php b/lib/lib_install.php index 0e7b7f036..c5cae4293 100644 --- a/lib/lib_install.php +++ b/lib/lib_install.php @@ -15,6 +15,7 @@ function checkRequirements() { $pdo = $pdo_mysql || $pdo_sqlite || $pdo_pgsql; $pcre = extension_loaded('pcre'); $ctype = extension_loaded('ctype'); + $fileinfo = extension_loaded('fileinfo'); $dom = class_exists('DOMDocument'); $xml = function_exists('xml_parser_create'); $json = function_exists('json_encode'); @@ -34,6 +35,7 @@ function checkRequirements() { 'pdo' => $pdo ? 'ok' : 'ko', 'pcre' => $pcre ? 'ok' : 'ko', 'ctype' => $ctype ? 'ok' : 'ko', + 'fileinfo' => $fileinfo ? 'ok' : 'ko', 'dom' => $dom ? 'ok' : 'ko', 'xml' => $xml ? 'ok' : 'ko', 'json' => $json ? 'ok' : 'ko', @@ -42,7 +44,7 @@ function checkRequirements() { 'users' => $users ? 'ok' : 'ko', 'favicons' => $favicons ? 'ok' : 'ko', 'http_referer' => $http_referer ? 'ok' : 'ko', - 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && + 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $fileinfo && $dom && $xml && $data && $cache && $users && $favicons && $http_referer ? 'ok' : 'ko' ); @@ -54,8 +56,8 @@ function generateSalt() { function checkDb(&$dbOptions) { $dsn = ''; + $driver_options = null; try { - $driver_options = null; switch ($dbOptions['type']) { case 'mysql': include_once(APP_PATH . '/SQL/install.sql.mysql.php'); @@ -99,8 +101,12 @@ function checkDb(&$dbOptions) { default: return false; } + + $c = new PDO($dsn, $dbOptions['user'], $dbOptions['password'], $driver_options); + $res = $c->query('SELECT 1'); } catch (PDOException $e) { $dsn = ''; + syslog(LOG_DEBUG, 'FreshRSS SQL warning: ' . $e->getMessage()); $dbOptions['error'] = $e->getMessage(); } $dbOptions['dsn'] = $dsn; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 143b55bee..560e5b256 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -127,6 +127,8 @@ function format_bytes($bytes, $precision = 2, $system = 'IEC') { } elseif ($system === 'SI') { $base = 1000; $units = array('B', 'KB', 'MB', 'GB', 'TB'); + } else { + return format_number($bytes, $precision); } $bytes = max(intval($bytes), 0); $pow = $bytes === 0 ? 0 : floor(log($bytes) / log($base)); @@ -396,6 +398,7 @@ function check_install_php() { 'pdo' => $pdo_mysql || $pdo_sqlite, 'pcre' => extension_loaded('pcre'), 'ctype' => extension_loaded('ctype'), + 'fileinfo' => extension_loaded('fileinfo'), 'dom' => class_exists('DOMDocument'), 'json' => extension_loaded('json'), 'zip' => extension_loaded('zip'), diff --git a/p/scripts/main.js b/p/scripts/main.js index 078bec682..14e0c5be5 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1354,7 +1354,6 @@ function init_beforeDOM() { window.setTimeout(init_beforeDOM, 100); return; } - init_confirm_action(); if (['normal', 'reader', 'global'].indexOf(context.current_view) >= 0) { inject_script('jquery.sticky-kit.min.js'); init_normal(); @@ -1372,6 +1371,7 @@ function init_afterDOM() { init_notifications(); $stream = $('#stream'); if ($stream.length > 0) { + init_confirm_action(); init_load_more($stream); init_posts(); init_nav_entries(); |
