Merge pull request #831 from Alkarex/PubSubHubbub

PubSubHubbub
pull/864/head^2
Alexandre Alapetite 9 years ago
commit ee55fd13a9
  1. 6
      CHANGELOG.md
  2. 1
      README.fr.md
  3. 1
      README.md
  4. 67
      app/Controllers/feedController.php
  5. 150
      app/Models/Feed.php
  6. 1
      app/i18n/cz/conf.php
  7. 1
      app/i18n/cz/sub.php
  8. 1
      app/i18n/de/sub.php
  9. 1
      app/i18n/en/sub.php
  10. 1
      app/i18n/fr/sub.php
  11. 8
      app/views/helpers/feed/update.phtml
  12. 1
      constants.php
  13. 1
      data/PubSubHubbub/feeds/.gitignore
  14. 7
      data/PubSubHubbub/feeds/README.md
  15. 1
      data/PubSubHubbub/keys/.gitignore
  16. 4
      data/PubSubHubbub/keys/README.md
  17. 8
      data/config.default.php
  18. 2
      data/users/_/config.default.php
  19. 9
      lib/lib_rss.php
  20. 133
      p/api/pshb.php

@ -1,5 +1,11 @@
# Changelog
## 2015-xx-xx FreshRSS 1.1.2 (beta)
* Features
* Support for PubSubHubbub for instant notifications from compatible Web sites.
## 2015-05-31 FreshRSS 1.1.1 (beta)
* Features

@ -6,6 +6,7 @@ FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de [Leed]
Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.
Il permet de gérer plusieurs utilisateurs, et dispose d’un mode de lecture anonyme.
Il supporte [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) pour des notifications instantanées depuis les sites compatibles.
* Site officiel : http://freshrss.org
* Démo : http://demo.freshrss.org/

@ -6,6 +6,7 @@ FreshRSS is a self-hosted RSS feed aggregator such as [Leed](http://projet.idlem
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.
* Official website: http://freshrss.org
* Demo: http://demo.freshrss.org/

@ -168,6 +168,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Ok, feed has been added in database. Now we have to refresh entries.
$feed->_id($id);
$feed->faviconPrepare();
//$feed->pubSubHubbubPrepare(); //TODO: prepare PubSubHubbub already when adding the feed
$is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
@ -261,12 +262,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
* This action actualizes entries from one or several feeds.
*
* Parameters are:
* - id (default: false)
* - id (default: false): Feed ID
* - url (default: false): Feed URL
* - force (default: false)
* If id is not specified, all the feeds are actualized. But if force is
* If id and url are not specified, all the feeds are actualized. But if force is
* false, process stops at 10 feeds to avoid time execution problem.
*/
public function actualizeAction() {
public function actualizeAction($simplePiePush = null) {
@set_time_limit(300);
$feedDAO = FreshRSS_Factory::createFeedDao();
@ -274,14 +276,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Session::_param('actualize_feeds', false);
$id = Minz_Request::param('id');
$url = Minz_Request::param('url');
$force = Minz_Request::param('force');
// Create a list of feeds to actualize.
// If id is set and valid, corresponding feed is added to the list but
// alone in order to automatize further process.
$feeds = array();
if ($id) {
$feed = $feedDAO->searchById($id);
if ($id || $url) {
$feed = $id ? $feedDAO->searchById($id) : $feedDAO->searchByUrl($url);
if ($feed) {
$feeds[] = $feed;
}
@ -292,19 +295,32 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Calculate date of oldest entries we accept in DB.
$nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
$pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration.
$updated_feeds = 0;
$is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
foreach ($feeds as $feed) {
$url = $feed->url(); //For detection of HTTP 301
$pubSubHubbubEnabled = $feed->pubSubHubbubEnabled();
if ((!$simplePiePush) && (!$id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) {
$text = 'Skip pull of feed using PubSubHubbub: ' . $url;
//Minz_Log::debug($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
continue; //When PubSubHubbub is used, do not pull refresh so often
}
if (!$feed->lock()) {
Minz_Log::notice('Feed already being actualized: ' . $feed->url());
continue;
}
$url = $feed->url(); //For detection of HTTP 301
try {
// Load entries
if ($simplePiePush) {
$feed->loadEntries($simplePiePush); //Used by PubSubHubbub
} else {
$feed->load(false);
}
} catch (FreshRSS_Feed_Exception $e) {
Minz_Log::notice($e->getMessage());
$feedDAO->updateLastUpdate($feed->id(), true);
@ -368,6 +384,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
continue;
}
if ($pubSubHubbubEnabled && !$simplePiePush) { //We use push, but have discovered an article by pull!
$text = 'An article was discovered by pull although we use PubSubHubbub!: Feed ' . $url . ' GUID ' . $entry->guid();
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
Minz_Log::warning($text);
$pubSubHubbubEnabled = false;
$feed->pubSubHubbubError(true);
}
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
@ -398,13 +422,32 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$entryDAO->commit();
}
if ($feed->url() !== $url) {
// HTTP 301 Moved Permanently
if ($feed->hubUrl() && $feed->selfUrl()) { //selfUrl has priority for PubSubHubbub
if ($feed->selfUrl() !== $url) { //https://code.google.com/p/pubsubhubbub/wiki/MovingFeedsOrChangingHubs
$selfUrl = checkUrl($feed->selfUrl());
if ($selfUrl) {
Minz_Log::debug('PubSubHubbub unsubscribe ' . $feed->url());
if (!$feed->pubSubHubbubSubscribe(false)) { //Unsubscribe
Minz_Log::warning('Error while PubSubHubbub unsubscribing from ' . $feed->url());
}
$feed->_url($selfUrl, false);
Minz_Log::notice('Feed ' . $url . ' canonical address moved to ' . $feed->url());
$feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
}
}
}
elseif ($feed->url() !== $url) { // HTTP 301 Moved Permanently
Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url());
$feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
}
$feed->faviconPrepare();
if ($feed->pubSubHubbubPrepare()) {
Minz_Log::notice('PubSubHubbub subscribe ' . $feed->url());
if (!$feed->pubSubHubbubSubscribe(true)) { //Subscribe
Minz_Log::warning('Error while PubSubHubbub subscribing to ' . $feed->url());
}
}
$feed->unlock();
$updated_feeds++;
unset($feed);
@ -427,9 +470,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Session::_param('notification', $notif);
// No layout in ajax request.
$this->view->_useLayout(false);
return;
}
} else {
// Redirect to the main page with correct notification.
if ($updated_feeds === 1) {
$feed = reset($feeds);
@ -442,6 +483,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array());
}
}
return $updated_feeds;
}
/**
* This action changes the category of a feed.

@ -19,6 +19,8 @@ class FreshRSS_Feed extends Minz_Model {
private $ttl = -2;
private $hash = null;
private $lockPath = '';
private $hubUrl = '';
private $selfUrl = '';
public function __construct($url, $validate=true) {
if ($validate) {
@ -49,6 +51,12 @@ class FreshRSS_Feed extends Minz_Model {
public function url() {
return $this->url;
}
public function selfUrl() {
return $this->selfUrl;
}
public function hubUrl() {
return $this->hubUrl;
}
public function category() {
return $this->category;
}
@ -96,6 +104,16 @@ class FreshRSS_Feed extends Minz_Model {
public function ttl() {
return $this->ttl;
}
// public function ttlExpire() {
// $ttl = $this->ttl;
// if ($ttl == -2) { //Default
// $ttl = FreshRSS_Context::$user_conf->ttl_default;
// }
// if ($ttl == -1) { //Never
// $ttl = 64000000; //~2 years. Good enough for PubSubHubbub logic
// }
// return $this->lastUpdate + $ttl;
// }
public function nbEntries() {
if ($this->nbEntries < 0) {
$feedDAO = FreshRSS_Factory::createFeedDao();
@ -226,6 +244,11 @@ class FreshRSS_Feed extends Minz_Model {
throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']');
}
$links = $feed->get_links('self');
$this->selfUrl = isset($links[0]) ? $links[0] : null;
$links = $feed->get_links('hub');
$this->hubUrl = isset($links[0]) ? $links[0] : null;
if ($loadDetails) {
// si on a utilisé l'auto-discover, notre url va avoir changé
$subscribe_url = $feed->subscribe_url(false);
@ -259,7 +282,7 @@ class FreshRSS_Feed extends Minz_Model {
}
}
private function loadEntries($feed) {
public function loadEntries($feed) {
$entries = array();
foreach ($feed->get_items() as $item) {
@ -333,4 +356,129 @@ class FreshRSS_Feed extends Minz_Model {
function unlock() {
@unlink($this->lockPath);
}
//<PubSubHubbub>
function pubSubHubbubEnabled() {
$url = $this->selfUrl ? $this->selfUrl : $this->url;
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
if ($hubJson && empty($hubJson['error']) &&
(empty($hubJson['lease_end']) || $hubJson['lease_end'] > time())) {
return true;
}
}
return false;
}
function pubSubHubbubError($error = true) {
$url = $this->selfUrl ? $this->selfUrl : $this->url;
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
$hubJson = $hubFile ? json_decode($hubFile, true) : array();
if (!isset($hubJson['error']) || $hubJson['error'] !== (bool)$error) {
$hubJson['error'] = (bool)$error;
file_put_contents($hubFilename, json_encode($hubJson));
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t"
. 'Set error to ' . ($error ? 1 : 0) . ' for ' . $url . "\n", FILE_APPEND);
}
return false;
}
function pubSubHubbubPrepare() {
$key = '';
if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) {
$path = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl);
$hubFilename = $path . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
$text = 'Invalid JSON for PubSubHubbub: ' . $this->url;
Minz_Log::warning($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
return false;
}
if ((!empty($hubJson['lease_end'])) && ($hubJson['lease_end'] < (time() + (3600 * 23)))) { //TODO: Make a better policy
$text = 'PubSubHubbub lease ends at '
. date('c', empty($hubJson['lease_end']) ? time() : $hubJson['lease_end'])
. ' and needs renewal: ' . $this->url;
Minz_Log::warning($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
$key = $hubJson['key']; //To renew our lease
} elseif (((!empty($hubJson['error'])) || empty($hubJson['lease_end'])) &&
(empty($hubJson['lease_start']) || $hubJson['lease_start'] < time() - (3600 * 23))) { //Do not renew too often
$key = $hubJson['key']; //To renew our lease
}
} else {
@mkdir($path, 0777, true);
$key = sha1($path . FreshRSS_Context::$system_conf->salt . uniqid(mt_rand(), true));
$hubJson = array(
'hub' => $this->hubUrl,
'key' => $key,
);
file_put_contents($hubFilename, json_encode($hubJson));
@mkdir(PSHB_PATH . '/keys/');
file_put_contents(PSHB_PATH . '/keys/' . $key . '.txt', base64url_encode($this->selfUrl));
$text = 'PubSubHubbub prepared for ' . $this->url;
Minz_Log::debug($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
}
$currentUser = Minz_Session::param('currentUser');
if (ctype_alnum($currentUser) && !file_exists($path . '/' . $currentUser . '.txt')) {
touch($path . '/' . $currentUser . '.txt');
}
}
return $key;
}
//Parameter true to subscribe, false to unsubscribe.
function pubSubHubbubSubscribe($state) {
if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl) {
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
if ($hubFile === false) {
Minz_Log::warning('JSON not found for PubSubHubbub: ' . $this->url);
return false;
}
$hubJson = json_decode($hubFile, true);
if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
Minz_Log::warning('Invalid JSON for PubSubHubbub: ' . $this->url);
return false;
}
$callbackUrl = checkUrl(FreshRSS_Context::$system_conf->base_url . 'api/pshb.php?k=' . $hubJson['key']);
if ($callbackUrl == '') {
Minz_Log::warning('Invalid callback for PubSubHubbub: ' . $this->url);
return false;
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $this->hubUrl,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => _t('gen.freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')',
CURLOPT_POSTFIELDS => 'hub.verify=sync'
. '&hub.mode=' . ($state ? 'subscribe' : 'unsubscribe')
. '&hub.topic=' . urlencode($this->selfUrl)
. '&hub.callback=' . urlencode($callbackUrl)
)
);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" .
'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $this->selfUrl .
' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response . "\n", FILE_APPEND);
if (!$state) { //unsubscribe
$hubJson['lease_end'] = time() - 60;
file_put_contents($hubFilename, json_encode($hubJson));
}
return substr($info['http_code'], 0, 1) == '2';
}
return false;
}
//</PubSubHubbub>
}

@ -84,6 +84,7 @@ return array(
'articles_per_page' => 'Počet článků na stranu',
'auto_load_more' => 'Načítat další články dole na stránce',
'auto_remove_article' => 'Po přečtení články schovat',
'mark_updated_article_unread' => 'Označte aktualizované položky jako nepřečtené',
'confirm_enabled' => 'Vyžadovat potvrzení pro akci “označit vše jako přečtené”',
'display_articles_unfolded' => 'Ve výchozím stavu zobrazovat články otevřené',
'display_categories_unfolded' => 'Ve výchozím stavu zobrazovat kategorie zavřené',

@ -37,6 +37,7 @@ return array(
'url' => 'URL kanálu',
'validator' => 'Zkontrolovat platnost kanálu',
'website' => 'URL webové stránky',
'pubsubhubbub' => 'Okamžité oznámení s PubSubHubbub',
),
'import_export' => array(
'export' => 'Export',

@ -37,6 +37,7 @@ return array(
'url' => 'Feed-URL',
'validator' => 'Überprüfen Sie die Gültigkeit des Feeds',
'website' => 'Webseiten-URL',
'pubsubhubbub' => 'Sofortbenachrichtigung mit PubSubHubbub',
),
'import_export' => array(
'export' => 'Exportieren',

@ -37,6 +37,7 @@ return array(
'url' => 'Feed URL',
'validator' => 'Check the validity of the feed',
'website' => 'Website URL',
'pubsubhubbub' => 'Instant notification with PubSubHubbub',
),
'import_export' => array(
'export' => 'Export',

@ -37,6 +37,7 @@ return array(
'url' => 'URL du flux',
'validator' => 'Vérifier la valididé du flux',
'website' => 'URL du site',
'pubsubhubbub' => 'Notification instantanée par PubSubHubbub',
),
'import_export' => array(
'export' => 'Exporter',

@ -126,6 +126,14 @@
?></select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="pubsubhubbub"><?php echo _t('sub.feed.pubsubhubbub'); ?></label>
<div class="group-controls">
<label class="checkbox" for="pubsubhubbub">
<input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1"<?php echo $this->feed->pubSubHubbubEnabled() ? ' checked="checked"' : ''; ?> />
</label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>

@ -19,6 +19,7 @@ define('FRESHRSS_PATH', dirname(__FILE__));
define('UPDATE_FILENAME', DATA_PATH . '/update.php');
define('USERS_PATH', DATA_PATH . '/users');
define('CACHE_PATH', DATA_PATH . '/cache');
define('PSHB_PATH', DATA_PATH . '/PubSubHubbub');
define('LIB_PATH', FRESHRSS_PATH . '/lib');
define('APP_PATH', FRESHRSS_PATH . '/app');

@ -0,0 +1,7 @@
List of canonical URLS of the various feeds users have subscribed to.
Several users can have subscribed to the same feed.
* ./base64url(canonicalUrl)/
* ./!hub.json
* ./user1.txt
* ./user2.txt

@ -0,0 +1,4 @@
List of keys given to PubSubHubbub hubs
* ./sha1(random + salt).txt
* base64url(canonicalUrl)

@ -11,9 +11,11 @@ return array(
# Used to make crypto more unique. Generated during install.
'salt' => '',
# Leave empty for most cases.
# Ability to override the address of the FreshRSS instance,
# used when building absolute URLs.
# Specify address of the FreshRSS instance,
# used when building absolute URLs, e.g. for PubSubHubbub.
# Examples:
# https://example.net/FreshRSS/p/
# https://freshrss.example.net/
'base_url' => '',
# Natural language of the user interface, e.g. `en`, `fr`.

@ -25,7 +25,7 @@ return array (
# In the case an article has changed (e.g. updated content):
# Set to `true` to mark it unread, or `false` to leave it as-is.
'mark_updated_article_unread' => false,
'mark_updated_article_unread' => false, //TODO: -1 => ignore, 0 => update, 1 => update and mark as unread
'sort_order' => 'DESC',
'anon_access' => false,

@ -446,3 +446,12 @@ function array_push_unique(&$array, $value) {
function array_remove(&$array, $value) {
$array = array_diff($array, array($value));
}
//RFC 4648
function base64url_encode($data) {
return strtr(rtrim(base64_encode($data), '='), '+/', '-_');
}
//RFC 4648
function base64url_decode($data) {
return base64_decode(strtr($data, '-_', '+/'));
}

@ -0,0 +1,133 @@
<?php
require('../../constants.php');
require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader
define('MAX_PAYLOAD', 3145728);
header('Content-Type: text/plain; charset=UTF-8');
function logMe($text) {
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
}
$ORIGINAL_INPUT = file_get_contents('php://input', false, null, -1, MAX_PAYLOAD);
//logMe(print_r(array('_SERVER' => $_SERVER, '_GET' => $_GET, '_POST' => $_POST, 'INPUT' => $ORIGINAL_INPUT), true));
$key = isset($_GET['k']) ? substr($_GET['k'], 0, 128) : '';
if (!ctype_xdigit($key)) {
header('HTTP/1.1 422 Unprocessable Entity');
die('Invalid feed key format!');
}
chdir(PSHB_PATH);
$canonical64 = @file_get_contents('keys/' . $key . '.txt');
if ($canonical64 === false) {
header('HTTP/1.1 404 Not Found');
logMe('Error: Feed key not found!: ' . $key);
die('Feed key not found!');
}
$canonical64 = trim($canonical64);
if (!preg_match('/^[A-Za-z0-9_-]+$/D', $canonical64)) {
header('HTTP/1.1 500 Internal Server Error');
logMe('Error: Invalid key reference!: ' . $canonical64);
die('Invalid key reference!');
}
$hubFile = @file_get_contents('feeds/' . $canonical64 . '/!hub.json');
if ($hubFile === false) {
header('HTTP/1.1 404 Not Found');
//@unlink('keys/' . $key . '.txt');
logMe('Error: Feed info not found!: ' . $canonical64);
die('Feed info not found!');
}
$hubJson = json_decode($hubFile, true);
if (!$hubJson || empty($hubJson['key']) || $hubJson['key'] !== $key) {
header('HTTP/1.1 500 Internal Server Error');
logMe('Error: Invalid key cross-check!: ' . $key);
die('Invalid key cross-check!');
}
chdir('feeds/' . $canonical64);
$users = glob('*.txt', GLOB_NOSORT);
if (empty($users)) {
header('HTTP/1.1 410 Gone');
logMe('Error: Nobody is subscribed to this feed anymore!: ' . $canonical64);
die('Nobody is subscribed to this feed anymore!');
}
if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'subscribe') {
$leaseSeconds = empty($_REQUEST['hub_lease_seconds']) ? 0 : intval($_REQUEST['hub_lease_seconds']);
if ($leaseSeconds > 60) {
$hubJson['lease_end'] = time() + $leaseSeconds;
} else {
unset($hubJson['lease_end']);
}
$hubJson['lease_start'] = time();
if (!isset($hubJson['error'])) {
$hubJson['error'] = true; //Do not assume that PubSubHubbub works until the first successul push
}
file_put_contents('./!hub.json', json_encode($hubJson));
exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : '');
}
if ($ORIGINAL_INPUT == '') {
header('HTTP/1.1 422 Unprocessable Entity');
die('Missing XML payload!');
}
Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php');
$system_conf = Minz_Configuration::get('system');
$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!)
Minz_Translate::init('en');
Minz_Request::_param('ajax', true);
$feedController = new FreshRSS_feed_Controller();
$simplePie = customSimplePie();
$simplePie->set_raw_data($ORIGINAL_INPUT);
$simplePie->init();
unset($ORIGINAL_INPUT);
$links = $simplePie->get_links('self');
$self = isset($links[0]) ? $links[0] : null;
if ($self !== base64url_decode($canonical64)) {
//header('HTTP/1.1 422 Unprocessable Entity');
logMe('Warning: Self URL [' . $self . '] does not match registered canonical URL!: ' . base64url_decode($canonical64));
//die('Self URL does not match registered canonical URL!');
$self = base64url_decode($canonical64);
}
Minz_Request::_param('url', $self);
$nb = 0;
foreach ($users as $userFilename) {
$username = basename($userFilename, '.txt');
if (!file_exists(USERS_PATH . '/' . $username . '/config.php')) {
break;
}
try {
Minz_Session::_param('currentUser', $username);
Minz_Configuration::register('user',
join_path(USERS_PATH, $username, 'config.php'),
join_path(USERS_PATH, '_', 'config.default.php'));
FreshRSS_Context::init();
if ($feedController->actualizeAction($simplePie) > 0) {
$nb++;
}
} catch (Exception $e) {
logMe('Error: ' . $e->getMessage());
}
}
$simplePie->__destruct();
unset($simplePie);
if ($nb === 0) {
header('HTTP/1.1 410 Gone');
logMe('Error: Nobody is subscribed to this feed anymore after all!: ' . $self);
die('Nobody is subscribed to this feed anymore after all!');
} elseif (!empty($hubJson['error'])) {
$hubJson['error'] = false;
file_put_contents('./!hub.json', json_encode($hubJson));
}
logMe('PubSubHubbub ' . $self . ' done: ' . $nb);
exit('Done: ' . $nb . "\n");
Loading…
Cancel
Save