diff options
| author | 2014-10-31 16:57:11 +0100 | |
|---|---|---|
| committer | 2014-10-31 16:57:11 +0100 | |
| commit | 54479a5027d83b5dc8deee5e2795c9d89c732ba0 (patch) | |
| tree | 7ae55930f3ab6d5e2a548784e4d7561809f7c68c /app/Models | |
| parent | cff8636e770b2072a41928cd918b37654c0dafbb (diff) | |
| parent | 724e13f0a6419b046b33da71e66058e279551edd (diff) | |
Merge branch 'dev' into beta
Conflicts:
CHANGELOG
README.fr.md
README.md
app/Controllers/feedController.php
app/Controllers/indexController.php
app/i18n/en.php
app/i18n/fr.php
app/views/helpers/view/normal_view.phtml
app/views/stats/index.phtml
app/views/stats/repartition.phtml
constants.php
p/scripts/main.js
Diffstat (limited to 'app/Models')
| -rw-r--r-- | app/Models/Auth.php | 232 | ||||
| -rw-r--r-- | app/Models/Category.php | 44 | ||||
| -rw-r--r-- | app/Models/CategoryDAO.php | 170 | ||||
| -rw-r--r-- | app/Models/Configuration.php | 58 | ||||
| -rw-r--r-- | app/Models/Context.php | 268 | ||||
| -rw-r--r-- | app/Models/DatabaseDAO.php | 83 | ||||
| -rw-r--r-- | app/Models/DatabaseDAOSQLite.php | 48 | ||||
| -rw-r--r-- | app/Models/Entry.php | 141 | ||||
| -rw-r--r-- | app/Models/EntryDAO.php | 103 | ||||
| -rw-r--r-- | app/Models/EntryDAOSQLite.php | 16 | ||||
| -rw-r--r-- | app/Models/Factory.php | 27 | ||||
| -rw-r--r-- | app/Models/Feed.php | 3 | ||||
| -rw-r--r-- | app/Models/FeedDAO.php | 22 | ||||
| -rw-r--r-- | app/Models/FeedDAOSQLite.php | 2 | ||||
| -rw-r--r-- | app/Models/Log.php | 12 | ||||
| -rw-r--r-- | app/Models/LogDAO.php | 10 | ||||
| -rw-r--r-- | app/Models/StatsDAO.php | 6 | ||||
| -rw-r--r-- | app/Models/Themes.php | 1 | ||||
| -rw-r--r-- | app/Models/UserDAO.php | 20 |
19 files changed, 957 insertions, 309 deletions
diff --git a/app/Models/Auth.php b/app/Models/Auth.php new file mode 100644 index 000000000..2971d65c8 --- /dev/null +++ b/app/Models/Auth.php @@ -0,0 +1,232 @@ +<?php + +/** + * This class handles all authentication process. + */ +class FreshRSS_Auth { + /** + * Determines if user is connected. + */ + private static $login_ok = false; + + /** + * This method initializes authentication system. + */ + public static function init() { + self::$login_ok = Minz_Session::param('loginOk', false); + $current_user = Minz_Session::param('currentUser', ''); + if ($current_user === '') { + $current_user = Minz_Configuration::defaultUser(); + Minz_Session::_param('currentUser', $current_user); + } + + if (self::$login_ok) { + self::giveAccess(); + } elseif (self::accessControl()) { + self::giveAccess(); + FreshRSS_UserDAO::touch($current_user); + } else { + // Be sure all accesses are removed! + self::removeAccess(); + } + } + + /** + * This method checks if user is allowed to connect. + * + * Required session parameters are also set in this method (such as + * currentUser). + * + * @return boolean true if user can be connected, false else. + */ + private static function accessControl() { + switch (Minz_Configuration::authType()) { + case 'form': + $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); + $current_user = ''; + if (isset($credentials[1])) { + $current_user = trim($credentials[0]); + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('passwordHash', trim($credentials[1])); + } + return $current_user != ''; + case 'http_auth': + $current_user = httpAuthUser(); + $login_ok = $current_user != ''; + if ($login_ok) { + Minz_Session::_param('currentUser', $current_user); + } + return $login_ok; + case 'persona': + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + return true; + } + return false; + case 'none': + return true; + default: + // TODO load extension + return false; + } + } + + /** + * Gives access to the current user. + */ + public static function giveAccess() { + $current_user = Minz_Session::param('currentUser'); + try { + $conf = new FreshRSS_Configuration($current_user); + } catch(Minz_Exception $e) { + die($e->getMessage()); + } + + switch (Minz_Configuration::authType()) { + case 'form': + self::$login_ok = Minz_Session::param('passwordHash') === $conf->passwordHash; + break; + case 'http_auth': + self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; + break; + case 'persona': + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + break; + case 'none': + self::$login_ok = true; + break; + default: + // TODO: extensions + self::$login_ok = false; + } + + Minz_Session::_param('loginOk', self::$login_ok); + } + + /** + * Returns if current user has access to the given scope. + * + * @param string $scope general (default) or admin + * @return boolean true if user has corresponding access, false else. + */ + public static function hasAccess($scope = 'general') { + $ok = self::$login_ok; + switch ($scope) { + case 'general': + break; + case 'admin': + $ok &= Minz_Session::param('currentUser') === Minz_Configuration::defaultUser(); + break; + default: + $ok = false; + } + return $ok; + } + + /** + * Removes all accesses for the current user. + */ + public static function removeAccess() { + Minz_Session::_param('loginOk'); + self::$login_ok = false; + Minz_Session::_param('currentUser', Minz_Configuration::defaultUser()); + + switch (Minz_Configuration::authType()) { + case 'form': + Minz_Session::_param('passwordHash'); + FreshRSS_FormAuth::deleteCookie(); + break; + case 'persona': + Minz_Session::_param('mail'); + break; + case 'http_auth': + case 'none': + // Nothing to do... + break; + default: + // TODO: extensions + } + } +} + + +class FreshRSS_FormAuth { + public static function checkCredentials($username, $hash, $nonce, $challenge) { + if (!ctype_alnum($username) || + !ctype_graph($challenge) || + !ctype_alnum($nonce)) { + Minz_Log::debug('Invalid credential parameters:' . + ' user=' . $username . + ' challenge=' . $challenge . + ' nonce=' . $nonce); + return false; + } + + if (!function_exists('password_verify')) { + include_once(LIB_PATH . '/password_compat.php'); + } + + return password_verify($nonce . $hash, $challenge); + } + + public static function getCredentialsFromCookie() { + $token = Minz_Session::getLongTermCookie('FreshRSS_login'); + if (!ctype_alnum($token)) { + return array(); + } + + $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; + $mtime = @filemtime($token_file); + if ($mtime + 2629744 < time()) { + // Token has expired (> 1 month) or does not exist. + // TODO: 1 month -> use a configuration instead + @unlink($token_file); + return array(); + } + + $credentials = @file_get_contents($token_file); + return $credentials === false ? array() : explode("\t", $credentials, 2); + } + + public static function makeCookie($username, $password_hash) { + do { + $token = sha1(Minz_Configuration::salt() . $username . uniqid(mt_rand(), true)); + $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; + } while (file_exists($token_file)); + + if (@file_put_contents($token_file, $username . "\t" . $password_hash) === false) { + return false; + } + + $expire = time() + 2629744; //1 month //TODO: Use a configuration instead + 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)) { + @unlink(DATA_PATH . '/tokens/' . $token . '.txt'); + } + + if (rand(0, 10) === 1) { + self::purgeTokens(); + } + } + + public static function purgeTokens() { + $oldest = time() - 2629744; // 1 month // TODO: Use a configuration instead + 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); + if ($extension === 'txt' && $file_info->getMTime() < $oldest) { + @unlink($file_info->getPathname()); + } + } + } +} diff --git a/app/Models/Category.php b/app/Models/Category.php index 0a0dbd3ca..37cb44dc3 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -7,65 +7,65 @@ class FreshRSS_Category extends Minz_Model { private $nbNotRead = -1; private $feeds = null; - public function __construct ($name = '', $feeds = null) { - $this->_name ($name); - if (isset ($feeds)) { - $this->_feeds ($feeds); + public function __construct($name = '', $feeds = null) { + $this->_name($name); + if (isset($feeds)) { + $this->_feeds($feeds); $this->nbFeed = 0; $this->nbNotRead = 0; foreach ($feeds as $feed) { $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); + $this->nbNotRead += $feed->nbNotRead(); } } } - public function id () { + public function id() { return $this->id; } - public function name () { + public function name() { return $this->name; } - public function nbFeed () { + public function nbFeed() { if ($this->nbFeed < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbFeed = $catDAO->countFeed ($this->id ()); + $catDAO = new FreshRSS_CategoryDAO(); + $this->nbFeed = $catDAO->countFeed($this->id()); } return $this->nbFeed; } - public function nbNotRead () { + public function nbNotRead() { if ($this->nbNotRead < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbNotRead = $catDAO->countNotRead ($this->id ()); + $catDAO = new FreshRSS_CategoryDAO(); + $this->nbNotRead = $catDAO->countNotRead($this->id()); } return $this->nbNotRead; } - public function feeds () { + public function feeds() { if ($this->feeds === null) { $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->feeds = $feedDAO->listByCategory ($this->id ()); + $this->feeds = $feedDAO->listByCategory($this->id()); $this->nbFeed = 0; $this->nbNotRead = 0; foreach ($this->feeds as $feed) { $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); + $this->nbNotRead += $feed->nbNotRead(); } } return $this->feeds; } - public function _id ($value) { + public function _id($value) { $this->id = $value; } - public function _name ($value) { - $this->name = $value; + public function _name($value) { + $this->name = substr(trim($value), 0, 255); } - public function _feeds ($values) { - if (!is_array ($values)) { - $values = array ($values); + public function _feeds($values) { + if (!is_array($values)) { + $values = array($values); } $this->feeds = $values; diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index f11f87f47..2e333d2f1 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -1,19 +1,19 @@ <?php class FreshRSS_CategoryDAO extends Minz_ModelPdo { - public function addCategory ($valuesTmp) { - $sql = 'INSERT INTO `' . $this->prefix . 'category` (name) VALUES(?)'; - $stm = $this->bd->prepare ($sql); + public function addCategory($valuesTmp) { + $sql = 'INSERT INTO `' . $this->prefix . 'category`(name) VALUES(?)'; + $stm = $this->bd->prepare($sql); - $values = array ( + $values = array( substr($valuesTmp['name'], 0, 255), ); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error addCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error addCategory: ' . $info[2] ); return false; } } @@ -31,73 +31,73 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $cat->id(); } - public function updateCategory ($id, $valuesTmp) { + public function updateCategory($id, $valuesTmp) { $sql = 'UPDATE `' . $this->prefix . 'category` SET name=? WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ( + $values = array( $valuesTmp['name'], $id ); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCategory: ' . $info[2]); return false; } } - public function deleteCategory ($id) { + public function deleteCategory($id) { $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($id); + $values = array($id); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteCategory: ' . $info[2]); return false; } } - public function searchById ($id) { + public function searchById($id) { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($id); + $values = array($id); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return null; } } - public function searchByName ($name) { + public function searchByName($name) { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE name=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($name); + $values = array($name); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return null; } } - public function listCategories ($prePopulateFeeds = true, $details = false) { + public function listCategories($prePopulateFeeds = true, $details = false) { if ($prePopulateFeeds) { $sql = 'SELECT c.id AS c_id, c.name AS c_name, ' . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ') @@ -105,80 +105,80 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { . '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 self::daoToCategoryPrepopulated ($stm->fetchAll (PDO::FETCH_ASSOC)); + $stm = $this->bd->prepare($sql); + $stm->execute(); + return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC)); } else { $sql = 'SELECT * FROM `' . $this->prefix . 'category` ORDER BY name'; - $stm = $this->bd->prepare ($sql); - $stm->execute (); - return self::daoToCategory ($stm->fetchAll (PDO::FETCH_ASSOC)); + $stm = $this->bd->prepare($sql); + $stm->execute(); + return self::daoToCategory($stm->fetchAll(PDO::FETCH_ASSOC)); } } - public function getDefault () { + public function getDefault() { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=1'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $stm->execute (); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return false; } } - public function checkDefault () { - $def_cat = $this->searchById (1); + public function checkDefault() { + $def_cat = $this->searchById(1); if ($def_cat == null) { - $cat = new FreshRSS_Category (Minz_Translate::t ('default_category')); - $cat->_id (1); + $cat = new FreshRSS_Category(_t('default_category')); + $cat->_id(1); - $values = array ( - 'id' => $cat->id (), - 'name' => $cat->name (), + $values = array( + 'id' => $cat->id(), + 'name' => $cat->name(), ); - $this->addCategory ($values); + $this->addCategory($values); } } - public function count () { + 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); + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); return $res[0]['count']; } - public function countFeed ($id) { + 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); + $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) { + 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); + $stm = $this->bd->prepare($sql); + $values = array($id); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); return $res[0]['count']; } public static function findFeed($categories, $feed_id) { foreach ($categories as $category) { - foreach ($category->feeds () as $feed) { - if ($feed->id () === $feed_id) { + foreach ($category->feeds() as $feed) { + if ($feed->id() === $feed_id) { return $feed; } } @@ -189,8 +189,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { public static function CountUnreads($categories, $minPriority = 0) { $n = 0; foreach ($categories as $category) { - foreach ($category->feeds () as $feed) { - if ($feed->priority () >= $minPriority) { + foreach ($category->feeds() as $feed) { + if ($feed->priority() >= $minPriority) { $n += $feed->nbNotRead(); } } @@ -198,11 +198,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $n; } - public static function daoToCategoryPrepopulated ($listDAO) { - $list = array (); + public static function daoToCategoryPrepopulated($listDAO) { + $list = array(); - if (!is_array ($listDAO)) { - $listDAO = array ($listDAO); + if (!is_array($listDAO)) { + $listDAO = array($listDAO); } $previousLine = null; @@ -210,11 +210,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { 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 ( + $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) ); - $cat->_id ($previousLine['c_id']); + $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; $feedsDao = array(); //Prepare for next category @@ -226,29 +226,29 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { // add the last category if ($previousLine != null) { - $cat = new FreshRSS_Category ( + $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) ); - $cat->_id ($previousLine['c_id']); + $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; } return $list; } - public static function daoToCategory ($listDAO) { - $list = array (); + public static function daoToCategory($listDAO) { + $list = array(); - if (!is_array ($listDAO)) { - $listDAO = array ($listDAO); + if (!is_array($listDAO)) { + $listDAO = array($listDAO); } foreach ($listDAO as $key => $dao) { - $cat = new FreshRSS_Category ( + $cat = new FreshRSS_Category( $dao['name'] ); - $cat->_id ($dao['id']); + $cat->_id($dao['id']); $list[$key] = $cat; } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 95f819779..53f136513 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -14,7 +14,8 @@ class FreshRSS_Configuration { 'apiPasswordHash' => '', //CRYPT_BLOWFISH 'posts_per_page' => 20, 'view_mode' => 'normal', - 'default_view' => FreshRSS_Entry::STATE_NOT_READ, + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, 'auto_load_more' => true, 'display_posts' => false, 'display_categories' => false, @@ -47,6 +48,7 @@ class FreshRSS_Configuration { 'focus_search' => 'a', 'user_filter' => 'u', 'help' => 'f1', + 'close_dropdown' => 'escape', ), 'topline_read' => true, 'topline_favorite' => true, @@ -139,44 +141,48 @@ class FreshRSS_Configuration { } $this->data['language'] = $value; } - public function _posts_per_page ($value) { + public function _posts_per_page($value) { $value = intval($value); $this->data['posts_per_page'] = $value > 0 ? $value : 10; } - public function _view_mode ($value) { + public function _view_mode($value) { if ($value === 'global' || $value === 'reader') { $this->data['view_mode'] = $value; } else { $this->data['view_mode'] = 'normal'; } } - public function _default_view ($value) { + public function _default_view($value) { switch ($value) { - case FreshRSS_Entry::STATE_ALL: - // left blank on purpose - case FreshRSS_Entry::STATE_NOT_READ: - // left blank on purpose - case FreshRSS_Entry::STATE_STRICT + FreshRSS_Entry::STATE_NOT_READ: + case 'all': $this->data['default_view'] = $value; + $this->data['default_state'] = (FreshRSS_Entry::STATE_READ + + FreshRSS_Entry::STATE_NOT_READ); break; + case 'adaptive': + case 'unread': default: - $this->data['default_view'] = FreshRSS_Entry::STATE_ALL; - break; + $this->data['default_view'] = $value; + $this->data['default_state'] = FreshRSS_Entry::STATE_NOT_READ; } } - public function _display_posts ($value) { + public function _default_state($value) { + $this->data['default_state'] = (int)$value; + } + + public function _display_posts($value) { $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; } - public function _display_categories ($value) { + public function _display_categories($value) { $this->data['display_categories'] = ((bool)$value) && $value !== 'no'; } public function _hide_read_feeds($value) { $this->data['hide_read_feeds'] = (bool)$value; } - public function _onread_jump_next ($value) { + public function _onread_jump_next($value) { $this->data['onread_jump_next'] = ((bool)$value) && $value !== 'no'; } - public function _lazyload ($value) { + public function _lazyload($value) { $this->data['lazyload'] = ((bool)$value) && $value !== 'no'; } public function _sticky_post($value) { @@ -185,7 +191,7 @@ class FreshRSS_Configuration { public function _reading_confirm($value) { $this->data['reading_confirm'] = ((bool)$value) && $value !== 'no'; } - public function _sort_order ($value) { + public function _sort_order($value) { $this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; } public function _old_entries($value) { @@ -200,20 +206,20 @@ class FreshRSS_Configuration { $value = intval($value); $this->data['ttl_default'] = $value >= -1 ? $value : 3600; } - public function _shortcuts ($values) { + public function _shortcuts($values) { foreach ($values as $key => $value) { if (isset($this->data['shortcuts'][$key])) { $this->data['shortcuts'][$key] = $value; } } } - public function _passwordHash ($value) { + public function _passwordHash($value) { $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; } - public function _apiPasswordHash ($value) { + public function _apiPasswordHash($value) { $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; } - public function _mail_login ($value) { + public function _mail_login($value) { $value = filter_var($value, FILTER_VALIDATE_EMAIL); if ($value) { $this->data['mail_login'] = $value; @@ -221,17 +227,17 @@ class FreshRSS_Configuration { $this->data['mail_login'] = ''; } } - public function _anon_access ($value) { + public function _anon_access($value) { $this->data['anon_access'] = ((bool)$value) && $value !== 'no'; } - public function _mark_when ($values) { + public function _mark_when($values) { foreach ($values as $key => $value) { if (isset($this->data['mark_when'][$key])) { $this->data['mark_when'][$key] = ((bool)$value) && $value !== 'no'; } } } - public function _sharing ($values) { + public function _sharing($values) { $this->data['sharing'] = array(); $unique = array(); foreach ($values as $value) { @@ -242,7 +248,7 @@ class FreshRSS_Configuration { // Verify URL and add default value when needed if (isset($value['url'])) { $is_url = ( - filter_var ($value['url'], FILTER_VALIDATE_URL) || + filter_var($value['url'], FILTER_VALIDATE_URL) || (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && ($value === filter_var($value, FILTER_SANITIZE_URL))) @@ -266,7 +272,7 @@ class FreshRSS_Configuration { } } } - public function _queries ($values) { + public function _queries($values) { $this->data['queries'] = array(); foreach ($values as $value) { $value = array_filter($value); @@ -291,7 +297,7 @@ class FreshRSS_Configuration { } } - public function _html5_notif_timeout ($value) { + public function _html5_notif_timeout($value) { $value = intval($value); $this->data['html5_notif_timeout'] = $value >= 0 ? $value : 0; } diff --git a/app/Models/Context.php b/app/Models/Context.php new file mode 100644 index 000000000..36c4087eb --- /dev/null +++ b/app/Models/Context.php @@ -0,0 +1,268 @@ +<?php + +/** + * The context object handles the current configuration file and different + * useful functions associated to the current view state. + */ +class FreshRSS_Context { + public static $conf = null; + public static $categories = array(); + + public static $name = ''; + + public static $total_unread = 0; + public static $total_starred = array( + 'all' => 0, + 'read' => 0, + 'unread' => 0, + ); + + public static $get_unread = 0; + public static $current_get = array( + 'all' => false, + 'starred' => false, + 'feed' => false, + 'category' => false, + ); + public static $next_get = 'a'; + + public static $state = 0; + public static $order = 'DESC'; + public static $number = 0; + public static $search = ''; + public static $first_id = ''; + public static $next_id = ''; + public static $id_max = ''; + + /** + * Initialize the context. + * + * Set the correct $conf and $categories variables. + */ + public static function init() { + // Init configuration. + $current_user = Minz_Session::param('currentUser'); + try { + self::$conf = new FreshRSS_Configuration($current_user); + } catch(Minz_Exception $e) { + Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); + die($e->getMessage()); + } + + $catDAO = new FreshRSS_CategoryDAO(); + self::$categories = $catDAO->listCategories(); + } + + /** + * Returns if the current state includes $state parameter. + */ + public static function isStateEnabled($state) { + return self::$state & $state; + } + + /** + * Returns the current state with or without $state parameter. + */ + public static function getRevertState($state) { + if (self::$state & $state) { + return self::$state & ~$state; + } else { + return self::$state | $state; + } + } + + /** + * Return the current get as a string or an array. + * + * If $array is true, the first item of the returned value is 'f' or 'c' and + * the second is the id. + */ + public static function currentGet($array = false) { + if (self::$current_get['all']) { + return 'a'; + } elseif (self::$current_get['starred']) { + return 's'; + } elseif (self::$current_get['feed']) { + if ($array) { + return array('f', self::$current_get['feed']); + } else { + return 'f_' . self::$current_get['feed']; + } + } elseif (self::$current_get['category']) { + if ($array) { + return array('c', self::$current_get['category']); + } else { + return 'c_' . self::$current_get['category']; + } + } + } + + /** + * Return true if $get parameter correspond to the $current_get attribute. + */ + public static function isCurrentGet($get) { + $type = $get[0]; + $id = substr($get, 2); + + switch($type) { + case 'a': + return self::$current_get['all']; + case 's': + return self::$current_get['starred']; + case 'f': + return self::$current_get['feed'] == $id; + case 'c': + return self::$current_get['category'] == $id; + default: + return false; + } + } + + /** + * Set the current $get attribute. + * + * Valid $get parameter are: + * - a + * - s + * - f_<feed id> + * - c_<category id> + * + * $name and $get_unread attributes are also updated as $next_get + * Raise an exception if id or $get is invalid. + */ + public static function _get($get) { + $type = $get[0]; + $id = substr($get, 2); + $nb_unread = 0; + + switch($type) { + case 'a': + self::$current_get['all'] = true; + self::$name = _t('your_rss_feeds'); + self::$get_unread = self::$total_unread; + break; + case 's': + self::$current_get['starred'] = true; + self::$name = _t('your_favorites'); + self::$get_unread = self::$total_starred['unread']; + + // Update state if favorite is not yet enabled. + self::$state = self::$state | FreshRSS_Entry::STATE_FAVORITE; + break; + case 'f': + // We try to find the corresponding feed. + $feed = FreshRSS_CategoryDAO::findFeed(self::$categories, $id); + if ($feed === null) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $feed = $feedDAO->searchById($id); + + if (!$feed) { + throw new FreshRSS_Context_Exception('Invalid feed: ' . $id); + } + } + + self::$current_get['feed'] = $id; + self::$current_get['category'] = $feed->category(); + self::$name = $feed->name(); + self::$get_unread = $feed->nbNotRead(); + break; + case 'c': + // We try to find the corresponding category. + self::$current_get['category'] = $id; + if (!isset(self::$categories[$id])) { + $catDAO = new FreshRSS_CategoryDAO(); + $cat = $catDAO->searchById($id); + + if (!$cat) { + throw new FreshRSS_Context_Exception('Invalid category: ' . $id); + } + } else { + $cat = self::$categories[$id]; + } + + self::$name = $cat->name(); + self::$get_unread = $cat->nbNotRead(); + break; + default: + throw new FreshRSS_Context_Exception('Invalid getter: ' . $get); + } + + self::_nextGet(); + } + + /** + * Set the value of $next_get attribute. + */ + public static function _nextGet() { + $get = self::currentGet(); + // By default, $next_get == $get + self::$next_get = $get; + + if (self::$conf->onread_jump_next && strlen($get) > 2) { + $another_unread_id = ''; + $found_current_get = false; + switch ($get[0]) { + case 'f': + // We search the next feed with at least one unread article in + // same category as the currend feed. + foreach (self::$categories as $cat) { + if ($cat->id() != self::$current_get['category']) { + // We look into the category of the current feed! + continue; + } + + foreach ($cat->feeds() as $feed) { + if ($feed->id() == self::$current_get['feed']) { + // Here is our current feed! Fine, the next one will + // be a potential candidate. + $found_current_get = true; + continue; + } + + if ($feed->nbNotRead() > 0) { + $another_unread_id = $feed->id(); + if ($found_current_get) { + // We have found our current feed and now we + // have an feed with unread articles. Leave the + // loop! + break; + } + } + } + break; + } + + // If no feed have been found, next_get is the current category. + self::$next_get = empty($another_unread_id) ? + 'c_' . self::$current_get['category'] : + 'f_' . $another_unread_id; + break; + case 'c': + // We search the next category with at least one unread article. + foreach (self::$categories as $cat) { + if ($cat->id() == self::$current_get['category']) { + // Here is our current category! Next one could be our + // champion if it has unread articles. + $found_current_get = true; + continue; + } + + if ($cat->nbNotRead() > 0) { + $another_unread_id = $cat->id(); + if ($found_current_get) { + // Unread articles and the current category has + // already been found? Leave the loop! + break; + } + } + } + + // No unread category? The main stream will be our destination! + self::$next_get = empty($another_unread_id) ? + 'a' : + 'c_' . $another_unread_id; + break; + } + } + } +} diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php new file mode 100644 index 000000000..0d85718e3 --- /dev/null +++ b/app/Models/DatabaseDAO.php @@ -0,0 +1,83 @@ +<?php + +/** + * This class is used to test database is well-constructed. + */ +class FreshRSS_DatabaseDAO extends Minz_ModelPdo { + public function tablesAreCorrect() { + $sql = 'SHOW TABLES'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + $this->prefix . 'category' => false, + $this->prefix . 'feed' => false, + $this->prefix . 'entry' => false, + ); + foreach ($res as $value) { + $tables[array_pop($value)] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'DESC ' . $this->prefix . $table; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function checkTable($table, $schema) { + $columns = $this->getSchema($table); + + $ok = (count($columns) == count($schema)); + foreach ($columns as $c) { + $ok &= in_array($c['name'], $schema); + } + + return $ok; + } + + public function categoryIsCorrect() { + return $this->checkTable('category', array( + 'id', 'name' + )); + } + + public function feedIsCorrect() { + return $this->checkTable('feed', array( + 'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate', + 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', + 'cache_nbEntries', 'cache_nbUnreads' + )); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content_bin', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['Field'], + 'type' => strtolower($dao['Type']), + 'notnull' => (bool)$dao['Null'], + 'default' => $dao['Default'], + ); + } + + public function listDaoToSchema($listDAO) { + $list = array(); + + foreach ($listDAO as $dao) { + $list[] = $this->daoToSchema($dao); + } + + return $list; + } +} diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php new file mode 100644 index 000000000..7f53f967d --- /dev/null +++ b/app/Models/DatabaseDAOSQLite.php @@ -0,0 +1,48 @@ +<?php + +/** + * This class is used to test database is well-constructed (SQLite). + */ +class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO { + public function tablesAreCorrect() { + $sql = 'SELECT name FROM sqlite_master WHERE type="table"'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + 'category' => false, + 'feed' => false, + 'entry' => false, + ); + foreach ($res as $value) { + $tables[$value['name']] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'PRAGMA table_info(' . $table . ')'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['name'], + 'type' => strtolower($dao['type']), + 'notnull' => $dao['notnull'] === '1' ? true : false, + 'default' => $dao['dflt_value'], + ); + } +} diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 9d7dd5dc4..346c98a92 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -1,12 +1,11 @@ <?php class FreshRSS_Entry extends Minz_Model { - const STATE_ALL = 0; const STATE_READ = 1; const STATE_NOT_READ = 2; + const STATE_ALL = 3; const STATE_FAVORITE = 4; const STATE_NOT_FAVORITE = 8; - const STATE_STRICT = 16; private $id = 0; private $guid; @@ -20,134 +19,134 @@ class FreshRSS_Entry extends Minz_Model { private $feed; private $tags; - public function __construct ($feed = '', $guid = '', $title = '', $author = '', $content = '', - $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { - $this->_guid ($guid); - $this->_title ($title); - $this->_author ($author); - $this->_content ($content); - $this->_link ($link); - $this->_date ($pubdate); - $this->_isRead ($is_read); - $this->_isFavorite ($is_favorite); - $this->_feed ($feed); - $this->_tags (preg_split('/[\s#]/', $tags)); + public function __construct($feed = '', $guid = '', $title = '', $author = '', $content = '', + $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { + $this->_guid($guid); + $this->_title($title); + $this->_author($author); + $this->_content($content); + $this->_link($link); + $this->_date($pubdate); + $this->_isRead($is_read); + $this->_isFavorite($is_favorite); + $this->_feed($feed); + $this->_tags(preg_split('/[\s#]/', $tags)); } - public function id () { + public function id() { return $this->id; } - public function guid () { + public function guid() { return $this->guid; } - public function title () { + public function title() { return $this->title; } - public function author () { + public function author() { return $this->author === null ? '' : $this->author; } - public function content () { + public function content() { return $this->content; } - public function link () { + public function link() { return $this->link; } - public function date ($raw = false) { + public function date($raw = false) { if ($raw) { return $this->date; } else { - return timestamptodate ($this->date); + return timestamptodate($this->date); } } - public function dateAdded ($raw = false) { + public function dateAdded($raw = false) { $date = intval(substr($this->id, 0, -6)); if ($raw) { return $date; } else { - return timestamptodate ($date); + return timestamptodate($date); } } - public function isRead () { + public function isRead() { return $this->is_read; } - public function isFavorite () { + public function isFavorite() { return $this->is_favorite; } - public function feed ($object = false) { + public function feed($object = false) { if ($object) { $feedDAO = FreshRSS_Factory::createFeedDao(); - return $feedDAO->searchById ($this->feed); + return $feedDAO->searchById($this->feed); } else { return $this->feed; } } - public function tags ($inString = false) { + public function tags($inString = false) { if ($inString) { - return empty ($this->tags) ? '' : '#' . implode(' #', $this->tags); + return empty($this->tags) ? '' : '#' . implode(' #', $this->tags); } else { return $this->tags; } } - public function _id ($value) { + public function _id($value) { $this->id = $value; } - public function _guid ($value) { + public function _guid($value) { $this->guid = $value; } - public function _title ($value) { + public function _title($value) { $this->title = $value; } - public function _author ($value) { + public function _author($value) { $this->author = $value; } - public function _content ($value) { + public function _content($value) { $this->content = $value; } - public function _link ($value) { + public function _link($value) { $this->link = $value; } - public function _date ($value) { + public function _date($value) { $value = intval($value); $this->date = $value > 1 ? $value : time(); } - public function _isRead ($value) { + public function _isRead($value) { $this->is_read = $value; } - public function _isFavorite ($value) { + public function _isFavorite($value) { $this->is_favorite = $value; } - public function _feed ($value) { + public function _feed($value) { $this->feed = $value; } - public function _tags ($value) { - if (!is_array ($value)) { - $value = array ($value); + public function _tags($value) { + if (!is_array($value)) { + $value = array($value); } foreach ($value as $key => $t) { if (!$t) { - unset ($value[$key]); + unset($value[$key]); } } $this->tags = $value; } - public function isDay ($day, $today) { + public function isDay($day, $today) { $date = $this->dateAdded(true); switch ($day) { - case FreshRSS_Days::TODAY: - $tomorrow = $today + 86400; - return $date >= $today && $date < $tomorrow; - case FreshRSS_Days::YESTERDAY: - $yesterday = $today - 86400; - return $date >= $yesterday && $date < $today; - case FreshRSS_Days::BEFORE_YESTERDAY: - $yesterday = $today - 86400; - return $date < $yesterday; - default: - return false; + case FreshRSS_Days::TODAY: + $tomorrow = $today + 86400; + return $date >= $today && $date < $tomorrow; + case FreshRSS_Days::YESTERDAY: + $yesterday = $today - 86400; + return $date >= $yesterday && $date < $today; + case FreshRSS_Days::BEFORE_YESTERDAY: + $yesterday = $today - 86400; + return $date < $yesterday; + default: + return false; } } @@ -158,7 +157,7 @@ class FreshRSS_Entry extends Minz_Model { $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $entryDAO->searchByGuid($this->feed, $this->guid); - if($entry) { + if ($entry) { // l'article existe déjà en BDD, en se contente de recharger ce contenu $this->content = $entry->content(); } else { @@ -168,25 +167,25 @@ class FreshRSS_Entry extends Minz_Model { htmlspecialchars_decode($this->link(), ENT_QUOTES), $pathEntries ); } catch (Exception $e) { - // rien à faire, on garde l'ancien contenu (requête a échoué) + // rien à faire, on garde l'ancien contenu(requête a échoué) } } } } - public function toArray () { - return array ( - 'id' => $this->id (), - 'guid' => $this->guid (), - 'title' => $this->title (), - 'author' => $this->author (), - 'content' => $this->content (), - 'link' => $this->link (), - 'date' => $this->date (true), - 'is_read' => $this->isRead (), - 'is_favorite' => $this->isFavorite (), - 'id_feed' => $this->feed (), - 'tags' => $this->tags (true), + public function toArray() { + return array( + 'id' => $this->id(), + 'guid' => $this->guid(), + 'title' => $this->title(), + 'author' => $this->author(), + 'content' => $this->content(), + 'link' => $this->link(), + 'date' => $this->date(true), + 'is_read' => $this->isRead(), + 'is_favorite' => $this->isFavorite(), + 'id_feed' => $this->feed(), + 'tags' => $this->tags(true), ); } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c1f87ee34..5d2909c62 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -40,11 +40,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } else { $info = $stm == null ? array(2 => 'syntax error') : $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 addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] - . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR); + Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); } /*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); + Minz_Log::debug('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); }*/ return false; } @@ -94,7 +94,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markFavorite: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markFavorite: ' . $info[2]); return false; } } @@ -124,7 +124,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCacheUnreads: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]); return false; } } @@ -147,7 +147,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -166,7 +166,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead: ' . $info[2]); return false; } } @@ -175,7 +175,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -190,7 +190,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadEntries: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -203,7 +203,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadCat(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -213,7 +213,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadCat: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -226,7 +226,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadFeed($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadFeed(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); } $this->bd->beginTransaction(); @@ -237,7 +237,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -251,7 +251,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -299,7 +299,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return 'CONCAT(' . $s1 . ',' . $s2 . ')'; //MySQL } - private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { if (!$state) { $state = FreshRSS_Entry::STATE_ALL; } @@ -307,34 +307,32 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $joinFeed = false; $values = array(); switch ($type) { - case 'a': - $where .= 'f.priority > 0 '; - $joinFeed = true; - break; - case 's': //Deprecated: use $state instead - $where .= 'e1.is_favorite=1 '; - break; - case 'c': - $where .= 'f.category=? '; - $values[] = intval($id); - $joinFeed = true; - break; - case 'f': - $where .= 'e1.id_feed=? '; - $values[] = intval($id); - break; - case 'A': - $where .= '1 '; - break; - default: - throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); + case 'a': + $where .= 'f.priority > 0 '; + $joinFeed = true; + break; + case 's': //Deprecated: use $state instead + $where .= 'e1.is_favorite=1 '; + break; + case 'c': + $where .= 'f.category=? '; + $values[] = intval($id); + $joinFeed = true; + break; + case 'f': + $where .= 'e1.id_feed=? '; + $values[] = intval($id); + break; + case 'A': + $where .= '1 '; + break; + default: + throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); } if ($state & FreshRSS_Entry::STATE_NOT_READ) { if (!($state & FreshRSS_Entry::STATE_READ)) { $where .= 'AND e1.is_read=0 '; - } elseif ($state & FreshRSS_Entry::STATE_STRICT) { - $where .= 'AND e1.is_read=0 '; } } elseif ($state & FreshRSS_Entry::STATE_READ) { @@ -356,23 +354,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { default: throw new FreshRSS_EntriesGetter_Exception('Bad order in Entry->listByType: [' . $order . ']!'); } - if ($firstId === '' && parent::$sharedDbType === 'mysql') { - $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. Tested on MySQL 5.5 with 150k articles - } + /*if ($firstId === '' && parent::$sharedDbType === 'mysql') { + $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. TODO: check if this is needed again, after the filtering for old articles has been removed in 0.9-dev + }*/ if ($firstId !== '') { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } - if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e1.id >= ' . $date_min . '000000'; - if ($showOlderUnreadsorFavorites) { //Lax date constraint - $where .= ' OR e1.is_read=0 OR e1.is_favorite=1 OR (f.keep_history <> 0'; - if (intval($keepHistoryDefault) === 0) { - $where .= ' AND f.keep_history <> -2'; //default - } - $where .= ')'; - } - $where .= ') '; - $joinFeed = true; + if ($date_min > 0) { + $where .= 'AND e1.id >= ' . $date_min . '000000 '; } $search = ''; if ($filter !== '') { @@ -434,8 +423,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . ($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, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); + public function listWhere($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 e.id, e.guid, e.title, e.author, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') @@ -452,8 +441,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return self::daoToEntry($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, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $stm = $this->bd->prepare($sql); $stm->execute($values); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 9dc395c3c..4a3fe24a2 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -26,7 +26,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCacheUnreads: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]); return false; } } @@ -47,7 +47,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead 1: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead 1: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -59,7 +59,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead 2: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead 2: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -72,7 +72,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` SET is_read=1 WHERE is_read=0 AND id <= ?'; @@ -85,7 +85,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadEntries: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -98,7 +98,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadCat(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` ' @@ -109,7 +109,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadCat: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -124,6 +124,6 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } public function size($all = false) { - return @filesize(DATA_PATH . '/' . Minz_Session::param('currentUser', '_') . '.sqlite'); + return @filesize(DATA_PATH . '/' . $this->current_user . '.sqlite'); } } diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 08569b2e2..91cb84998 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -2,30 +2,39 @@ class FreshRSS_Factory { - public static function createFeedDao() { + public static function createFeedDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_FeedDAOSQLite(); + return new FreshRSS_FeedDAOSQLite($username); } else { - return new FreshRSS_FeedDAO(); + return new FreshRSS_FeedDAO($username); } } - public static function createEntryDao() { + public static function createEntryDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_EntryDAOSQLite(); + return new FreshRSS_EntryDAOSQLite($username); } else { - return new FreshRSS_EntryDAO(); + return new FreshRSS_EntryDAO($username); } } - public static function createStatsDAO() { + public static function createStatsDAO($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_StatsDAOSQLite(); + return new FreshRSS_StatsDAOSQLite($username); } else { - return new FreshRSS_StatsDAO(); + return new FreshRSS_StatsDAO($username); + } + } + + public static function createDatabaseDAO($username = null) { + $db = Minz_Configuration::dataBase(); + if ($db['type'] === 'sqlite') { + return new FreshRSS_DatabaseDAOSQLite($username); + } else { + return new FreshRSS_DatabaseDAO($username); } } diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 03baf3ad2..bd1babeea 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -217,7 +217,8 @@ class FreshRSS_Feed extends Minz_Model { $mtime = $feed->init(); if ((!$mtime) || $feed->error()) { - throw new FreshRSS_Feed_Exception($feed->error() . ' [' . $url . ']'); + $errorMessage = $feed->error(); + throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']'); } if ($loadDetails) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index b89ae2045..74597c730 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -19,7 +19,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error addFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error addFeed: ' . $info[2]); return false; } } @@ -77,7 +77,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateFeed: ' . $info[2]); return false; } } @@ -107,7 +107,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateLastUpdate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateLastUpdate: ' . $info[2]); return false; } } @@ -131,7 +131,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error changeCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error changeCategory: ' . $info[2]); return false; } } @@ -146,7 +146,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteFeed: ' . $info[2]); return false; } } @@ -160,7 +160,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteFeedByCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteFeedByCategory: ' . $info[2]); return false; } } @@ -191,7 +191,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $res = $stm->fetchAll(PDO::FETCH_ASSOC); $feed = current(self::daoToFeed($res)); - if (isset($feed)) { + if (isset($feed) && $feed !== false) { return $feed; } else { return null; @@ -289,7 +289,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCachedValues: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCachedValues: ' . $info[2]); return false; } } @@ -301,7 +301,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $this->bd->beginTransaction(); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error truncate: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -313,7 +313,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error truncate: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -338,7 +338,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error cleanOldEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error cleanOldEntries: ' . $info[2]); return false; } } diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php index 0d1872389..7599fda53 100644 --- a/app/Models/FeedDAOSQLite.php +++ b/app/Models/FeedDAOSQLite.php @@ -11,7 +11,7 @@ class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCachedValues: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCachedValues: ' . $info[2]); return false; } } diff --git a/app/Models/Log.php b/app/Models/Log.php index d2794458b..df2de72ac 100644 --- a/app/Models/Log.php +++ b/app/Models/Log.php @@ -5,22 +5,22 @@ class FreshRSS_Log extends Minz_Model { private $level; private $information; - public function date () { + public function date() { return $this->date; } - public function level () { + public function level() { return $this->level; } - public function info () { + public function info() { return $this->information; } - public function _date ($date) { + public function _date($date) { $this->date = $date; } - public function _level ($level) { + public function _level($level) { $this->level = $level; } - public function _info ($information) { + public function _info($information) { $this->information = $information; } } diff --git a/app/Models/LogDAO.php b/app/Models/LogDAO.php index d1e515200..21593435d 100644 --- a/app/Models/LogDAO.php +++ b/app/Models/LogDAO.php @@ -2,15 +2,15 @@ class FreshRSS_LogDAO { public static function lines() { - $logs = array (); + $logs = array(); $handle = @fopen(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log', 'r'); if ($handle) { while (($line = fgets($handle)) !== false) { - if (preg_match ('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) { + if (preg_match('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) { $myLog = new FreshRSS_Log (); - $myLog->_date ($matches[1]); - $myLog->_level ($matches[2]); - $myLog->_info ($matches[3]); + $myLog->_date($matches[1]); + $myLog->_level($matches[2]); + $myLog->_info($matches[3]); $logs[] = $myLog; } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 08dd4cd5c..283d5dcb1 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -237,7 +237,7 @@ SQL; $interval_in_days = $period; } - return round($res['count'] / ($interval_in_days / $period), 2); + return $res['count'] / ($interval_in_days / $period); } /** @@ -415,8 +415,8 @@ SQL; * @return string */ private function convertToTranslatedJson($data = array()) { - $translated = array_map(function ($a) { - return Minz_Translate::t($a); + $translated = array_map(function($a) { + return _t($a); }, $data); return json_encode($translated); diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 68fc17a2b..e3b260261 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -82,6 +82,7 @@ class FreshRSS_Themes extends Minz_Model { 'favorite' => '★', 'help' => 'ⓘ', 'icon' => '⊚', + 'import' => '⤓', 'key' => '⚿', 'link' => '↗', 'login' => '🔒', diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 9f64fb4a7..60fca71b1 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -9,7 +9,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $ok = false; if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); + $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { //E.g. SQLite @@ -17,7 +17,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { if (is_array($SQL_CREATE_TABLES)) { $ok = true; foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, '', Minz_Translate::t('default_category')); + $sql = sprintf($instruction, '', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok &= ($stm && $stm->execute()); } @@ -28,7 +28,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return true; } else { $info = empty($stm) ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error : ' . $info[2]); return false; } } @@ -48,9 +48,21 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error : ' . $info[2]); return false; } } } + + public static function exist($username) { + return file_exists(DATA_PATH . '/' . $username . '_user.php'); + } + + public static function touch($username) { + return touch(DATA_PATH . '/' . $username . '_user.php'); + } + + public static function mtime($username) { + return @filemtime(DATA_PATH . '/' . $username . '_user.php'); + } } |
