Răsfoiți Sursa

SimplePie HTTP 301 Moved Permanently

Add support for HTTP 301 Moved Permanently in SimplePie
FreshRSS will automatically update the address of a feed, only in this
case.
Alexandre Alapetite 11 ani în urmă
părinte
comite
63c9c47a76

+ 33 - 31
app/Controllers/feedController.php

@@ -162,38 +162,39 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 			}
 
 			Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true);
-		}
-
-		// GET request so we must ask confirmation to user
-		Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · ');
-		$this->view->categories = $this->catDAO->listCategories();
-		$this->view->feed = new FreshRSS_Feed($url);
-		try {
-			// We try to get some more information about the feed
-			$this->view->feed->load(true);
-			$this->view->load_ok = true;
-		} catch (Exception $e) {
-			$this->view->load_ok = false;
-		}
+		} else {
 
-		$feed = $feedDAO->searchByUrl($this->view->feed->url());
-		if ($feed) {
-			// Already subscribe so we redirect to the feed configuration page
-			$notif = array(
-				'type' => 'bad',
-				'content' => Minz_Translate::t(
-					'already_subscribed', $feed->name()
-				)
-			);
-			Minz_Session::_param('notification', $notif);
+			// GET request so we must ask confirmation to user
+			Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · ');
+			$this->view->categories = $this->catDAO->listCategories();
+			$this->view->feed = new FreshRSS_Feed($url);
+			try {
+				// We try to get some more information about the feed
+				$this->view->feed->load(true);
+				$this->view->load_ok = true;
+			} catch (Exception $e) {
+				$this->view->load_ok = false;
+			}
 
-			Minz_Request::forward(array(
-				'c' => 'configure',
-				'a' => 'feed',
-				'params' => array(
-					'id' => $feed->id()
-				)
-			), true);
+			$feed = $feedDAO->searchByUrl($this->view->feed->url());
+			if ($feed) {
+				// Already subscribe so we redirect to the feed configuration page
+				$notif = array(
+					'type' => 'bad',
+					'content' => Minz_Translate::t(
+						'already_subscribed', $feed->name()
+					)
+				);
+				Minz_Session::_param('notification', $notif);
+
+				Minz_Request::forward(array(
+					'c' => 'configure',
+					'a' => 'feed',
+					'params' => array(
+						'id' => $feed->id()
+					)
+				), true);
+			}
 		}
 	}
 
@@ -300,7 +301,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 					$feedDAO->commit();
 				}
 				$flux_update++;
-				if ($feed->url() !== $url) {	//URL has changed (auto-discovery)
+				if (($feed->url() !== $url)) {	//HTTP 301 Moved Permanently
+					Minz_Log::record('Feed ' . $url . ' moved permanently to ' . $feed->url(), Minz_Log::NOTICE);
 					$feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
 				}
 			} catch (FreshRSS_Feed_Exception $e) {

+ 24 - 17
app/Models/Feed.php

@@ -17,6 +17,7 @@ class FreshRSS_Feed extends Minz_Model {
 	private $error = false;
 	private $keep_history = -2;
 	private $hash = null;
+	private $lockPath = '';
 
 	public function __construct ($url, $validate=true) {
 		if ($validate) {
@@ -193,28 +194,35 @@ class FreshRSS_Feed extends Minz_Model {
 				}
 				$feed = customSimplePie();
 				$feed->set_feed_url ($url);
+				if (!$loadDetails) {	//Only activates auto-discovery when adding a new feed
+					$feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE);
+				}
 				$mtime = $feed->init();
 
 				if ((!$mtime) || $feed->error()) {
 					throw new FreshRSS_Feed_Exception ($feed->error() . ' [' . $url . ']');
 				}
 
-				// si on a utilisé l'auto-discover, notre url va avoir changé
-				$subscribe_url = $feed->subscribe_url ();
-				if ($subscribe_url !== null && $subscribe_url !== $this->url) {
-					if ($this->httpAuth != '') {
-						// on enlève les id si authentification HTTP
-						$subscribe_url = preg_replace ('#((.+)://)((.+)@)(.+)#', '${1}${5}', $subscribe_url);
-					}
-					$this->_url ($subscribe_url);
-				}
-
 				if ($loadDetails) {
+					// si on a utilisé l'auto-discover, notre url va avoir changé
+					$subscribe_url = $feed->subscribe_url(false);
+
 					$title = strtr(html_only_entity_decode($feed->get_title()), array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;'));	//HTML to HTML-PRE	//ENT_COMPAT except &
 					$this->_name ($title == '' ? $this->url : $title);
 
 					$this->_website(html_only_entity_decode($feed->get_link()));
 					$this->_description(html_only_entity_decode($feed->get_description()));
+				} else {
+					//The case of HTTP 301 Moved Permanently
+					$subscribe_url = $feed->subscribe_url(true);
+				}
+
+				if ($subscribe_url !== null && $subscribe_url !== $this->url) {
+					if ($this->httpAuth != '') {
+						// on enlève les id si authentification HTTP
+						$subscribe_url = preg_replace ('#((.+)://)((.+)@)(.+)#', '${1}${5}', $subscribe_url);
+					}
+					$this->_url ($subscribe_url);
 				}
 
 				if (($mtime === true) || ($mtime > $this->lastUpdate)) {
@@ -288,20 +296,19 @@ class FreshRSS_Feed extends Minz_Model {
 	}
 
 	function lock() {
-		$lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock';
-		if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) {
-			@unlink($lock);
+		$this->lockPath = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock';
+		if (file_exists($this->lockPath) && ((time() - @filemtime($this->lockPath)) > 3600)) {
+			@unlink($this->lockPath);
 		}
-		if (($handle = @fopen($lock, 'x')) === false) {
+		if (($handle = @fopen($this->lockPath, 'x')) === false) {
 			return false;
 		}
-		//register_shutdown_function('unlink', $lock);
+		//register_shutdown_function('unlink', $this->lockPath);
 		@fclose($handle);
 		return true;
 	}
 
 	function unlock() {
-		$lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock';
-		@unlink($lock);
+		@unlink($this->lockPath);
 	}
 }

+ 30 - 8
lib/SimplePie/SimplePie.php

@@ -445,6 +445,13 @@ class SimplePie
 	 */
 	public $feed_url;
 
+	/**
+	 * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
+	 * @see SimplePie::subscribe_url()
+	 * @access private
+	 */
+	public $permanent_url = null;	//FreshRSS
+
 	/**
 	 * @var object Instance of SimplePie_File to use as a feed
 	 * @see SimplePie::set_file()
@@ -735,6 +742,7 @@ class SimplePie
 		else
 		{
 			$this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
+			$this->permanent_url = $this->feed_url;	//FreshRSS
 		}
 	}
 
@@ -749,6 +757,7 @@ class SimplePie
 		if ($file instanceof SimplePie_File)
 		{
 			$this->feed_url = $file->url;
+			$this->permanent_url = $this->feed_url;	//FreshRSS
 			$this->file =& $file;
 			return true;
 		}
@@ -1602,7 +1611,7 @@ class SimplePie
 		}
 
 		$this->raw_data = $file->body;
-
+		$this->permanent_url = $file->permanent_url;	//FreshRSS
 		$headers = $file->headers;
 		$sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
 		$sniffed = $sniffer->get_type();
@@ -1788,26 +1797,39 @@ class SimplePie
 
 	/**
 	 * Get the URL for the feed
+	 * 
+	 * When the 'permanent' mode is enabled, returns the original feed URL,
+	 * except in the case of an `HTTP 301 Moved Permanently` status response,
+	 * in which case the location of the first redirection is returned.
 	 *
-	 * May or may not be different from the URL passed to {@see set_feed_url()},
+	 * When the 'permanent' mode is disabled (default),
+	 * may or may not be different from the URL passed to {@see set_feed_url()},
 	 * depending on whether auto-discovery was used.
 	 *
 	 * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
-	 * @todo If we have a perm redirect we should return the new URL
-	 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+	 * @todo Support <itunes:new-feed-url>
 	 * @todo Also, |atom:link|@rel=self
+	 * @param bool $permanent Permanent mode to return only the original URL or the first redirection
+	 *  iff it is a 301 redirection
 	 * @return string|null
 	 */
-	public function subscribe_url()
+	public function subscribe_url($permanent = false)
 	{
-		if ($this->feed_url !== null)
+		if ($permanent)	//FreshRSS
 		{
-			return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+			if ($this->permanent_url !== null)
+			{
+				return $this->sanitize($this->permanent_url, SIMPLEPIE_CONSTRUCT_IRI);
+			}
 		}
 		else
 		{
-			return null;
+			if ($this->feed_url !== null)
+			{
+				return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+			}
 		}
+		return null;
 	}
 
 	/**

+ 10 - 2
lib/SimplePie/SimplePie/File.php

@@ -64,6 +64,7 @@ class SimplePie_File
 	var $redirects = 0;
 	var $error;
 	var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+	var $permanent_url;	//FreshRSS
 
 	public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
 	{
@@ -74,6 +75,7 @@ class SimplePie_File
 			$url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
 		}
 		$this->url = $url;
+		$this->permanent_url = $url;	//FreshRSS
 		$this->useragent = $useragent;
 		if (preg_match('/^http(s)?:\/\//i', $url))
 		{
@@ -142,7 +144,10 @@ class SimplePie_File
 						{
 							$this->redirects++;
 							$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
-							return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+							$previousStatusCode = $this->status_code;
+							$this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+							$this->permanent_url = ($previousStatusCode == 301) ? $location : $url;	//FreshRSS
+							return;
 						}
 					}
 				}
@@ -224,7 +229,10 @@ class SimplePie_File
 							{
 								$this->redirects++;
 								$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
-								return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+								$previousStatusCode = $this->status_code;
+								$this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+								$this->permanent_url = ($previousStatusCode == 301) ? $location : $url;	//FreshRSS
+								return;
 							}
 							if (isset($this->headers['content-encoding']))
 							{