FeedFactory.php
4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Feed;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Http\HttpFactory;
use Joomla\Registry\Registry;
/**
* Feed factory class.
*
* @since 3.1.4
*/
class FeedFactory
{
/**
* @var array The list of registered parser classes for feeds.
* @since 3.1.4
*/
protected $parsers = array('rss' => 'Joomla\\CMS\\Feed\\Parser\\RssParser', 'feed' => 'Joomla\\CMS\\Feed\\Parser\\AtomParser');
/**
* Method to load a URI into the feed reader for parsing.
*
* @param string $uri The URI of the feed to load. Idn uris must be passed already converted to punycode.
*
* @return Feed
*
* @since 3.1.4
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function getFeed($uri)
{
// Create the XMLReader object.
$reader = new \XMLReader;
// Open the URI within the stream reader.
if (!@$reader->open($uri, null, LIBXML_NOERROR | LIBXML_ERR_NONE | LIBXML_NOWARNING))
{
// Retry with JHttpFactory that allow using CURL and Sockets as alternative method when available
// Adding a valid user agent string, otherwise some feed-servers returning an error
$options = new Registry;
$options->set('userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0');
try
{
$response = HttpFactory::getHttp($options)->get($uri);
}
catch (RuntimeException $e)
{
throw new \RuntimeException('Unable to open the feed.', $e->getCode(), $e);
}
if ($response->code != 200)
{
throw new \RuntimeException('Unable to open the feed.');
}
// Set the value to the XMLReader parser
if (!$reader->xml($response->body, null, LIBXML_NOERROR | LIBXML_ERR_NONE | LIBXML_NOWARNING))
{
throw new \RuntimeException('Unable to parse the feed.');
}
}
try
{
// Skip ahead to the root node.
while ($reader->read())
{
if ($reader->nodeType == \XMLReader::ELEMENT)
{
break;
}
}
}
catch (\Exception $e)
{
throw new \RuntimeException('Error reading feed.', $e->getCode(), $e);
}
// Setup the appropriate feed parser for the feed.
$parser = $this->_fetchFeedParser($reader->name, $reader);
return $parser->parse();
}
/**
* Method to register a FeedParser class for a given root tag name.
*
* @param string $tagName The root tag name for which to register the parser class.
* @param string $className The FeedParser class name to register for a root tag name.
* @param boolean $overwrite True to overwrite the parser class if one is already registered.
*
* @return FeedFactory
*
* @since 3.1.4
* @throws \InvalidArgumentException
*/
public function registerParser($tagName, $className, $overwrite = false)
{
// Verify that the class exists.
if (!class_exists($className))
{
throw new \InvalidArgumentException('The feed parser class ' . $className . ' does not exist.');
}
// Validate that the tag name is valid.
if (!preg_match('/\A(?!XML)[a-z][\w0-9-]*/i', $tagName))
{
throw new \InvalidArgumentException('The tag name ' . $tagName . ' is not valid.');
}
// Register the given parser class for the tag name if nothing registered or the overwrite flag set.
if (empty($this->parsers[$tagName]) || (bool) $overwrite)
{
$this->parsers[(string) $tagName] = (string) $className;
}
return $this;
}
/**
* Method to return a new JFeedParser object based on the registered parsers and a given type.
*
* @param string $type The name of parser to return.
* @param \XMLReader $reader The XMLReader instance for the feed.
*
* @return FeedParser
*
* @since 3.1.4
* @throws \LogicException
*/
private function _fetchFeedParser($type, \XMLReader $reader)
{
// Look for a registered parser for the feed type.
if (empty($this->parsers[$type]))
{
throw new \LogicException('No registered feed parser for type ' . $type . '.');
}
return new $this->parsers[$type]($reader);
}
}