mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-05-24 08:14:56 -04:00
Merge remote-tracking branch 'origin/sql_hash_lastUpdate' into dev
This commit is contained in:
@@ -145,7 +145,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
// Call the extension hook
|
||||
$name = $feed->name();
|
||||
$feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed);
|
||||
if (is_null($feed)) {
|
||||
if ($feed === null) {
|
||||
Minz_Request::bad(_t('feed_not_added', $name), $url_redirect);
|
||||
}
|
||||
|
||||
@@ -181,7 +181,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
|
||||
// Use a shared statement and a transaction to improve a LOT the
|
||||
// performances.
|
||||
$prepared_statement = $entryDAO->addEntryPrepare();
|
||||
$feedDAO->beginTransaction();
|
||||
foreach ($entries as $entry) {
|
||||
// Entries are added without any verification.
|
||||
@@ -190,13 +189,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
$entry->_isRead($is_read);
|
||||
|
||||
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
|
||||
if (is_null($entry)) {
|
||||
if ($entry === null) {
|
||||
// An extension has returned a null value, there is nothing to insert.
|
||||
continue;
|
||||
}
|
||||
|
||||
$values = $entry->toArray();
|
||||
$entryDAO->addEntry($values, $prepared_statement);
|
||||
$entryDAO->addEntry($values);
|
||||
}
|
||||
$feedDAO->updateLastUpdate($feed->id());
|
||||
$feedDAO->commit();
|
||||
@@ -307,7 +306,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
$feed->load(false);
|
||||
} catch (FreshRSS_Feed_Exception $e) {
|
||||
Minz_Log::notice($e->getMessage());
|
||||
$feedDAO->updateLastUpdate($feed->id(), 1);
|
||||
$feedDAO->updateLastUpdate($feed->id(), true);
|
||||
$feed->unlock();
|
||||
continue;
|
||||
}
|
||||
@@ -323,50 +322,69 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
// We want chronological order and SimplePie uses reverse order.
|
||||
$entries = array_reverse($feed->entries());
|
||||
if (count($entries) > 0) {
|
||||
// For this feed, check last n entry GUIDs already in database.
|
||||
$existing_guids = array_fill_keys($entryDAO->listLastGuidsByFeed(
|
||||
$feed->id(), count($entries) + 10
|
||||
), 1);
|
||||
$use_declared_date = empty($existing_guids);
|
||||
$newGuids = array();
|
||||
foreach ($entries as $entry) {
|
||||
$newGuids[] = $entry->guid();
|
||||
}
|
||||
// For this feed, check existing GUIDs already in database.
|
||||
$existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids);
|
||||
unset($newGuids);
|
||||
$use_declared_date = empty($existingHashForGuids);
|
||||
|
||||
$oldGuids = array();
|
||||
// Add entries in database if possible.
|
||||
$prepared_statement = $entryDAO->addEntryPrepare();
|
||||
$feedDAO->beginTransaction();
|
||||
foreach ($entries as $entry) {
|
||||
$entry_date = $entry->date(true);
|
||||
if (isset($existing_guids[$entry->guid()]) ||
|
||||
($feed_history == 0 && $entry_date < $date_min)) {
|
||||
// This entry already exists in DB or should not be added
|
||||
// considering configuration and date.
|
||||
continue;
|
||||
if (isset($existingHashForGuids[$entry->guid()])) {
|
||||
$existingHash = $existingHashForGuids[$entry->guid()];
|
||||
if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') {
|
||||
//This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3
|
||||
$oldGuids[] = $entry->guid();
|
||||
} else { //This entry already exists but has been updated
|
||||
Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() .
|
||||
', old hash ' . $existingHash . ', new hash ' . $entry->hash());
|
||||
$entry->_isRead($is_read); //Reset is_read
|
||||
if (!$entryDAO->hasTransaction()) {
|
||||
$entryDAO->beginTransaction();
|
||||
}
|
||||
$entryDAO->updateEntry($entry->toArray());
|
||||
}
|
||||
} elseif ($feed_history == 0 && $entry_date < $date_min) {
|
||||
// This entry should not be added considering configuration and date.
|
||||
$oldGuids[] = $entry->guid();
|
||||
} else {
|
||||
$id = uTimeString();
|
||||
if ($use_declared_date || $entry_date < $date_min) {
|
||||
// Use declared date at first import.
|
||||
$id = min(time(), $entry_date) . uSecString();
|
||||
}
|
||||
|
||||
$entry->_id($id);
|
||||
$entry->_isRead($is_read);
|
||||
|
||||
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
|
||||
if ($entry === null) {
|
||||
// An extension has returned a null value, there is nothing to insert.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$entryDAO->hasTransaction()) {
|
||||
$entryDAO->beginTransaction();
|
||||
}
|
||||
$entryDAO->addEntry($entry->toArray());
|
||||
}
|
||||
|
||||
$id = uTimeString();
|
||||
if ($use_declared_date || $entry_date < $date_min) {
|
||||
// Use declared date at first import.
|
||||
$id = min(time(), $entry_date) . uSecString();
|
||||
}
|
||||
|
||||
$entry->_id($id);
|
||||
$entry->_isRead($is_read);
|
||||
|
||||
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
|
||||
if (is_null($entry)) {
|
||||
// An extension has returned a null value, there is nothing to insert.
|
||||
continue;
|
||||
}
|
||||
|
||||
$values = $entry->toArray();
|
||||
$entryDAO->addEntry($values, $prepared_statement);
|
||||
}
|
||||
$entryDAO->updateLastSeen($feed->id(), $oldGuids);
|
||||
}
|
||||
//TODO: updateLastSeen old GUIDS once in a while, in the case of caching (i.e. the whole feed content has not changed)
|
||||
|
||||
if ($feed_history >= 0 && rand(0, 30) === 1) {
|
||||
// TODO: move this function in web cron when available (see entry::purge)
|
||||
// Remove old entries once in 30.
|
||||
if (!$feedDAO->hasTransaction()) {
|
||||
$feedDAO->beginTransaction();
|
||||
if (!$entryDAO->hasTransaction()) {
|
||||
$entryDAO->beginTransaction();
|
||||
}
|
||||
//TODO: more robust system based on entry.lastSeen to avoid cleaning entries that are still published in the RSS feed.
|
||||
|
||||
$nb = $feedDAO->cleanOldEntries($feed->id(),
|
||||
$date_min,
|
||||
@@ -377,9 +395,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
$feedDAO->updateLastUpdate($feed->id(), 0, $feedDAO->hasTransaction());
|
||||
if ($feedDAO->hasTransaction()) {
|
||||
$feedDAO->commit();
|
||||
$feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction());
|
||||
if ($entryDAO->hasTransaction()) {
|
||||
$entryDAO->commit();
|
||||
}
|
||||
|
||||
if ($feed->url() !== $url) {
|
||||
|
||||
@@ -361,7 +361,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
|
||||
}
|
||||
|
||||
// Then, articles are imported.
|
||||
$prepared_statement = $this->entryDAO->addEntryPrepare();
|
||||
$this->entryDAO->beginTransaction();
|
||||
foreach ($article_object['items'] as $item) {
|
||||
if (!isset($article_to_feed[$item['id']])) {
|
||||
@@ -396,7 +395,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
|
||||
}
|
||||
|
||||
$values = $entry->toArray();
|
||||
$id = $this->entryDAO->addEntry($values, $prepared_statement);
|
||||
$id = $this->entryDAO->addEntry($values);
|
||||
|
||||
if (!$error && ($id === false)) {
|
||||
$error = true;
|
||||
|
||||
@@ -14,6 +14,7 @@ class FreshRSS_Entry extends Minz_Model {
|
||||
private $content;
|
||||
private $link;
|
||||
private $date;
|
||||
private $hash = null;
|
||||
private $is_read;
|
||||
private $is_favorite;
|
||||
private $feed;
|
||||
@@ -88,6 +89,14 @@ class FreshRSS_Entry extends Minz_Model {
|
||||
}
|
||||
}
|
||||
|
||||
public function hash() {
|
||||
if ($this->hash === null) {
|
||||
//Do not include $this->date because it may be automatically generated when lacking
|
||||
$this->hash = md5($this->link . $this->title . $this->author . $this->content . $this->tags(true));
|
||||
}
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
public function _id($value) {
|
||||
$this->id = $value;
|
||||
}
|
||||
@@ -95,18 +104,23 @@ class FreshRSS_Entry extends Minz_Model {
|
||||
$this->guid = $value;
|
||||
}
|
||||
public function _title($value) {
|
||||
$this->hash = null;
|
||||
$this->title = $value;
|
||||
}
|
||||
public function _author($value) {
|
||||
$this->hash = null;
|
||||
$this->author = $value;
|
||||
}
|
||||
public function _content($value) {
|
||||
$this->hash = null;
|
||||
$this->content = $value;
|
||||
}
|
||||
public function _link($value) {
|
||||
$this->hash = null;
|
||||
$this->link = $value;
|
||||
}
|
||||
public function _date($value) {
|
||||
$this->hash = null;
|
||||
$value = intval($value);
|
||||
$this->date = $value > 1 ? $value : time();
|
||||
}
|
||||
@@ -120,6 +134,7 @@ class FreshRSS_Entry extends Minz_Model {
|
||||
$this->feed = $value;
|
||||
}
|
||||
public function _tags($value) {
|
||||
$this->hash = null;
|
||||
if (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
@@ -182,6 +197,7 @@ class FreshRSS_Entry extends Minz_Model {
|
||||
'content' => $this->content(),
|
||||
'link' => $this->link(),
|
||||
'date' => $this->date(true),
|
||||
'hash' => $this->hash(),
|
||||
'is_read' => $this->isRead(),
|
||||
'is_favorite' => $this->isFavorite(),
|
||||
'id_feed' => $this->feed(),
|
||||
|
||||
@@ -6,20 +6,57 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
return parent::$sharedDbType !== 'sqlite';
|
||||
}
|
||||
|
||||
public function addEntryPrepare() {
|
||||
$sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, '
|
||||
. ($this->isCompressed() ? 'content_bin' : 'content')
|
||||
. ', link, date, is_read, is_favorite, id_feed, tags) '
|
||||
. 'VALUES(?, ?, ?, ?, '
|
||||
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
|
||||
. ', ?, ?, ?, ?, ?, ?)';
|
||||
return $this->bd->prepare($sql);
|
||||
protected function autoAddColumn($errorInfo) {
|
||||
if (isset($errorInfo[0])) {
|
||||
if ($errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR
|
||||
$hasTransaction = false;
|
||||
try {
|
||||
$stm = null;
|
||||
if (stripos($errorInfo[2], 'lastSeen') !== false) { //v1.2
|
||||
if (!$this->bd->inTransaction()) {
|
||||
$this->bd->beginTransaction();
|
||||
$hasTransaction = true;
|
||||
}
|
||||
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN lastSeen INT(11) NOT NULL');
|
||||
if ($stm && $stm->execute()) {
|
||||
$stm = $this->bd->prepare('CREATE INDEX entry_lastSeen_index ON `' . $this->prefix . 'entry`(`lastSeen`);'); //"IF NOT EXISTS" does not exist in MySQL 5.7
|
||||
if ($stm && $stm->execute()) {
|
||||
if ($hasTransaction) {
|
||||
$this->bd->commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($hasTransaction) {
|
||||
$this->bd->rollBack();
|
||||
}
|
||||
} elseif (stripos($errorInfo[2], 'hash') !== false) { //v1.2
|
||||
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN hash BINARY(16) NOT NULL');
|
||||
return $stm && $stm->execute();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn error: ' . $e->getMessage());
|
||||
if ($hasTransaction) {
|
||||
$this->bd->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addEntry($valuesTmp, $preparedStatement = null) {
|
||||
$stm = $preparedStatement === null ?
|
||||
FreshRSS_EntryDAO::addEntryPrepare() :
|
||||
$preparedStatement;
|
||||
private $addEntryPrepared = null;
|
||||
|
||||
public function addEntry($valuesTmp) {
|
||||
if ($this->addEntryPrepared === null) {
|
||||
$sql = 'INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, '
|
||||
. ($this->isCompressed() ? 'content_bin' : 'content')
|
||||
. ', link, date, lastSeen, hash, is_read, is_favorite, id_feed, tags) '
|
||||
. 'VALUES(?, ?, ?, ?, '
|
||||
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
|
||||
. ', ?, ?, ?, X?, ?, ?, ?, ?)';
|
||||
$this->addEntryPrepared = $this->bd->prepare($sql);
|
||||
}
|
||||
|
||||
$values = array(
|
||||
$valuesTmp['id'],
|
||||
@@ -29,55 +66,65 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
$valuesTmp['content'],
|
||||
substr($valuesTmp['link'], 0, 1023),
|
||||
$valuesTmp['date'],
|
||||
time(),
|
||||
$valuesTmp['hash'],
|
||||
$valuesTmp['is_read'] ? 1 : 0,
|
||||
$valuesTmp['is_favorite'] ? 1 : 0,
|
||||
$valuesTmp['id_feed'],
|
||||
substr($valuesTmp['tags'], 0, 1023),
|
||||
);
|
||||
|
||||
if ($stm && $stm->execute($values)) {
|
||||
if ($this->addEntryPrepared && $this->addEntryPrepared->execute($values)) {
|
||||
return $this->bd->lastInsertId();
|
||||
} 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
|
||||
$info = $this->addEntryPrepared == null ? array(2 => 'syntax error') : $this->addEntryPrepared->errorInfo();
|
||||
if ($this->autoAddColumn($info)) {
|
||||
return $this->addEntry($valuesTmp);
|
||||
} elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries
|
||||
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::debug('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
|
||||
. ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']);
|
||||
}*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function addEntryObject($entry, $conf, $feedHistory) {
|
||||
$existingGuids = array_fill_keys(
|
||||
$this->listLastGuidsByFeed($entry->feed(), 20), 1
|
||||
private $updateEntryPrepared = null;
|
||||
|
||||
public function updateEntry($valuesTmp) {
|
||||
if ($this->updateEntryPrepared === null) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` '
|
||||
. 'SET title=?, author=?, '
|
||||
. ($this->isCompressed() ? 'content_bin=COMPRESS(?)' : 'content=?')
|
||||
. ', link=?, date=?, lastSeen=?, hash=X?, is_read=?, tags=? '
|
||||
. 'WHERE id_feed=? AND guid=?';
|
||||
$this->updateEntryPrepared = $this->bd->prepare($sql);
|
||||
}
|
||||
|
||||
$values = array(
|
||||
substr($valuesTmp['title'], 0, 255),
|
||||
substr($valuesTmp['author'], 0, 255),
|
||||
$valuesTmp['content'],
|
||||
substr($valuesTmp['link'], 0, 1023),
|
||||
$valuesTmp['date'],
|
||||
time(),
|
||||
$valuesTmp['hash'],
|
||||
$valuesTmp['is_read'] ? 1 : 0,
|
||||
substr($valuesTmp['tags'], 0, 1023),
|
||||
$valuesTmp['id_feed'],
|
||||
substr($valuesTmp['guid'], 0, 760),
|
||||
);
|
||||
|
||||
$nb_month_old = max($conf->old_entries, 1);
|
||||
$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
|
||||
|
||||
$eDate = $entry->date(true);
|
||||
|
||||
if ($feedHistory == -2) {
|
||||
$feedHistory = $conf->keep_history_default;
|
||||
if ($this->updateEntryPrepared && $this->updateEntryPrepared->execute($values)) {
|
||||
return $this->bd->lastInsertId();
|
||||
} else {
|
||||
$info = $this->updateEntryPrepared == null ? array(2 => 'syntax error') : $this->updateEntryPrepared->errorInfo();
|
||||
if ($this->autoAddColumn($info)) {
|
||||
return $this->updateEntry($valuesTmp);
|
||||
}
|
||||
Minz_Log::error('SQL error updateEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
|
||||
. ' while updating entry with GUID ' . $valuesTmp['guid'] . ' in feed ' . $valuesTmp['id_feed']);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($existingGuids[$entry->guid()]) &&
|
||||
($feedHistory != 0 || $eDate >= $date_min || $entry->isFavorite())) {
|
||||
$values = $entry->toArray();
|
||||
|
||||
$useDeclaredDate = empty($existingGuids);
|
||||
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
|
||||
min(time(), $eDate) . uSecString() :
|
||||
uTimeString();
|
||||
|
||||
return $this->addEntry($values);
|
||||
}
|
||||
|
||||
// We don't return Entry object to avoid a research in DB
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +141,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
if (count($ids) < 1) {
|
||||
return 0;
|
||||
}
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` '
|
||||
. 'SET is_favorite=? '
|
||||
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)';
|
||||
@@ -296,11 +346,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
*
|
||||
* If $idMax equals 0, a deprecated debug message is logged
|
||||
*
|
||||
* @param integer $id feed ID
|
||||
* @param integer $id_feed feed ID
|
||||
* @param integer $idMax fail safe article ID
|
||||
* @return integer affected rows
|
||||
*/
|
||||
public function markReadFeed($id, $idMax = 0) {
|
||||
public function markReadFeed($id_feed, $idMax = 0) {
|
||||
if ($idMax == 0) {
|
||||
$idMax = time() . '000000';
|
||||
Minz_Log::debug('Calling markReadFeed(0) is deprecated!');
|
||||
@@ -310,7 +360,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` '
|
||||
. 'SET is_read=1 '
|
||||
. 'WHERE id_feed=? AND is_read=0 AND id <= ?';
|
||||
$values = array($id, $idMax);
|
||||
$values = array($id_feed, $idMax);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute($values))) {
|
||||
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
|
||||
@@ -324,7 +374,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` '
|
||||
. 'SET cache_nbUnreads=cache_nbUnreads-' . $affected
|
||||
. ' WHERE id=?';
|
||||
$values = array($id);
|
||||
$values = array($id_feed);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute($values))) {
|
||||
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
|
||||
@@ -338,7 +388,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
return $affected;
|
||||
}
|
||||
|
||||
public function searchByGuid($feed_id, $id) {
|
||||
public function searchByGuid($id_feed, $guid) {
|
||||
// un guid est unique pour un flux donné
|
||||
$sql = 'SELECT id, guid, title, author, '
|
||||
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
|
||||
@@ -347,8 +397,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
$stm = $this->bd->prepare($sql);
|
||||
|
||||
$values = array(
|
||||
$feed_id,
|
||||
$id
|
||||
$id_feed,
|
||||
$guid,
|
||||
);
|
||||
|
||||
$stm->execute($values);
|
||||
@@ -519,12 +569,52 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
|
||||
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||
}
|
||||
|
||||
public function listLastGuidsByFeed($id, $n) {
|
||||
$sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n);
|
||||
public function listHashForFeedGuids($id_feed, $guids) {
|
||||
if (count($guids) < 1) {
|
||||
return array();
|
||||
}
|
||||
$sql = 'SELECT guid, hex(hash) AS hexHash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
|
||||
$stm = $this->bd->prepare($sql);
|
||||
$values = array($id);
|
||||
$stm->execute($values);
|
||||
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||
$values = array($id_feed);
|
||||
$values = array_merge($values, $guids);
|
||||
if ($stm && $stm->execute($values)) {
|
||||
$result = array();
|
||||
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['guid']] = $row['hexHash'];
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
|
||||
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
|
||||
if ($this->autoAddColumn($info)) {
|
||||
return $this->listHashForFeedGuids($id_feed, $guids);
|
||||
}
|
||||
Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
|
||||
. ' while querying feed ' . $id_feed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateLastSeen($id_feed, $guids) {
|
||||
if (count($guids) < 1) {
|
||||
return 0;
|
||||
}
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` SET lastSeen=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
|
||||
$stm = $this->bd->prepare($sql);
|
||||
$values = array(time(), $id_feed);
|
||||
$values = array_merge($values, $guids);
|
||||
if ($stm && $stm->execute($values)) {
|
||||
return $stm->rowCount();
|
||||
} else {
|
||||
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
|
||||
if ($this->autoAddColumn($info)) {
|
||||
return $this->updateLastSeen($id_feed, $guids);
|
||||
}
|
||||
Minz_Log::error('SQL error updateLastSeen: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
|
||||
. ' while updating feed ' . $id_feed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function countUnreadRead() {
|
||||
|
||||
@@ -255,6 +255,7 @@ class FreshRSS_Feed extends Minz_Model {
|
||||
|
||||
$feed->__destruct(); //http://simplepie.org/wiki/faq/i_m_getting_memory_leaks
|
||||
unset($feed);
|
||||
//TODO: Return a different information in case of cache/no-cache, and give access to the GUIDs in case of cache
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` (
|
||||
`name` varchar(255) NOT NULL,
|
||||
`website` varchar(255) CHARACTER SET latin1,
|
||||
`description` text,
|
||||
`lastUpdate` int(11) DEFAULT 0,
|
||||
`lastUpdate` int(11) DEFAULT 0, -- Until year 2038
|
||||
`priority` tinyint(2) NOT NULL DEFAULT 10,
|
||||
`pathEntries` varchar(511) DEFAULT NULL,
|
||||
`httpAuth` varchar(511) DEFAULT NULL,
|
||||
@@ -40,7 +40,9 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
|
||||
`author` varchar(255),
|
||||
`content_bin` blob, -- v0.7
|
||||
`link` varchar(1023) CHARACTER SET latin1 NOT NULL,
|
||||
`date` int(11),
|
||||
`date` int(11), -- Until year 2038
|
||||
`lastSeen` INT(11) NOT NULL, -- v1.2, Until year 2038
|
||||
`hash` BINARY(16), -- v1.2
|
||||
`is_read` boolean NOT NULL DEFAULT 0,
|
||||
`is_favorite` boolean NOT NULL DEFAULT 0,
|
||||
`id_feed` SMALLINT, -- v0.7
|
||||
@@ -50,6 +52,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
|
||||
UNIQUE KEY (`id_feed`,`guid`), -- v0.7
|
||||
INDEX (`is_favorite`), -- v0.7
|
||||
INDEX (`is_read`) -- v0.7
|
||||
INDEX entry_lastSeen_index (`lastSeen`) -- v1.2
|
||||
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci
|
||||
ENGINE = INNODB;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ $SQL_CREATE_TABLES = array(
|
||||
`name` varchar(255) NOT NULL,
|
||||
`website` varchar(255),
|
||||
`description` text,
|
||||
`lastUpdate` int(11) DEFAULT 0,
|
||||
`lastUpdate` int(11) DEFAULT 0, -- Until year 2038
|
||||
`priority` tinyint(2) NOT NULL DEFAULT 10,
|
||||
`pathEntries` varchar(511) DEFAULT NULL,
|
||||
`httpAuth` varchar(511) DEFAULT NULL,
|
||||
@@ -38,7 +38,9 @@ $SQL_CREATE_TABLES = array(
|
||||
`author` varchar(255),
|
||||
`content` text,
|
||||
`link` varchar(1023) NOT NULL,
|
||||
`date` int(11),
|
||||
`date` int(11), -- Until year 2038
|
||||
`lastSeen` INT(11) NOT NULL, -- v1.2, Until year 2038
|
||||
`hash` BINARY(16), -- v1.2
|
||||
`is_read` boolean NOT NULL DEFAULT 0,
|
||||
`is_favorite` boolean NOT NULL DEFAULT 0,
|
||||
`id_feed` SMALLINT,
|
||||
@@ -50,6 +52,7 @@ $SQL_CREATE_TABLES = array(
|
||||
|
||||
'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `%1$sentry`(`is_favorite`);',
|
||||
'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `%1$sentry`(`is_read`);',
|
||||
'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `%1$sentry`(`lastSeen`);', //v1.2
|
||||
|
||||
'INSERT OR IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");',
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ function classAutoloader($class) {
|
||||
include(APP_PATH . '/Models/' . $components[1] . '.php');
|
||||
return;
|
||||
case 3: //Controllers, Exceptions
|
||||
@include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
|
||||
include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
|
||||
return;
|
||||
}
|
||||
} elseif (strpos($class, 'Minz') === 0) {
|
||||
|
||||
Reference in New Issue
Block a user