Version Description
Download this release
Release Info
Developer | radgeek |
Plugin | FeedWordPress |
Version | 0.981 |
Comparing to | |
See all releases |
Code changes from version 0.98 to 0.981
- ChangeLog.text +46 -0
- OPTIONAL/wp-includes/rss-functions.php +3 -1634
- OPTIONAL/wp-includes/rss.php +1635 -0
- README.text +18 -16
- wp-content/plugins/feedwordpress.php +373 -232
ChangeLog.text
CHANGED
@@ -1,6 +1,52 @@
|
|
1 |
FeedWordPress Change Log
|
2 |
========================
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
Changes from 0.97 to 0.98
|
5 |
--------------------------
|
6 |
|
1 |
FeedWordPress Change Log
|
2 |
========================
|
3 |
|
4 |
+
Changes from 0.98 to 0.981
|
5 |
+
--------------------------
|
6 |
+
|
7 |
+
Version 0.981 is a narrowly targeted bugfix and compatibility release, whose
|
8 |
+
main purpose is to resolve a major outstanding problem: the incompatibility
|
9 |
+
between version 0.98 of WordPress and the recently released WordPress 2.1.
|
10 |
+
|
11 |
+
* WORDPRESS 2.1 COMPATIBILITY: FeedWordPress is now compatible with
|
12 |
+
WordPress 2.1, as well as retaining its existing support for WordPress
|
13 |
+
2.0 and 1.5. Incompatibilities that resulted in database warnings, fatal
|
14 |
+
errors, and which prevented FeedWordPress from syndicating new posts,
|
15 |
+
have been eliminated.
|
16 |
+
|
17 |
+
* RSS-FUNCTIONS.PHP RENAMED TO RSS.PHP: if you use the upgraded MagpieRSS
|
18 |
+
replacement that's included with FeedWordPress, be sure to note that
|
19 |
+
there are now *two* files to upload from the `OPTIONAL/wp-includes`
|
20 |
+
subdirectory in order to carry out the upgrade: rss-functions.php and
|
21 |
+
rss.php. **It is necessary to upload both files**, due to a change in
|
22 |
+
the file naming scheme in WordPress 2.1, and it is necessary to do so
|
23 |
+
whether you are using WordPress 2.1 or not. If you only upload the
|
24 |
+
`rss-functions.php` file as in previous installations you will not have
|
25 |
+
a working copy of MagpieRSS; the rss.php file contains the actual code.
|
26 |
+
|
27 |
+
* DATE BUG AFFECTING SOME PHP INSTALLATIONS RESOLVED: due to a subtle bug
|
28 |
+
in parse_w3cdtf(), some installations of PHP encountered problems with
|
29 |
+
FeedWordPress's attempt to date posts, which would cause some new posts
|
30 |
+
on Atom feeds to be dated as if they had apppeared in 1969 or 1970
|
31 |
+
(thus, effectively, never appearing on front apge at all). This bug in
|
32 |
+
the date handling should now be fixed.
|
33 |
+
|
34 |
+
* PHP <?=...?> SHORT FORM ELIMINATED: some installations of PHP do not
|
35 |
+
allow the <?=...?> short form for printing PHP values, which was used
|
36 |
+
extensively in the FeedWordPress interface code. Since this could cause
|
37 |
+
fatal errors for users with the wrong installation of PHP, the short
|
38 |
+
form has been replaced with full PHP echo statements, and is no longer
|
39 |
+
used in FeedWordPress.
|
40 |
+
|
41 |
+
* BETTER USER INTERFACE INTEGRATION WITH WORDPRESS 2.x: Some minor changes
|
42 |
+
have been made to help the FeedWordPress interface pages blend in better
|
43 |
+
with the user interface when running under WordPress 2.x.
|
44 |
+
|
45 |
+
* GLOBAL CATEGORIES BUG RESOLVED: a bug that prevented some users from
|
46 |
+
setting one or more categories to apply to syndicated posts from all
|
47 |
+
feeds (using the checkbox interface under Options --> Syndication) has
|
48 |
+
been resolved.
|
49 |
+
|
50 |
Changes from 0.97 to 0.98
|
51 |
--------------------------
|
52 |
|
OPTIONAL/wp-includes/rss-functions.php
CHANGED
@@ -1,1635 +1,4 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
* WordPress development team <http://www.wordpress.org/>
|
6 |
-
* Charles Johnson <technophilia@radgeek.com>
|
7 |
-
* Version: 0.8wp (2005.10.14)
|
8 |
-
* License: GPL
|
9 |
-
*
|
10 |
-
* Provenance:
|
11 |
-
*
|
12 |
-
* This is a drop-in replacement for the `rss-functions.php` provided with the
|
13 |
-
* WordPress 1.5 distribution, which upgrades the version of MagpieRSS from 0.51
|
14 |
-
* to 0.8a. The update improves handling of character encoding, supports
|
15 |
-
* multiple categories for posts (using <dc:subject> or <category>), supports
|
16 |
-
* Atom 1.0, and implements many other useful features. The file is derived from
|
17 |
-
* a combination of (1) the WordPress development team's modifications to
|
18 |
-
* MagpieRSS 0.51 and (2) the latest bleeding-edge updates to the "official"
|
19 |
-
* MagpieRSS software, including Kellan's original work and some substantial
|
20 |
-
* updates by Charles Johnson. All possible through the magic of the GPL. Yay
|
21 |
-
* for free software!
|
22 |
-
*
|
23 |
-
* Differences from the main branch of MagpieRSS:
|
24 |
-
*
|
25 |
-
* 1. Everything in rss_parse.inc, rss_fetch.inc, rss_cache.inc, and
|
26 |
-
* rss_utils.inc is included in one file.
|
27 |
-
*
|
28 |
-
* 2. MagpieRSS returns the WordPress version as the user agent, rather than
|
29 |
-
* Magpie
|
30 |
-
*
|
31 |
-
* 3. class RSSCache is a modified version by WordPress developers, which
|
32 |
-
* caches feeds in the WordPress database (in the options table), rather
|
33 |
-
* than writing external files directly.
|
34 |
-
*
|
35 |
-
* 4. There are two WordPress-specific functions, get_rss() and wp_rss()
|
36 |
-
*
|
37 |
-
* Differences from the version of MagpieRSS packaged with WordPress:
|
38 |
-
*
|
39 |
-
* 1. Support for translation between multiple character encodings. Under
|
40 |
-
* PHP 5 this is very nicely handled by the XML parsing library. Under PHP
|
41 |
-
* 4 we need to do a little bit of work ourselves, using either iconv or
|
42 |
-
* mb_convert_encoding if it is not one of the (extremely limited) number
|
43 |
-
* of character sets that PHP 4's XML module can handle natively.
|
44 |
-
*
|
45 |
-
* 2. Numerous bug fixes.
|
46 |
-
*
|
47 |
-
* 3. The parser class MagpieRSS has been substantially revised to better
|
48 |
-
* support popular features such as enclosures and multiple categories,
|
49 |
-
* and to support the new Atom 1.0 IETF standard. (Atom feeds are
|
50 |
-
* normalized so as to make the data available using terminology from
|
51 |
-
* either Atom 0.3 or Atom 1.0. Atom 0.3 backward-compatibility is provided
|
52 |
-
* to allow existing software to easily begin accepting Atom 1.0 data; new
|
53 |
-
* software SHOULD NOT depend on the 0.3 terminology, but rather use the
|
54 |
-
* normalization as a convenient way to keep supporting 0.3 feeds while
|
55 |
-
* they linger in the world.)
|
56 |
-
*
|
57 |
-
* The upgraded MagpieRSS can also now handle some content constructs that
|
58 |
-
* had not been handled well by previous versions of Magpie (such as the
|
59 |
-
* use of namespaced XHTML in <xhtml:body> or <xhtml:div> elements to
|
60 |
-
* provide the full content of posts in RSS 2.0 feeds).
|
61 |
-
*
|
62 |
-
* Unlike previous versions of MagpieRSS, this version can parse multiple
|
63 |
-
* instances of the same child element in item/entry and channel/feed
|
64 |
-
* containers. This is done using simple counters next to the element
|
65 |
-
* names: the first <category> element on an RSS item, for example, can be
|
66 |
-
* found in $item['category'] (thus preserving backward compatibility); the
|
67 |
-
* second in $item['category#2'], the third in $item['category#3'], and so
|
68 |
-
* on. The number of categories applied to the item can be found in
|
69 |
-
* $item['category#']
|
70 |
-
*
|
71 |
-
* Also unlike previous versions of MagpieRSS, this version allows you to
|
72 |
-
* access the values of elements' attributes as well as the content they
|
73 |
-
* contain. This can be done using a simple syntax inspired by XPath: to
|
74 |
-
* access the type attribute of an RSS 2.0 enclosure, for example, you
|
75 |
-
* need only access `$item['enclosure@type']`. A comma-separated list of
|
76 |
-
* attributes for the enclosure element is stored in `$item['enclosure@']`.
|
77 |
-
* (This syntax interacts easily with the syntax for multiple categories;
|
78 |
-
* for example, the value of the `scheme` attribute for the fourth category
|
79 |
-
* element on a particular item is stored in `$item['category#4@scheme']`.)
|
80 |
-
*
|
81 |
-
* Note also that this implementation IS NOT backward-compatible with the
|
82 |
-
* kludges that were used to hack in support for multiple categories and
|
83 |
-
* for enclosures in upgraded versions of MagpieRSS distributed with
|
84 |
-
* previous versions of FeedWordPress. If your hacks or filter plugins
|
85 |
-
* depended on the old way of doing things... well, I warned you that they
|
86 |
-
* might not be permanent. Sorry!
|
87 |
-
*/
|
88 |
-
|
89 |
-
define('RSS', 'RSS');
|
90 |
-
define('ATOM', 'Atom');
|
91 |
-
|
92 |
-
################################################################################
|
93 |
-
## WordPress: make some settings WordPress-appropriate #########################
|
94 |
-
################################################################################
|
95 |
-
|
96 |
-
define('MAGPIE_USER_AGENT', 'WordPress/' . $wp_version . '(+http://www.wordpress.org)');
|
97 |
-
|
98 |
-
$wp_encoding = get_settings('blog_charset');
|
99 |
-
define('MAGPIE_OUTPUT_ENCODING', ($wp_encoding?$wp_encoding:'ISO-8859-1'));
|
100 |
-
|
101 |
-
################################################################################
|
102 |
-
## rss_parse.inc: from MagpieRSS 0.8a ##########################################
|
103 |
-
################################################################################
|
104 |
-
|
105 |
-
/**
|
106 |
-
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
|
107 |
-
*
|
108 |
-
* see: rss_fetch.inc for a simpler interface with integrated caching support
|
109 |
-
*
|
110 |
-
*/
|
111 |
-
class MagpieRSS {
|
112 |
-
var $parser;
|
113 |
-
|
114 |
-
var $current_item = array(); // item currently being parsed
|
115 |
-
var $items = array(); // collection of parsed items
|
116 |
-
var $channel = array(); // hash of channel fields
|
117 |
-
var $textinput = array();
|
118 |
-
var $image = array();
|
119 |
-
var $feed_type;
|
120 |
-
var $feed_version;
|
121 |
-
var $encoding = ''; // output encoding of parsed rss
|
122 |
-
|
123 |
-
var $_source_encoding = ''; // only set if we have to parse xml prolog
|
124 |
-
|
125 |
-
var $ERROR = "";
|
126 |
-
var $WARNING = "";
|
127 |
-
|
128 |
-
// define some constants
|
129 |
-
|
130 |
-
var $_ATOM_CONTENT_CONSTRUCTS = array(
|
131 |
-
'content', 'summary', 'title', /* common */
|
132 |
-
'info', 'tagline', 'copyright', /* Atom 0.3 */
|
133 |
-
'rights', 'subtitle', /* Atom 1.0 */
|
134 |
-
);
|
135 |
-
var $_XHTML_CONTENT_CONSTRUCTS = array('body', 'div');
|
136 |
-
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
|
137 |
-
|
138 |
-
// parser variables, useless if you're not a parser, treat as private
|
139 |
-
var $stack = array(); // parser stack
|
140 |
-
var $inchannel = false;
|
141 |
-
var $initem = false;
|
142 |
-
|
143 |
-
var $incontent = array(); // non-empty if in namespaced XML content field
|
144 |
-
var $exclude_top = false; // true when Atom 1.0 type="xhtml"
|
145 |
-
|
146 |
-
var $intextinput = false;
|
147 |
-
var $inimage = false;
|
148 |
-
var $current_namespace = false;
|
149 |
-
|
150 |
-
/**
|
151 |
-
* Set up XML parser, parse source, and return populated RSS object..
|
152 |
-
*
|
153 |
-
* @param string $source string containing the RSS to be parsed
|
154 |
-
*
|
155 |
-
* NOTE: Probably a good idea to leave the encoding options alone unless
|
156 |
-
* you know what you're doing as PHP's character set support is
|
157 |
-
* a little weird.
|
158 |
-
*
|
159 |
-
* NOTE: A lot of this is unnecessary but harmless with PHP5
|
160 |
-
*
|
161 |
-
*
|
162 |
-
* @param string $output_encoding output the parsed RSS in this character
|
163 |
-
* set defaults to ISO-8859-1 as this is PHP's
|
164 |
-
* default.
|
165 |
-
*
|
166 |
-
* NOTE: might be changed to UTF-8 in future
|
167 |
-
* versions.
|
168 |
-
*
|
169 |
-
* @param string $input_encoding the character set of the incoming RSS source.
|
170 |
-
* Leave blank and Magpie will try to figure it
|
171 |
-
* out.
|
172 |
-
*
|
173 |
-
*
|
174 |
-
* @param bool $detect_encoding if false Magpie won't attempt to detect
|
175 |
-
* source encoding. (caveat emptor)
|
176 |
-
*
|
177 |
-
*/
|
178 |
-
function MagpieRSS ($source, $output_encoding='ISO-8859-1',
|
179 |
-
$input_encoding=null, $detect_encoding=true)
|
180 |
-
{
|
181 |
-
# if PHP xml isn't compiled in, die
|
182 |
-
#
|
183 |
-
if (!function_exists('xml_parser_create')) {
|
184 |
-
$this->error( "Failed to load PHP's XML Extension. " .
|
185 |
-
"http://www.php.net/manual/en/ref.xml.php",
|
186 |
-
E_USER_ERROR );
|
187 |
-
}
|
188 |
-
|
189 |
-
list($parser, $source) = $this->create_parser($source,
|
190 |
-
$output_encoding, $input_encoding, $detect_encoding);
|
191 |
-
|
192 |
-
|
193 |
-
if (!is_resource($parser)) {
|
194 |
-
$this->error( "Failed to create an instance of PHP's XML parser. " .
|
195 |
-
"http://www.php.net/manual/en/ref.xml.php",
|
196 |
-
E_USER_ERROR );
|
197 |
-
}
|
198 |
-
|
199 |
-
|
200 |
-
$this->parser = $parser;
|
201 |
-
|
202 |
-
# pass in parser, and a reference to this object
|
203 |
-
# setup handlers
|
204 |
-
#
|
205 |
-
xml_set_object( $this->parser, $this );
|
206 |
-
xml_set_element_handler($this->parser,
|
207 |
-
'feed_start_element', 'feed_end_element' );
|
208 |
-
|
209 |
-
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
|
210 |
-
|
211 |
-
$status = xml_parse( $this->parser, $source );
|
212 |
-
|
213 |
-
if (! $status ) {
|
214 |
-
$errorcode = xml_get_error_code( $this->parser );
|
215 |
-
if ( $errorcode != XML_ERROR_NONE ) {
|
216 |
-
$xml_error = xml_error_string( $errorcode );
|
217 |
-
$error_line = xml_get_current_line_number($this->parser);
|
218 |
-
$error_col = xml_get_current_column_number($this->parser);
|
219 |
-
$errormsg = "$xml_error at line $error_line, column $error_col";
|
220 |
-
|
221 |
-
$this->error( $errormsg );
|
222 |
-
}
|
223 |
-
}
|
224 |
-
|
225 |
-
xml_parser_free( $this->parser );
|
226 |
-
|
227 |
-
$this->normalize();
|
228 |
-
}
|
229 |
-
|
230 |
-
function feed_start_element($p, $element, &$attrs) {
|
231 |
-
$el = $element = strtolower($element);
|
232 |
-
$attrs = array_change_key_case($attrs, CASE_LOWER);
|
233 |
-
|
234 |
-
// check for a namespace, and split if found
|
235 |
-
if ( empty($this->incontent) ) { // Don't munge content tags
|
236 |
-
$ns = false;
|
237 |
-
if ( strpos( $element, ':' ) ) {
|
238 |
-
list($ns, $el) = split( ':', $element, 2);
|
239 |
-
}
|
240 |
-
if ( $ns and $ns != 'rdf' ) {
|
241 |
-
$this->current_namespace = $ns;
|
242 |
-
}
|
243 |
-
}
|
244 |
-
|
245 |
-
# if feed type isn't set, then this is first element of feed
|
246 |
-
# identify feed from root element
|
247 |
-
#
|
248 |
-
if (!isset($this->feed_type) ) {
|
249 |
-
if ( $el == 'rdf' ) {
|
250 |
-
$this->feed_type = RSS;
|
251 |
-
$this->feed_version = '1.0';
|
252 |
-
}
|
253 |
-
elseif ( $el == 'rss' ) {
|
254 |
-
$this->feed_type = RSS;
|
255 |
-
$this->feed_version = $attrs['version'];
|
256 |
-
}
|
257 |
-
elseif ( $el == 'feed' ) {
|
258 |
-
$this->feed_type = ATOM;
|
259 |
-
if ($attrs['xmlns'] == 'http://www.w3.org/2005/Atom') { // Atom 1.0
|
260 |
-
$this->feed_version = '1.0';
|
261 |
-
}
|
262 |
-
else { // Atom 0.3, probably.
|
263 |
-
$this->feed_version = $attrs['version'];
|
264 |
-
}
|
265 |
-
$this->inchannel = true;
|
266 |
-
}
|
267 |
-
return;
|
268 |
-
}
|
269 |
-
|
270 |
-
// if we're inside a namespaced content construct, treat tags as text
|
271 |
-
if ( !empty($this->incontent) )
|
272 |
-
{
|
273 |
-
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
274 |
-
// if tags are inlined, then flatten
|
275 |
-
$attrs_str = join(' ',
|
276 |
-
array_map('map_attrs',
|
277 |
-
array_keys($attrs),
|
278 |
-
array_values($attrs) ) );
|
279 |
-
if (strlen($attrs_str) > 0) $attrs_str = ' '.$attrs_str;
|
280 |
-
|
281 |
-
$this->append_content( "<{$element}{$attrs_str}>" );
|
282 |
-
}
|
283 |
-
array_push($this->incontent, $el); // stack for parsing content XML
|
284 |
-
}
|
285 |
-
|
286 |
-
elseif ( $el == 'channel' )
|
287 |
-
{
|
288 |
-
$this->inchannel = true;
|
289 |
-
}
|
290 |
-
|
291 |
-
elseif ($el == 'item' or $el == 'entry' )
|
292 |
-
{
|
293 |
-
$this->initem = true;
|
294 |
-
if ( isset($attrs['rdf:about']) ) {
|
295 |
-
$this->current_item['about'] = $attrs['rdf:about'];
|
296 |
-
}
|
297 |
-
}
|
298 |
-
|
299 |
-
// if we're in the default namespace of an RSS feed,
|
300 |
-
// record textinput or image fields
|
301 |
-
elseif (
|
302 |
-
$this->feed_type == RSS and
|
303 |
-
$this->current_namespace == '' and
|
304 |
-
$el == 'textinput' )
|
305 |
-
{
|
306 |
-
$this->intextinput = true;
|
307 |
-
}
|
308 |
-
|
309 |
-
elseif (
|
310 |
-
$this->feed_type == RSS and
|
311 |
-
$this->current_namespace == '' and
|
312 |
-
$el == 'image' )
|
313 |
-
{
|
314 |
-
$this->inimage = true;
|
315 |
-
}
|
316 |
-
|
317 |
-
// set stack[0] to current element
|
318 |
-
else {
|
319 |
-
// Atom support many links per containing element.
|
320 |
-
// Magpie treats link elements of type rel='alternate'
|
321 |
-
// as being equivalent to RSS's simple link element.
|
322 |
-
|
323 |
-
$atom_link = false;
|
324 |
-
if ($this->feed_type == ATOM and $el == 'link') {
|
325 |
-
$atom_link = true;
|
326 |
-
if (isset($attrs['rel']) and $attrs['rel'] != 'alternate') {
|
327 |
-
$el = $el . "_" . $attrs['rel']; // pseudo-element names for Atom link elements
|
328 |
-
}
|
329 |
-
}
|
330 |
-
# handle atom content constructs
|
331 |
-
elseif ( $this->feed_type == ATOM and in_array($el, $this->_ATOM_CONTENT_CONSTRUCTS) )
|
332 |
-
{
|
333 |
-
// avoid clashing w/ RSS mod_content
|
334 |
-
if ($el == 'content' ) {
|
335 |
-
$el = 'atom_content';
|
336 |
-
}
|
337 |
-
|
338 |
-
// assume that everything accepts namespaced XML
|
339 |
-
// (that will pass through some non-validating feeds;
|
340 |
-
// but so what? this isn't a validating parser)
|
341 |
-
$this->incontent = array();
|
342 |
-
array_push($this->incontent, $el); // start a stack
|
343 |
-
|
344 |
-
if (
|
345 |
-
isset($attrs['type'])
|
346 |
-
and trim(strtolower($attrs['type']))=='xhtml'
|
347 |
-
) {
|
348 |
-
$this->exclude_top = true;
|
349 |
-
} else {
|
350 |
-
$this->exclude_top = false;
|
351 |
-
}
|
352 |
-
}
|
353 |
-
# Handle inline XHTML body elements --CWJ
|
354 |
-
elseif (
|
355 |
-
($this->current_namespace=='xhtml' or (isset($attrs['xmlns']) and $attrs['xmlns'] == 'http://www.w3.org/1999/xhtml'))
|
356 |
-
and in_array($el, $this->_XHTML_CONTENT_CONSTRUCTS) )
|
357 |
-
{
|
358 |
-
$this->current_namespace = 'xhtml';
|
359 |
-
$this->incontent = array();
|
360 |
-
array_push($this->incontent, $el); // start a stack
|
361 |
-
$this->exclude_top = false;
|
362 |
-
}
|
363 |
-
|
364 |
-
array_unshift($this->stack, $el);
|
365 |
-
$elpath = join('_', array_reverse($this->stack));
|
366 |
-
|
367 |
-
$n = $this->element_count($elpath);
|
368 |
-
$this->element_count($elpath, $n+1);
|
369 |
-
|
370 |
-
if ($n > 0) {
|
371 |
-
array_shift($this->stack);
|
372 |
-
array_unshift($this->stack, $el.'#'.($n+1));
|
373 |
-
$elpath = join('_', array_reverse($this->stack));
|
374 |
-
}
|
375 |
-
|
376 |
-
// this makes the baby Jesus cry, but we can't do it in normalize()
|
377 |
-
// because we've made the element name for Atom links unpredictable
|
378 |
-
// by tacking on the relation to the end. -CWJ
|
379 |
-
if ($atom_link and isset($attrs['href'])) {
|
380 |
-
$this->append($elpath, $attrs['href']);
|
381 |
-
}
|
382 |
-
|
383 |
-
// add attributes
|
384 |
-
if (count($attrs) > 0) {
|
385 |
-
$this->append($elpath.'@', join(',', array_keys($attrs)));
|
386 |
-
foreach ($attrs as $attr => $value) {
|
387 |
-
$this->append($elpath.'@'.$attr, $value);
|
388 |
-
}
|
389 |
-
}
|
390 |
-
}
|
391 |
-
}
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
function feed_cdata ($p, $text) {
|
396 |
-
|
397 |
-
if ($this->incontent) {
|
398 |
-
$this->append_content( $text );
|
399 |
-
}
|
400 |
-
else {
|
401 |
-
$current_el = join('_', array_reverse($this->stack));
|
402 |
-
$this->append($current_el, $text);
|
403 |
-
}
|
404 |
-
}
|
405 |
-
|
406 |
-
function feed_end_element ($p, $el) {
|
407 |
-
$el = strtolower($el);
|
408 |
-
|
409 |
-
if ( $this->incontent ) {
|
410 |
-
$opener = array_pop($this->incontent);
|
411 |
-
|
412 |
-
// Don't get bamboozled by namespace voodoo
|
413 |
-
if (strpos($el, ':')) { list($ns, $closer) = split(':', $el); }
|
414 |
-
else { $ns = false; $closer = $el; }
|
415 |
-
|
416 |
-
// Don't get bamboozled by our munging of <atom:content>, either
|
417 |
-
if ($this->feed_type == ATOM and $closer == 'content') {
|
418 |
-
$closer = 'atom_content';
|
419 |
-
}
|
420 |
-
|
421 |
-
// balance tags properly
|
422 |
-
// note: i don't think this is actually neccessary
|
423 |
-
if ($opener != $closer) {
|
424 |
-
array_push($this->incontent, $opener);
|
425 |
-
$this->append_content("<$el />");
|
426 |
-
} elseif ($this->incontent) { // are we in the content construct still?
|
427 |
-
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
428 |
-
$this->append_content("</$el>");
|
429 |
-
}
|
430 |
-
} else { // shift the opening of the content construct off the normal stack
|
431 |
-
array_shift( $this->stack );
|
432 |
-
}
|
433 |
-
}
|
434 |
-
elseif ( $el == 'item' or $el == 'entry' )
|
435 |
-
{
|
436 |
-
$this->items[] = $this->current_item;
|
437 |
-
$this->current_item = array();
|
438 |
-
$this->initem = false;
|
439 |
-
|
440 |
-
$this->current_category = 0;
|
441 |
-
}
|
442 |
-
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
|
443 |
-
{
|
444 |
-
$this->intextinput = false;
|
445 |
-
}
|
446 |
-
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
|
447 |
-
{
|
448 |
-
$this->inimage = false;
|
449 |
-
}
|
450 |
-
elseif ($el == 'channel' or $el == 'feed' )
|
451 |
-
{
|
452 |
-
$this->inchannel = false;
|
453 |
-
}
|
454 |
-
else {
|
455 |
-
array_shift( $this->stack );
|
456 |
-
}
|
457 |
-
|
458 |
-
if ( !$this->incontent ) { // Don't munge the namespace after finishing with elements in namespaced content constructs -CWJ
|
459 |
-
$this->current_namespace = false;
|
460 |
-
}
|
461 |
-
}
|
462 |
-
|
463 |
-
function concat (&$str1, $str2="") {
|
464 |
-
if (!isset($str1) ) {
|
465 |
-
$str1="";
|
466 |
-
}
|
467 |
-
$str1 .= $str2;
|
468 |
-
}
|
469 |
-
|
470 |
-
function append_content($text) {
|
471 |
-
if ( $this->initem ) {
|
472 |
-
if ($this->current_namespace) {
|
473 |
-
$this->concat( $this->current_item[$this->current_namespace][ reset($this->incontent) ], $text );
|
474 |
-
} else {
|
475 |
-
$this->concat( $this->current_item[ reset($this->incontent) ], $text );
|
476 |
-
}
|
477 |
-
}
|
478 |
-
elseif ( $this->inchannel ) {
|
479 |
-
if ($this->current_namespace) {
|
480 |
-
$this->concat( $this->channel[$this->current_namespace][ reset($this->incontent) ], $text );
|
481 |
-
} else {
|
482 |
-
$this->concat( $this->channel[ reset($this->incontent) ], $text );
|
483 |
-
}
|
484 |
-
}
|
485 |
-
}
|
486 |
-
|
487 |
-
// smart append - field and namespace aware
|
488 |
-
function append($el, $text) {
|
489 |
-
if (!$el) {
|
490 |
-
return;
|
491 |
-
}
|
492 |
-
if ( $this->current_namespace )
|
493 |
-
{
|
494 |
-
if ( $this->initem ) {
|
495 |
-
$this->concat(
|
496 |
-
$this->current_item[ $this->current_namespace ][ $el ], $text);
|
497 |
-
}
|
498 |
-
elseif ($this->inchannel) {
|
499 |
-
$this->concat(
|
500 |
-
$this->channel[ $this->current_namespace][ $el ], $text );
|
501 |
-
}
|
502 |
-
elseif ($this->intextinput) {
|
503 |
-
$this->concat(
|
504 |
-
$this->textinput[ $this->current_namespace][ $el ], $text );
|
505 |
-
}
|
506 |
-
elseif ($this->inimage) {
|
507 |
-
$this->concat(
|
508 |
-
$this->image[ $this->current_namespace ][ $el ], $text );
|
509 |
-
}
|
510 |
-
}
|
511 |
-
else {
|
512 |
-
if ( $this->initem ) {
|
513 |
-
$this->concat(
|
514 |
-
$this->current_item[ $el ], $text);
|
515 |
-
}
|
516 |
-
elseif ($this->intextinput) {
|
517 |
-
$this->concat(
|
518 |
-
$this->textinput[ $el ], $text );
|
519 |
-
}
|
520 |
-
elseif ($this->inimage) {
|
521 |
-
$this->concat(
|
522 |
-
$this->image[ $el ], $text );
|
523 |
-
}
|
524 |
-
elseif ($this->inchannel) {
|
525 |
-
$this->concat(
|
526 |
-
$this->channel[ $el ], $text );
|
527 |
-
}
|
528 |
-
|
529 |
-
}
|
530 |
-
}
|
531 |
-
|
532 |
-
// smart count - field and namespace aware
|
533 |
-
function element_count ($el, $set = NULL) {
|
534 |
-
if (!$el) {
|
535 |
-
return;
|
536 |
-
}
|
537 |
-
if ( $this->current_namespace )
|
538 |
-
{
|
539 |
-
if ( $this->initem ) {
|
540 |
-
if (!is_null($set)) { $this->current_item[ $this->current_namespace ][ $el.'#' ] = $set; }
|
541 |
-
$ret = (isset($this->current_item[ $this->current_namespace ][ $el.'#' ]) ?
|
542 |
-
$this->current_item[ $this->current_namespace ][ $el.'#' ] : 0);
|
543 |
-
}
|
544 |
-
elseif ($this->inchannel) {
|
545 |
-
if (!is_null($set)) { $this->channel[ $this->current_namespace ][ $el.'#' ] = $set; }
|
546 |
-
$ret = (isset($this->channel[ $this->current_namespace][ $el.'#' ]) ?
|
547 |
-
$this->channel[ $this->current_namespace][ $el.'#' ] : 0);
|
548 |
-
}
|
549 |
-
}
|
550 |
-
else {
|
551 |
-
if ( $this->initem ) {
|
552 |
-
if (!is_null($set)) { $this->current_item[ $el.'#' ] = $set; }
|
553 |
-
$ret = (isset($this->current_item[ $el.'#' ]) ?
|
554 |
-
$this->current_item[ $el.'#' ] : 0);
|
555 |
-
}
|
556 |
-
elseif ($this->inchannel) {
|
557 |
-
if (!is_null($set)) {$this->channel[ $el.'#' ] = $set; }
|
558 |
-
$ret = (isset($this->channel[ $el.'#' ]) ?
|
559 |
-
$this->channel[ $el.'#' ] : 0);
|
560 |
-
}
|
561 |
-
}
|
562 |
-
return $ret;
|
563 |
-
}
|
564 |
-
|
565 |
-
function normalize_enclosure (&$source, $from, &$dest, $to, $i) {
|
566 |
-
$id_from = $this->element_id($from, $i);
|
567 |
-
$id_to = $this->element_id($to, $i);
|
568 |
-
if (isset($source["{$id_from}@"])) {
|
569 |
-
foreach (explode(',', $source["{$id_from}@"]) as $attr) {
|
570 |
-
if ($from=='link_enclosure' and $attr=='href') { // from Atom
|
571 |
-
$dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"];
|
572 |
-
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
573 |
-
}
|
574 |
-
elseif ($from=='enclosure' and $attr=='url') { // from RSS
|
575 |
-
$dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"];
|
576 |
-
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
577 |
-
}
|
578 |
-
else {
|
579 |
-
$dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"];
|
580 |
-
}
|
581 |
-
}
|
582 |
-
}
|
583 |
-
}
|
584 |
-
|
585 |
-
function normalize_atom_person (&$source, $person, &$dest, $to, $i) {
|
586 |
-
$id = $this->element_id($person, $i);
|
587 |
-
$id_to = $this->element_id($to, $i);
|
588 |
-
|
589 |
-
// Atom 0.3 <=> Atom 1.0
|
590 |
-
if ($this->feed_version >= 1.0) { $used = 'uri'; $norm = 'url'; }
|
591 |
-
else { $used = 'url'; $norm = 'uri'; }
|
592 |
-
|
593 |
-
if (isset($source["{$id}_{$used}"])) {
|
594 |
-
$dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"];
|
595 |
-
}
|
596 |
-
|
597 |
-
// Atom to RSS 2.0 and Dublin Core
|
598 |
-
// RSS 2.0 person strings should be valid e-mail addresses if possible.
|
599 |
-
if (isset($source["{$id}_email"])) {
|
600 |
-
$rss_author = $source["{$id}_email"];
|
601 |
-
}
|
602 |
-
if (isset($source["{$id}_name"])) {
|
603 |
-
$rss_author = $source["{$id}_name"]
|
604 |
-
. (isset($rss_author) ? " <$rss_author>" : '');
|
605 |
-
}
|
606 |
-
if (isset($rss_author)) {
|
607 |
-
$source[$id] = $rss_author; // goes to top-level author or contributor
|
608 |
-
$dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor
|
609 |
-
}
|
610 |
-
}
|
611 |
-
|
612 |
-
// Normalize Atom 1.0 and RSS 2.0 categories to Dublin Core...
|
613 |
-
function normalize_category (&$source, $from, &$dest, $to, $i) {
|
614 |
-
$cat_id = $this->element_id($from, $i);
|
615 |
-
$dc_id = $this->element_id($to, $i);
|
616 |
-
|
617 |
-
// first normalize category elements: Atom 1.0 <=> RSS 2.0
|
618 |
-
if ( isset($source["{$cat_id}@term"]) ) { // category identifier
|
619 |
-
$source[$cat_id] = $source["{$cat_id}@term"];
|
620 |
-
} elseif ( $this->feed_type == RSS ) {
|
621 |
-
$source["{$cat_id}@term"] = $source[$cat_id];
|
622 |
-
}
|
623 |
-
|
624 |
-
if ( isset($source["{$cat_id}@scheme"]) ) { // URI to taxonomy
|
625 |
-
$source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"];
|
626 |
-
} elseif ( isset($source["{$cat_id}@domain"]) ) {
|
627 |
-
$source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"];
|
628 |
-
}
|
629 |
-
|
630 |
-
// Now put the identifier into dc:subject
|
631 |
-
$dest[$dc_id] = $source[$cat_id];
|
632 |
-
}
|
633 |
-
|
634 |
-
// ... or vice versa
|
635 |
-
function normalize_dc_subject (&$source, $from, &$dest, $to, $i) {
|
636 |
-
$dc_id = $this->element_id($from, $i);
|
637 |
-
$cat_id = $this->element_id($to, $i);
|
638 |
-
|
639 |
-
$dest[$cat_id] = $source[$dc_id]; // RSS 2.0
|
640 |
-
$dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0
|
641 |
-
}
|
642 |
-
|
643 |
-
// simplify the logic for normalize(). Makes sure that count of elements and
|
644 |
-
// each of multiple elements is normalized properly. If you need to mess
|
645 |
-
// with things like attributes or change formats or the like, pass it a
|
646 |
-
// callback to handle each element.
|
647 |
-
function normalize_element (&$source, $from, &$dest, $to, $via = NULL) {
|
648 |
-
if (isset($source[$from]) or isset($source["{$from}#"])) {
|
649 |
-
if (isset($source["{$from}#"])) {
|
650 |
-
$n = $source["{$from}#"];
|
651 |
-
$dest["{$to}#"] = $source["{$from}#"];
|
652 |
-
}
|
653 |
-
else { $n = 1; }
|
654 |
-
|
655 |
-
for ($i = 1; $i <= $n; $i++) {
|
656 |
-
if (isset($via)) { // custom callback for ninja attacks
|
657 |
-
$this->{$via}($source, $from, $dest, $to, $i);
|
658 |
-
}
|
659 |
-
else { // just make it the same
|
660 |
-
$from_id = $this->element_id($from, $i);
|
661 |
-
$to_id = $this->element_id($to, $i);
|
662 |
-
$dest[$to_id] = $source[$from_id];
|
663 |
-
}
|
664 |
-
}
|
665 |
-
}
|
666 |
-
}
|
667 |
-
|
668 |
-
function normalize () {
|
669 |
-
// if atom populate rss fields and normalize 0.3 and 1.0 feeds
|
670 |
-
if ( $this->is_atom() ) {
|
671 |
-
// Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!)
|
672 |
-
if ($this->feed_version < 1.0) {
|
673 |
-
$this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle');
|
674 |
-
$this->normalize_element($this->channel, 'copyright', $this->channel, 'rights');
|
675 |
-
$this->normalize_element($this->channel, 'modified', $this->channel, 'updated');
|
676 |
-
} else {
|
677 |
-
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline');
|
678 |
-
$this->normalize_element($this->channel, 'rights', $this->channel, 'copyright');
|
679 |
-
$this->normalize_element($this->channel, 'updated', $this->channel, 'modified');
|
680 |
-
}
|
681 |
-
$this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person');
|
682 |
-
$this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person');
|
683 |
-
|
684 |
-
// Atom elements to RSS elements
|
685 |
-
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'description');
|
686 |
-
|
687 |
-
if ( isset($this->channel['logo']) ) {
|
688 |
-
$this->normalize_element($this->channel, 'logo', $this->image, 'url');
|
689 |
-
$this->normalize_element($this->channel, 'link', $this->image, 'link');
|
690 |
-
$this->normalize_element($this->channel, 'title', $this->image, 'title');
|
691 |
-
}
|
692 |
-
|
693 |
-
for ( $i = 0; $i < count($this->items); $i++) {
|
694 |
-
$item = $this->items[$i];
|
695 |
-
|
696 |
-
// Atom 1.0 elements <=> Atom 0.3 elements
|
697 |
-
if ($this->feed_version < 1.0) {
|
698 |
-
$this->normalize_element($item, 'modified', $item, 'updated');
|
699 |
-
$this->normalize_element($item, 'issued', $item, 'published');
|
700 |
-
} else {
|
701 |
-
$this->normalize_element($item, 'updated', $item, 'modified');
|
702 |
-
$this->normalize_element($item, 'published', $item, 'issued');
|
703 |
-
}
|
704 |
-
|
705 |
-
// "If an atom:entry element does not contain
|
706 |
-
// atom:author elements, then the atom:author elements
|
707 |
-
// of the contained atom:source element are considered
|
708 |
-
// to apply. In an Atom Feed Document, the atom:author
|
709 |
-
// elements of the containing atom:feed element are
|
710 |
-
// considered to apply to the entry if there are no
|
711 |
-
// atom:author elements in the locations described
|
712 |
-
// above." <http://atompub.org/2005/08/17/draft-ietf-atompub-format-11.html#rfc.section.4.2.1>
|
713 |
-
if (!isset($item["author#"])) {
|
714 |
-
if (isset($item["source_author#"])) { // from aggregation source
|
715 |
-
$source = $item;
|
716 |
-
$author = "source_author";
|
717 |
-
} elseif (isset($this->channel["author#"])) { // from containing feed
|
718 |
-
$source = $this->channel;
|
719 |
-
$author = "author";
|
720 |
-
}
|
721 |
-
|
722 |
-
$item["author#"] = $source["{$author}#"];
|
723 |
-
for ($au = 1; $au <= $item["author#"]; $au++) {
|
724 |
-
$id_to = $this->element_id('author', $au);
|
725 |
-
$id_from = $this->element_id($author, $au);
|
726 |
-
|
727 |
-
$item[$id_to] = $source[$id_from];
|
728 |
-
foreach (array('name', 'email', 'uri', 'url') as $what) {
|
729 |
-
if (isset($source["{$id_from}_{$what}"])) {
|
730 |
-
$item["{$id_to}_{$what}"] = $source["{$id_from}_{$what}"];
|
731 |
-
}
|
732 |
-
}
|
733 |
-
}
|
734 |
-
}
|
735 |
-
|
736 |
-
// Atom elements to RSS elements
|
737 |
-
$this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person');
|
738 |
-
$this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person');
|
739 |
-
$this->normalize_element($item, 'summary', $item, 'description');
|
740 |
-
$this->normalize_element($item, 'atom_content', $item['content'], 'encoded');
|
741 |
-
$this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure');
|
742 |
-
|
743 |
-
// Categories
|
744 |
-
if ( isset($item['category#']) ) { // Atom 1.0 categories to dc:subject and RSS 2.0 categories
|
745 |
-
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
746 |
-
}
|
747 |
-
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
748 |
-
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
749 |
-
}
|
750 |
-
|
751 |
-
// Normalized item timestamp
|
752 |
-
$atom_date = (isset($item['published']) ) ? $item['published'] : $item['updated'];
|
753 |
-
if ( $atom_date ) {
|
754 |
-
$epoch = @parse_w3cdtf($atom_date);
|
755 |
-
if ($epoch and $epoch > 0) {
|
756 |
-
$item['date_timestamp'] = $epoch;
|
757 |
-
}
|
758 |
-
}
|
759 |
-
|
760 |
-
$this->items[$i] = $item;
|
761 |
-
}
|
762 |
-
}
|
763 |
-
elseif ( $this->is_rss() ) {
|
764 |
-
// RSS elements to Atom elements
|
765 |
-
$this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3
|
766 |
-
$this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!)
|
767 |
-
$this->normalize_element($this->image, 'url', $this->channel, 'logo');
|
768 |
-
|
769 |
-
for ( $i = 0; $i < count($this->items); $i++) {
|
770 |
-
$item = $this->items[$i];
|
771 |
-
|
772 |
-
// RSS elements to Atom elements
|
773 |
-
$this->normalize_element($item, 'description', $item, 'summary');
|
774 |
-
$this->normalize_element($item['content'], 'encoded', $item, 'atom_content');
|
775 |
-
$this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure');
|
776 |
-
|
777 |
-
// Categories
|
778 |
-
if ( isset($item['category#']) ) { // RSS 2.0 categories to dc:subject and Atom 1.0 categories
|
779 |
-
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
780 |
-
}
|
781 |
-
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
782 |
-
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
783 |
-
}
|
784 |
-
|
785 |
-
// Normalized item timestamp
|
786 |
-
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
|
787 |
-
$epoch = @parse_w3cdtf($item['dc']['date']);
|
788 |
-
if ($epoch and $epoch > 0) {
|
789 |
-
$item['date_timestamp'] = $epoch;
|
790 |
-
}
|
791 |
-
}
|
792 |
-
elseif ( isset($item['pubdate']) ) {
|
793 |
-
$epoch = @strtotime($item['pubdate']);
|
794 |
-
if ($epoch > 0) {
|
795 |
-
$item['date_timestamp'] = $epoch;
|
796 |
-
}
|
797 |
-
}
|
798 |
-
|
799 |
-
$this->items[$i] = $item;
|
800 |
-
}
|
801 |
-
}
|
802 |
-
}
|
803 |
-
|
804 |
-
|
805 |
-
function is_rss () {
|
806 |
-
if ( $this->feed_type == RSS ) {
|
807 |
-
return $this->feed_version;
|
808 |
-
}
|
809 |
-
else {
|
810 |
-
return false;
|
811 |
-
}
|
812 |
-
}
|
813 |
-
|
814 |
-
function is_atom() {
|
815 |
-
if ( $this->feed_type == ATOM ) {
|
816 |
-
return $this->feed_version;
|
817 |
-
}
|
818 |
-
else {
|
819 |
-
return false;
|
820 |
-
}
|
821 |
-
}
|
822 |
-
|
823 |
-
/**
|
824 |
-
* return XML parser, and possibly re-encoded source
|
825 |
-
*
|
826 |
-
*/
|
827 |
-
function create_parser($source, $out_enc, $in_enc, $detect) {
|
828 |
-
if ( substr(phpversion(),0,1) == 5) {
|
829 |
-
$parser = $this->php5_create_parser($in_enc, $detect);
|
830 |
-
}
|
831 |
-
else {
|
832 |
-
list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
|
833 |
-
}
|
834 |
-
if ($out_enc) {
|
835 |
-
$this->encoding = $out_enc;
|
836 |
-
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
|
837 |
-
}
|
838 |
-
|
839 |
-
return array($parser, $source);
|
840 |
-
}
|
841 |
-
|
842 |
-
/**
|
843 |
-
* Instantiate an XML parser under PHP5
|
844 |
-
*
|
845 |
-
* PHP5 will do a fine job of detecting input encoding
|
846 |
-
* if passed an empty string as the encoding.
|
847 |
-
*
|
848 |
-
* All hail libxml2!
|
849 |
-
*
|
850 |
-
*/
|
851 |
-
function php5_create_parser($in_enc, $detect) {
|
852 |
-
// by default php5 does a fine job of detecting input encodings
|
853 |
-
if(!$detect && $in_enc) {
|
854 |
-
return xml_parser_create($in_enc);
|
855 |
-
}
|
856 |
-
else {
|
857 |
-
return xml_parser_create('');
|
858 |
-
}
|
859 |
-
}
|
860 |
-
|
861 |
-
/**
|
862 |
-
* Instaniate an XML parser under PHP4
|
863 |
-
*
|
864 |
-
* Unfortunately PHP4's support for character encodings
|
865 |
-
* and especially XML and character encodings sucks. As
|
866 |
-
* long as the documents you parse only contain characters
|
867 |
-
* from the ISO-8859-1 character set (a superset of ASCII,
|
868 |
-
* and a subset of UTF-8) you're fine. However once you
|
869 |
-
* step out of that comfy little world things get mad, bad,
|
870 |
-
* and dangerous to know.
|
871 |
-
*
|
872 |
-
* The following code is based on SJM's work with FoF
|
873 |
-
* @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
|
874 |
-
*
|
875 |
-
*/
|
876 |
-
function php4_create_parser($source, $in_enc, $detect) {
|
877 |
-
if ( !$detect ) {
|
878 |
-
return array(xml_parser_create($in_enc), $source);
|
879 |
-
}
|
880 |
-
|
881 |
-
if (!$in_enc) {
|
882 |
-
if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
|
883 |
-
$in_enc = strtoupper($m[1]);
|
884 |
-
$this->source_encoding = $in_enc;
|
885 |
-
}
|
886 |
-
else {
|
887 |
-
$in_enc = 'UTF-8';
|
888 |
-
}
|
889 |
-
}
|
890 |
-
|
891 |
-
if ($this->known_encoding($in_enc)) {
|
892 |
-
return array(xml_parser_create($in_enc), $source);
|
893 |
-
}
|
894 |
-
|
895 |
-
// the dectected encoding is not one of the simple encodings PHP knows
|
896 |
-
|
897 |
-
// attempt to use the iconv extension to
|
898 |
-
// cast the XML to a known encoding
|
899 |
-
// @see http://php.net/iconv
|
900 |
-
|
901 |
-
if (function_exists('iconv')) {
|
902 |
-
$encoded_source = iconv($in_enc,'UTF-8', $source);
|
903 |
-
if ($encoded_source) {
|
904 |
-
return array(xml_parser_create('UTF-8'), $encoded_source);
|
905 |
-
}
|
906 |
-
}
|
907 |
-
|
908 |
-
// iconv didn't work, try mb_convert_encoding
|
909 |
-
// @see http://php.net/mbstring
|
910 |
-
if(function_exists('mb_convert_encoding')) {
|
911 |
-
$encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
|
912 |
-
if ($encoded_source) {
|
913 |
-
return array(xml_parser_create('UTF-8'), $encoded_source);
|
914 |
-
}
|
915 |
-
}
|
916 |
-
|
917 |
-
// else
|
918 |
-
$this->error("Feed is in an unsupported character encoding. ($in_enc) " .
|
919 |
-
"You may see strange artifacts, and mangled characters.",
|
920 |
-
E_USER_NOTICE);
|
921 |
-
|
922 |
-
return array(xml_parser_create(), $source);
|
923 |
-
}
|
924 |
-
|
925 |
-
function known_encoding($enc) {
|
926 |
-
$enc = strtoupper($enc);
|
927 |
-
if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) {
|
928 |
-
return $enc;
|
929 |
-
}
|
930 |
-
else {
|
931 |
-
return false;
|
932 |
-
}
|
933 |
-
}
|
934 |
-
|
935 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
936 |
-
// append PHP's error message if track_errors enabled
|
937 |
-
if ( isset($php_errormsg) ) {
|
938 |
-
$errormsg .= " ($php_errormsg)";
|
939 |
-
}
|
940 |
-
if ( MAGPIE_DEBUG ) {
|
941 |
-
trigger_error( $errormsg, $lvl);
|
942 |
-
}
|
943 |
-
else {
|
944 |
-
error_log( $errormsg, 0);
|
945 |
-
}
|
946 |
-
|
947 |
-
$notices = E_USER_NOTICE|E_NOTICE;
|
948 |
-
if ( $lvl&$notices ) {
|
949 |
-
$this->WARNING = $errormsg;
|
950 |
-
} else {
|
951 |
-
$this->ERROR = $errormsg;
|
952 |
-
}
|
953 |
-
}
|
954 |
-
|
955 |
-
// magic ID function for multiple elemenets.
|
956 |
-
// can be called as static MagpieRSS::element_id()
|
957 |
-
function element_id ($el, $counter) {
|
958 |
-
return $el . (($counter > 1) ? '#'.$counter : '');
|
959 |
-
}
|
960 |
-
} // end class RSS
|
961 |
-
|
962 |
-
function map_attrs($k, $v) {
|
963 |
-
return "$k=\"$v\"";
|
964 |
-
}
|
965 |
-
|
966 |
-
// patch to support medieval versions of PHP4.1.x,
|
967 |
-
// courtesy, Ryan Currie, ryan@digibliss.com
|
968 |
-
|
969 |
-
if (!function_exists('array_change_key_case')) {
|
970 |
-
define("CASE_UPPER",1);
|
971 |
-
define("CASE_LOWER",0);
|
972 |
-
|
973 |
-
|
974 |
-
function array_change_key_case($array,$case=CASE_LOWER) {
|
975 |
-
if ($case==CASE_LOWER) $cmd='strtolower';
|
976 |
-
elseif ($case==CASE_UPPER) $cmd='strtoupper';
|
977 |
-
foreach($array as $key=>$value) {
|
978 |
-
$output[$cmd($key)]=$value;
|
979 |
-
}
|
980 |
-
return $output;
|
981 |
-
}
|
982 |
-
|
983 |
-
}
|
984 |
-
|
985 |
-
################################################################################
|
986 |
-
## WordPress: Load in Snoopy from wp-includes ##################################
|
987 |
-
################################################################################
|
988 |
-
|
989 |
-
require_once( dirname(__FILE__) . '/class-snoopy.php');
|
990 |
-
|
991 |
-
################################################################################
|
992 |
-
## rss_fetch.inc: from MagpieRSS 0.8a ##########################################
|
993 |
-
################################################################################
|
994 |
-
|
995 |
-
/*=======================================================================*\
|
996 |
-
Function: fetch_rss:
|
997 |
-
Purpose: return RSS object for the give url
|
998 |
-
maintain the cache
|
999 |
-
Input: url of RSS file
|
1000 |
-
Output: parsed RSS object (see rss_parse.inc)
|
1001 |
-
|
1002 |
-
NOTES ON CACHEING:
|
1003 |
-
If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache.
|
1004 |
-
|
1005 |
-
NOTES ON RETRIEVING REMOTE FILES:
|
1006 |
-
If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will
|
1007 |
-
return a cached object, and touch the cache object upon recieving a
|
1008 |
-
304.
|
1009 |
-
|
1010 |
-
NOTES ON FAILED REQUESTS:
|
1011 |
-
If there is an HTTP error while fetching an RSS object, the cached
|
1012 |
-
version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off)
|
1013 |
-
\*=======================================================================*/
|
1014 |
-
|
1015 |
-
define('MAGPIE_VERSION', '0.7');
|
1016 |
-
|
1017 |
-
$MAGPIE_ERROR = "";
|
1018 |
-
|
1019 |
-
function fetch_rss ($url) {
|
1020 |
-
// initialize constants
|
1021 |
-
init();
|
1022 |
-
|
1023 |
-
if ( !isset($url) ) {
|
1024 |
-
error("fetch_rss called without a url");
|
1025 |
-
return false;
|
1026 |
-
}
|
1027 |
-
|
1028 |
-
// if cache is disabled
|
1029 |
-
if ( !MAGPIE_CACHE_ON ) {
|
1030 |
-
// fetch file, and parse it
|
1031 |
-
$resp = _fetch_remote_file( $url );
|
1032 |
-
if ( is_success( $resp->status ) ) {
|
1033 |
-
return _response_to_rss( $resp );
|
1034 |
-
}
|
1035 |
-
else {
|
1036 |
-
error("Failed to fetch $url and cache is off");
|
1037 |
-
return false;
|
1038 |
-
}
|
1039 |
-
}
|
1040 |
-
// else cache is ON
|
1041 |
-
else {
|
1042 |
-
// Flow
|
1043 |
-
// 1. check cache
|
1044 |
-
// 2. if there is a hit, make sure its fresh
|
1045 |
-
// 3. if cached obj fails freshness check, fetch remote
|
1046 |
-
// 4. if remote fails, return stale object, or error
|
1047 |
-
|
1048 |
-
$cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
|
1049 |
-
|
1050 |
-
if (MAGPIE_DEBUG and $cache->ERROR) {
|
1051 |
-
debug($cache->ERROR, E_USER_WARNING);
|
1052 |
-
}
|
1053 |
-
|
1054 |
-
|
1055 |
-
$cache_status = 0; // response of check_cache
|
1056 |
-
$request_headers = array(); // HTTP headers to send with fetch
|
1057 |
-
$rss = 0; // parsed RSS object
|
1058 |
-
$errormsg = 0; // errors, if any
|
1059 |
-
|
1060 |
-
// store parsed XML by desired output encoding
|
1061 |
-
// as character munging happens at parse time
|
1062 |
-
$cache_key = $url . MAGPIE_OUTPUT_ENCODING;
|
1063 |
-
|
1064 |
-
if (!$cache->ERROR) {
|
1065 |
-
// return cache HIT, MISS, or STALE
|
1066 |
-
$cache_status = $cache->check_cache( $cache_key);
|
1067 |
-
}
|
1068 |
-
|
1069 |
-
// if object cached, and cache is fresh, return cached obj
|
1070 |
-
if ( $cache_status == 'HIT' ) {
|
1071 |
-
$rss = $cache->get( $cache_key );
|
1072 |
-
if ( isset($rss) and $rss ) {
|
1073 |
-
// should be cache age
|
1074 |
-
$rss->from_cache = 1;
|
1075 |
-
if ( MAGPIE_DEBUG > 1) {
|
1076 |
-
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
|
1077 |
-
}
|
1078 |
-
return $rss;
|
1079 |
-
}
|
1080 |
-
}
|
1081 |
-
|
1082 |
-
// else attempt a conditional get
|
1083 |
-
|
1084 |
-
// setup headers
|
1085 |
-
if ( $cache_status == 'STALE' ) {
|
1086 |
-
$rss = $cache->get( $cache_key );
|
1087 |
-
if ( $rss and $rss->etag and $rss->last_modified ) {
|
1088 |
-
$request_headers['If-None-Match'] = $rss->etag;
|
1089 |
-
$request_headers['If-Last-Modified'] = $rss->last_modified;
|
1090 |
-
}
|
1091 |
-
}
|
1092 |
-
|
1093 |
-
$resp = _fetch_remote_file( $url, $request_headers );
|
1094 |
-
|
1095 |
-
if (isset($resp) and $resp) {
|
1096 |
-
if ($resp->status == '304' ) {
|
1097 |
-
// we have the most current copy
|
1098 |
-
if ( MAGPIE_DEBUG > 1) {
|
1099 |
-
debug("Got 304 for $url");
|
1100 |
-
}
|
1101 |
-
// reset cache on 304 (at minutillo insistent prodding)
|
1102 |
-
$cache->set($cache_key, $rss);
|
1103 |
-
return $rss;
|
1104 |
-
}
|
1105 |
-
elseif ( is_success( $resp->status ) ) {
|
1106 |
-
$rss = _response_to_rss( $resp );
|
1107 |
-
if ( $rss ) {
|
1108 |
-
if (MAGPIE_DEBUG > 1) {
|
1109 |
-
debug("Fetch successful");
|
1110 |
-
}
|
1111 |
-
// add object to cache
|
1112 |
-
$cache->set( $cache_key, $rss );
|
1113 |
-
return $rss;
|
1114 |
-
}
|
1115 |
-
}
|
1116 |
-
else {
|
1117 |
-
$errormsg = "Failed to fetch $url ";
|
1118 |
-
if ( $resp->status == '-100' ) {
|
1119 |
-
$errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)";
|
1120 |
-
}
|
1121 |
-
elseif ( $resp->error ) {
|
1122 |
-
# compensate for Snoopy's annoying habbit to tacking
|
1123 |
-
# on '\n'
|
1124 |
-
$http_error = substr($resp->error, 0, -2);
|
1125 |
-
$errormsg .= "(HTTP Error: $http_error)";
|
1126 |
-
}
|
1127 |
-
else {
|
1128 |
-
$errormsg .= "(HTTP Response: " . $resp->response_code .')';
|
1129 |
-
}
|
1130 |
-
}
|
1131 |
-
}
|
1132 |
-
else {
|
1133 |
-
$errormsg = "Unable to retrieve RSS file for unknown reasons.";
|
1134 |
-
}
|
1135 |
-
|
1136 |
-
// else fetch failed
|
1137 |
-
|
1138 |
-
// attempt to return cached object
|
1139 |
-
if ($rss) {
|
1140 |
-
if ( MAGPIE_DEBUG ) {
|
1141 |
-
debug("Returning STALE object for $url");
|
1142 |
-
}
|
1143 |
-
return $rss;
|
1144 |
-
}
|
1145 |
-
|
1146 |
-
// else we totally failed
|
1147 |
-
error( $errormsg );
|
1148 |
-
|
1149 |
-
return false;
|
1150 |
-
|
1151 |
-
} // end if ( !MAGPIE_CACHE_ON ) {
|
1152 |
-
} // end fetch_rss()
|
1153 |
-
|
1154 |
-
/*=======================================================================*\
|
1155 |
-
Function: error
|
1156 |
-
Purpose: set MAGPIE_ERROR, and trigger error
|
1157 |
-
\*=======================================================================*/
|
1158 |
-
|
1159 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1160 |
-
global $MAGPIE_ERROR;
|
1161 |
-
|
1162 |
-
// append PHP's error message if track_errors enabled
|
1163 |
-
if ( isset($php_errormsg) ) {
|
1164 |
-
$errormsg .= " ($php_errormsg)";
|
1165 |
-
}
|
1166 |
-
if ( $errormsg ) {
|
1167 |
-
$errormsg = "MagpieRSS: $errormsg";
|
1168 |
-
$MAGPIE_ERROR = $errormsg;
|
1169 |
-
trigger_error( $errormsg, $lvl);
|
1170 |
-
}
|
1171 |
-
}
|
1172 |
-
|
1173 |
-
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1174 |
-
trigger_error("MagpieRSS [debug] $debugmsg", $lvl);
|
1175 |
-
}
|
1176 |
-
|
1177 |
-
/*=======================================================================*\
|
1178 |
-
Function: magpie_error
|
1179 |
-
Purpose: accessor for the magpie error variable
|
1180 |
-
\*=======================================================================*/
|
1181 |
-
function magpie_error ($errormsg="") {
|
1182 |
-
global $MAGPIE_ERROR;
|
1183 |
-
|
1184 |
-
if ( isset($errormsg) and $errormsg ) {
|
1185 |
-
$MAGPIE_ERROR = $errormsg;
|
1186 |
-
}
|
1187 |
-
|
1188 |
-
return $MAGPIE_ERROR;
|
1189 |
-
}
|
1190 |
-
|
1191 |
-
/*=======================================================================*\
|
1192 |
-
Function: _fetch_remote_file
|
1193 |
-
Purpose: retrieve an arbitrary remote file
|
1194 |
-
Input: url of the remote file
|
1195 |
-
headers to send along with the request (optional)
|
1196 |
-
Output: an HTTP response object (see Snoopy.class.inc)
|
1197 |
-
\*=======================================================================*/
|
1198 |
-
function _fetch_remote_file ($url, $headers = "" ) {
|
1199 |
-
// Snoopy is an HTTP client in PHP
|
1200 |
-
$client = new Snoopy();
|
1201 |
-
$client->agent = MAGPIE_USER_AGENT;
|
1202 |
-
$client->read_timeout = MAGPIE_FETCH_TIME_OUT;
|
1203 |
-
$client->use_gzip = MAGPIE_USE_GZIP;
|
1204 |
-
if (is_array($headers) ) {
|
1205 |
-
$client->rawheaders = $headers;
|
1206 |
-
}
|
1207 |
-
|
1208 |
-
@$client->fetch($url);
|
1209 |
-
return $client;
|
1210 |
-
|
1211 |
-
}
|
1212 |
-
|
1213 |
-
/*=======================================================================*\
|
1214 |
-
Function: _response_to_rss
|
1215 |
-
Purpose: parse an HTTP response object into an RSS object
|
1216 |
-
Input: an HTTP response object (see Snoopy)
|
1217 |
-
Output: parsed RSS object (see rss_parse)
|
1218 |
-
\*=======================================================================*/
|
1219 |
-
function _response_to_rss ($resp) {
|
1220 |
-
$rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
|
1221 |
-
|
1222 |
-
// if RSS parsed successfully
|
1223 |
-
if ( $rss and !$rss->ERROR) {
|
1224 |
-
|
1225 |
-
// find Etag, and Last-Modified
|
1226 |
-
foreach($resp->headers as $h) {
|
1227 |
-
// 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
|
1228 |
-
if (strpos($h, ": ")) {
|
1229 |
-
list($field, $val) = explode(": ", $h, 2);
|
1230 |
-
}
|
1231 |
-
else {
|
1232 |
-
$field = $h;
|
1233 |
-
$val = "";
|
1234 |
-
}
|
1235 |
-
|
1236 |
-
if ( $field == 'ETag' ) {
|
1237 |
-
$rss->etag = $val;
|
1238 |
-
}
|
1239 |
-
|
1240 |
-
if ( $field == 'Last-Modified' ) {
|
1241 |
-
$rss->last_modified = $val;
|
1242 |
-
}
|
1243 |
-
}
|
1244 |
-
|
1245 |
-
return $rss;
|
1246 |
-
} // else construct error message
|
1247 |
-
else {
|
1248 |
-
$errormsg = "Failed to parse RSS file.";
|
1249 |
-
|
1250 |
-
if ($rss) {
|
1251 |
-
$errormsg .= " (" . $rss->ERROR . ")";
|
1252 |
-
}
|
1253 |
-
error($errormsg);
|
1254 |
-
|
1255 |
-
return false;
|
1256 |
-
} // end if ($rss and !$rss->error)
|
1257 |
-
}
|
1258 |
-
|
1259 |
-
/*=======================================================================*\
|
1260 |
-
Function: init
|
1261 |
-
Purpose: setup constants with default values
|
1262 |
-
check for user overrides
|
1263 |
-
\*=======================================================================*/
|
1264 |
-
function init () {
|
1265 |
-
if ( defined('MAGPIE_INITALIZED') ) {
|
1266 |
-
return;
|
1267 |
-
}
|
1268 |
-
else {
|
1269 |
-
define('MAGPIE_INITALIZED', true);
|
1270 |
-
}
|
1271 |
-
|
1272 |
-
if ( !defined('MAGPIE_CACHE_ON') ) {
|
1273 |
-
define('MAGPIE_CACHE_ON', true);
|
1274 |
-
}
|
1275 |
-
|
1276 |
-
if ( !defined('MAGPIE_CACHE_DIR') ) {
|
1277 |
-
define('MAGPIE_CACHE_DIR', './cache');
|
1278 |
-
}
|
1279 |
-
|
1280 |
-
if ( !defined('MAGPIE_CACHE_AGE') ) {
|
1281 |
-
define('MAGPIE_CACHE_AGE', 60*60); // one hour
|
1282 |
-
}
|
1283 |
-
|
1284 |
-
if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
|
1285 |
-
define('MAGPIE_CACHE_FRESH_ONLY', false);
|
1286 |
-
}
|
1287 |
-
|
1288 |
-
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
|
1289 |
-
define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1');
|
1290 |
-
}
|
1291 |
-
|
1292 |
-
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
|
1293 |
-
define('MAGPIE_INPUT_ENCODING', null);
|
1294 |
-
}
|
1295 |
-
|
1296 |
-
if ( !defined('MAGPIE_DETECT_ENCODING') ) {
|
1297 |
-
define('MAGPIE_DETECT_ENCODING', true);
|
1298 |
-
}
|
1299 |
-
|
1300 |
-
if ( !defined('MAGPIE_DEBUG') ) {
|
1301 |
-
define('MAGPIE_DEBUG', 0);
|
1302 |
-
}
|
1303 |
-
|
1304 |
-
if ( !defined('MAGPIE_USER_AGENT') ) {
|
1305 |
-
$ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net';
|
1306 |
-
|
1307 |
-
if ( MAGPIE_CACHE_ON ) {
|
1308 |
-
$ua = $ua . ')';
|
1309 |
-
}
|
1310 |
-
else {
|
1311 |
-
$ua = $ua . '; No cache)';
|
1312 |
-
}
|
1313 |
-
|
1314 |
-
define('MAGPIE_USER_AGENT', $ua);
|
1315 |
-
}
|
1316 |
-
|
1317 |
-
if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
|
1318 |
-
define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout
|
1319 |
-
}
|
1320 |
-
|
1321 |
-
// use gzip encoding to fetch rss files if supported?
|
1322 |
-
if ( !defined('MAGPIE_USE_GZIP') ) {
|
1323 |
-
define('MAGPIE_USE_GZIP', true);
|
1324 |
-
}
|
1325 |
-
}
|
1326 |
-
|
1327 |
-
// NOTE: the following code should really be in Snoopy, or at least
|
1328 |
-
// somewhere other then rss_fetch!
|
1329 |
-
|
1330 |
-
/*=======================================================================*\
|
1331 |
-
HTTP STATUS CODE PREDICATES
|
1332 |
-
These functions attempt to classify an HTTP status code
|
1333 |
-
based on RFC 2616 and RFC 2518.
|
1334 |
-
|
1335 |
-
All of them take an HTTP status code as input, and return true or false
|
1336 |
-
|
1337 |
-
All this code is adapted from LWP's HTTP::Status.
|
1338 |
-
\*=======================================================================*/
|
1339 |
-
|
1340 |
-
|
1341 |
-
/*=======================================================================*\
|
1342 |
-
Function: is_info
|
1343 |
-
Purpose: return true if Informational status code
|
1344 |
-
\*=======================================================================*/
|
1345 |
-
function is_info ($sc) {
|
1346 |
-
return $sc >= 100 && $sc < 200;
|
1347 |
-
}
|
1348 |
-
|
1349 |
-
/*=======================================================================*\
|
1350 |
-
Function: is_success
|
1351 |
-
Purpose: return true if Successful status code
|
1352 |
-
\*=======================================================================*/
|
1353 |
-
function is_success ($sc) {
|
1354 |
-
return $sc >= 200 && $sc < 300;
|
1355 |
-
}
|
1356 |
-
|
1357 |
-
/*=======================================================================*\
|
1358 |
-
Function: is_redirect
|
1359 |
-
Purpose: return true if Redirection status code
|
1360 |
-
\*=======================================================================*/
|
1361 |
-
function is_redirect ($sc) {
|
1362 |
-
return $sc >= 300 && $sc < 400;
|
1363 |
-
}
|
1364 |
-
|
1365 |
-
/*=======================================================================*\
|
1366 |
-
Function: is_error
|
1367 |
-
Purpose: return true if Error status code
|
1368 |
-
\*=======================================================================*/
|
1369 |
-
function is_error ($sc) {
|
1370 |
-
return $sc >= 400 && $sc < 600;
|
1371 |
-
}
|
1372 |
-
|
1373 |
-
/*=======================================================================*\
|
1374 |
-
Function: is_client_error
|
1375 |
-
Purpose: return true if Error status code, and its a client error
|
1376 |
-
\*=======================================================================*/
|
1377 |
-
function is_client_error ($sc) {
|
1378 |
-
return $sc >= 400 && $sc < 500;
|
1379 |
-
}
|
1380 |
-
|
1381 |
-
/*=======================================================================*\
|
1382 |
-
Function: is_client_error
|
1383 |
-
Purpose: return true if Error status code, and its a server error
|
1384 |
-
\*=======================================================================*/
|
1385 |
-
function is_server_error ($sc) {
|
1386 |
-
return $sc >= 500 && $sc < 600;
|
1387 |
-
}
|
1388 |
-
|
1389 |
-
################################################################################
|
1390 |
-
## rss_cache.inc: from WordPress 1.5 ###########################################
|
1391 |
-
################################################################################
|
1392 |
-
|
1393 |
-
class RSSCache {
|
1394 |
-
var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
|
1395 |
-
var $MAX_AGE = 43200; // when are files stale, default twelve hours
|
1396 |
-
var $ERROR = ''; // accumulate error messages
|
1397 |
-
|
1398 |
-
function RSSCache ($base='', $age='') {
|
1399 |
-
if ( $base ) {
|
1400 |
-
$this->BASE_CACHE = $base;
|
1401 |
-
}
|
1402 |
-
if ( $age ) {
|
1403 |
-
$this->MAX_AGE = $age;
|
1404 |
-
}
|
1405 |
-
|
1406 |
-
}
|
1407 |
-
|
1408 |
-
/*=======================================================================*\
|
1409 |
-
Function: set
|
1410 |
-
Purpose: add an item to the cache, keyed on url
|
1411 |
-
Input: url from wich the rss file was fetched
|
1412 |
-
Output: true on sucess
|
1413 |
-
\*=======================================================================*/
|
1414 |
-
function set ($url, $rss) {
|
1415 |
-
global $wpdb;
|
1416 |
-
$cache_option = 'rss_' . $this->file_name( $url );
|
1417 |
-
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1418 |
-
|
1419 |
-
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_option'") )
|
1420 |
-
add_option($cache_option, '', '', 'no');
|
1421 |
-
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_timestamp'") )
|
1422 |
-
add_option($cache_timestamp, '', '', 'no');
|
1423 |
-
|
1424 |
-
update_option($cache_option, $rss);
|
1425 |
-
update_option($cache_timestamp, time() );
|
1426 |
-
|
1427 |
-
return $cache_option;
|
1428 |
-
}
|
1429 |
-
|
1430 |
-
/*=======================================================================*\
|
1431 |
-
Function: get
|
1432 |
-
Purpose: fetch an item from the cache
|
1433 |
-
Input: url from wich the rss file was fetched
|
1434 |
-
Output: cached object on HIT, false on MISS
|
1435 |
-
\*=======================================================================*/
|
1436 |
-
function get ($url) {
|
1437 |
-
$this->ERROR = "";
|
1438 |
-
$cache_option = 'rss_' . $this->file_name( $url );
|
1439 |
-
|
1440 |
-
if ( ! get_option( $cache_option ) ) {
|
1441 |
-
$this->debug(
|
1442 |
-
"Cache doesn't contain: $url (cache option: $cache_option)"
|
1443 |
-
);
|
1444 |
-
return 0;
|
1445 |
-
}
|
1446 |
-
|
1447 |
-
$rss = get_option( $cache_option );
|
1448 |
-
|
1449 |
-
return $rss;
|
1450 |
-
}
|
1451 |
-
|
1452 |
-
/*=======================================================================*\
|
1453 |
-
Function: check_cache
|
1454 |
-
Purpose: check a url for membership in the cache
|
1455 |
-
and whether the object is older then MAX_AGE (ie. STALE)
|
1456 |
-
Input: url from wich the rss file was fetched
|
1457 |
-
Output: cached object on HIT, false on MISS
|
1458 |
-
\*=======================================================================*/
|
1459 |
-
function check_cache ( $url ) {
|
1460 |
-
$this->ERROR = "";
|
1461 |
-
$cache_option = $this->file_name( $url );
|
1462 |
-
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1463 |
-
|
1464 |
-
if ( $mtime = get_option($cache_timestamp) ) {
|
1465 |
-
// find how long ago the file was added to the cache
|
1466 |
-
// and whether that is longer then MAX_AGE
|
1467 |
-
$age = time() - $mtime;
|
1468 |
-
if ( $this->MAX_AGE > $age ) {
|
1469 |
-
// object exists and is current
|
1470 |
-
return 'HIT';
|
1471 |
-
}
|
1472 |
-
else {
|
1473 |
-
// object exists but is old
|
1474 |
-
return 'STALE';
|
1475 |
-
}
|
1476 |
-
}
|
1477 |
-
else {
|
1478 |
-
// object does not exist
|
1479 |
-
return 'MISS';
|
1480 |
-
}
|
1481 |
-
}
|
1482 |
-
|
1483 |
-
/*=======================================================================*\
|
1484 |
-
Function: serialize
|
1485 |
-
\*=======================================================================*/
|
1486 |
-
function serialize ( $rss ) {
|
1487 |
-
return serialize( $rss );
|
1488 |
-
}
|
1489 |
-
|
1490 |
-
/*=======================================================================*\
|
1491 |
-
Function: unserialize
|
1492 |
-
\*=======================================================================*/
|
1493 |
-
function unserialize ( $data ) {
|
1494 |
-
return unserialize( $data );
|
1495 |
-
}
|
1496 |
-
|
1497 |
-
/*=======================================================================*\
|
1498 |
-
Function: file_name
|
1499 |
-
Purpose: map url to location in cache
|
1500 |
-
Input: url from wich the rss file was fetched
|
1501 |
-
Output: a file name
|
1502 |
-
\*=======================================================================*/
|
1503 |
-
function file_name ($url) {
|
1504 |
-
return md5( $url );
|
1505 |
-
}
|
1506 |
-
|
1507 |
-
/*=======================================================================*\
|
1508 |
-
Function: error
|
1509 |
-
Purpose: register error
|
1510 |
-
\*=======================================================================*/
|
1511 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1512 |
-
// append PHP's error message if track_errors enabled
|
1513 |
-
if ( isset($php_errormsg) ) {
|
1514 |
-
$errormsg .= " ($php_errormsg)";
|
1515 |
-
}
|
1516 |
-
$this->ERROR = $errormsg;
|
1517 |
-
if ( MAGPIE_DEBUG ) {
|
1518 |
-
trigger_error( $errormsg, $lvl);
|
1519 |
-
}
|
1520 |
-
else {
|
1521 |
-
error_log( $errormsg, 0);
|
1522 |
-
}
|
1523 |
-
}
|
1524 |
-
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1525 |
-
if ( MAGPIE_DEBUG ) {
|
1526 |
-
$this->error("MagpieRSS [debug] $debugmsg", $lvl);
|
1527 |
-
}
|
1528 |
-
}
|
1529 |
-
}
|
1530 |
-
|
1531 |
-
################################################################################
|
1532 |
-
## rss_utils.inc: from MagpieRSS 0.8a ##########################################
|
1533 |
-
################################################################################
|
1534 |
-
|
1535 |
-
/*======================================================================*\
|
1536 |
-
Function: parse_w3cdtf
|
1537 |
-
Purpose: parse a W3CDTF date into unix epoch
|
1538 |
-
|
1539 |
-
NOTE: http://www.w3.org/TR/NOTE-datetime
|
1540 |
-
\*======================================================================*/
|
1541 |
-
|
1542 |
-
function parse_w3cdtf ( $date_str ) {
|
1543 |
-
|
1544 |
-
# regex to match wc3dtf
|
1545 |
-
$pat = "/^\s*(\d{4})(-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(\.\d+)?)?(?:([-+])(\d{2}):?(\d{2})|(Z))?)?)?)?\s*\$/";
|
1546 |
-
|
1547 |
-
if ( preg_match( $pat, $date_str, $match ) ) {
|
1548 |
-
list( $year, $month, $day, $hours, $minutes, $seconds) =
|
1549 |
-
array( $match[1], $match[3], $match[5], $match[7], $match[8], $match[9]);
|
1550 |
-
|
1551 |
-
# W3C dates can omit the time, the day of the month, or even the month.
|
1552 |
-
# Fill in any blanks using information from the present moment. --CWJ
|
1553 |
-
$default['hr'] = (int) gmdate('H');
|
1554 |
-
$default['day'] = (int) gmdate('d');
|
1555 |
-
$default['month'] = (int) gmdate('m');
|
1556 |
-
|
1557 |
-
if (is_null($hours)) : $hours = $default['hr']; $minutes = 0; $seconds = 0; endif;
|
1558 |
-
if (is_null($day)) : $day = $default['day']; endif;
|
1559 |
-
if (is_null($month)) : $month = $default['month']; endif;
|
1560 |
-
|
1561 |
-
# calc epoch for current date assuming GMT
|
1562 |
-
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
|
1563 |
-
|
1564 |
-
$offset = 0;
|
1565 |
-
if ( $match[14] == 'Z' ) {
|
1566 |
-
# zulu time, aka GMT
|
1567 |
-
}
|
1568 |
-
else {
|
1569 |
-
list( $tz_mod, $tz_hour, $tz_min ) =
|
1570 |
-
array( $match[12], $match[13], $match[14]);
|
1571 |
-
|
1572 |
-
# zero out the variables
|
1573 |
-
if ( ! $tz_hour ) { $tz_hour = 0; }
|
1574 |
-
if ( ! $tz_min ) { $tz_min = 0; }
|
1575 |
-
|
1576 |
-
$offset_secs = (($tz_hour*60)+$tz_min)*60;
|
1577 |
-
|
1578 |
-
# is timezone ahead of GMT? then subtract offset
|
1579 |
-
#
|
1580 |
-
if ( $tz_mod == '+' ) {
|
1581 |
-
$offset_secs = $offset_secs * -1;
|
1582 |
-
}
|
1583 |
-
|
1584 |
-
$offset = $offset_secs;
|
1585 |
-
}
|
1586 |
-
$epoch = $epoch + $offset;
|
1587 |
-
return $epoch;
|
1588 |
-
}
|
1589 |
-
else {
|
1590 |
-
return -1;
|
1591 |
-
}
|
1592 |
-
}
|
1593 |
-
|
1594 |
-
################################################################################
|
1595 |
-
## WordPress: wp_rss(), get_rss() ##############################################
|
1596 |
-
################################################################################
|
1597 |
-
|
1598 |
-
function wp_rss ($url, $num) {
|
1599 |
-
//ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
|
1600 |
-
$num_items = $num;
|
1601 |
-
$rss = fetch_rss($url);
|
1602 |
-
if ( $rss ) {
|
1603 |
-
echo "<ul>";
|
1604 |
-
$rss->items = array_slice($rss->items, 0, $num_items);
|
1605 |
-
foreach ($rss->items as $item ) {
|
1606 |
-
echo "<li>\n";
|
1607 |
-
echo "<a href='$item[link]' title='$item[description]'>";
|
1608 |
-
echo htmlentities($item['title']);
|
1609 |
-
echo "</a><br />\n";
|
1610 |
-
echo "</li>\n";
|
1611 |
-
}
|
1612 |
-
echo "</ul>";
|
1613 |
-
}
|
1614 |
-
else {
|
1615 |
-
echo "an error has occured the feed is probably down, try again later.";
|
1616 |
-
}
|
1617 |
-
}
|
1618 |
-
|
1619 |
-
function get_rss ($uri, $num = 5) { // Like get posts, but for RSS
|
1620 |
-
$rss = fetch_rss($url);
|
1621 |
-
if ( $rss ) {
|
1622 |
-
$rss->items = array_slice($rss->items, 0, $num_items);
|
1623 |
-
foreach ($rss->items as $item ) {
|
1624 |
-
echo "<li>\n";
|
1625 |
-
echo "<a href='$item[link]' title='$item[description]'>";
|
1626 |
-
echo htmlentities($item['title']);
|
1627 |
-
echo "</a><br />\n";
|
1628 |
-
echo "</li>\n";
|
1629 |
-
}
|
1630 |
-
return $posts;
|
1631 |
-
} else {
|
1632 |
-
return false;
|
1633 |
-
}
|
1634 |
-
}
|
1635 |
-
?>
|
1 |
<?php
|
2 |
+
// Deprecated. Use rss.php instead.
|
3 |
+
require_once (ABSPATH . WPINC . '/rss.php');
|
4 |
+
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OPTIONAL/wp-includes/rss.php
ADDED
@@ -0,0 +1,1635 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* Project: MagpieRSS: a simple RSS integration tool
|
3 |
+
* File: A compiled file for RSS syndication
|
4 |
+
* Author: Kellan Elliot-McCrea <kellan@protest.net>
|
5 |
+
* WordPress development team <http://www.wordpress.org/>
|
6 |
+
* Charles Johnson <technophilia@radgeek.com>
|
7 |
+
* Version: 0.8wp (2005.10.14)
|
8 |
+
* License: GPL
|
9 |
+
*
|
10 |
+
* Provenance:
|
11 |
+
*
|
12 |
+
* This is a drop-in replacement for the `rss-functions.php` provided with the
|
13 |
+
* WordPress 1.5 distribution, which upgrades the version of MagpieRSS from 0.51
|
14 |
+
* to 0.8a. The update improves handling of character encoding, supports
|
15 |
+
* multiple categories for posts (using <dc:subject> or <category>), supports
|
16 |
+
* Atom 1.0, and implements many other useful features. The file is derived from
|
17 |
+
* a combination of (1) the WordPress development team's modifications to
|
18 |
+
* MagpieRSS 0.51 and (2) the latest bleeding-edge updates to the "official"
|
19 |
+
* MagpieRSS software, including Kellan's original work and some substantial
|
20 |
+
* updates by Charles Johnson. All possible through the magic of the GPL. Yay
|
21 |
+
* for free software!
|
22 |
+
*
|
23 |
+
* Differences from the main branch of MagpieRSS:
|
24 |
+
*
|
25 |
+
* 1. Everything in rss_parse.inc, rss_fetch.inc, rss_cache.inc, and
|
26 |
+
* rss_utils.inc is included in one file.
|
27 |
+
*
|
28 |
+
* 2. MagpieRSS returns the WordPress version as the user agent, rather than
|
29 |
+
* Magpie
|
30 |
+
*
|
31 |
+
* 3. class RSSCache is a modified version by WordPress developers, which
|
32 |
+
* caches feeds in the WordPress database (in the options table), rather
|
33 |
+
* than writing external files directly.
|
34 |
+
*
|
35 |
+
* 4. There are two WordPress-specific functions, get_rss() and wp_rss()
|
36 |
+
*
|
37 |
+
* Differences from the version of MagpieRSS packaged with WordPress:
|
38 |
+
*
|
39 |
+
* 1. Support for translation between multiple character encodings. Under
|
40 |
+
* PHP 5 this is very nicely handled by the XML parsing library. Under PHP
|
41 |
+
* 4 we need to do a little bit of work ourselves, using either iconv or
|
42 |
+
* mb_convert_encoding if it is not one of the (extremely limited) number
|
43 |
+
* of character sets that PHP 4's XML module can handle natively.
|
44 |
+
*
|
45 |
+
* 2. Numerous bug fixes.
|
46 |
+
*
|
47 |
+
* 3. The parser class MagpieRSS has been substantially revised to better
|
48 |
+
* support popular features such as enclosures and multiple categories,
|
49 |
+
* and to support the new Atom 1.0 IETF standard. (Atom feeds are
|
50 |
+
* normalized so as to make the data available using terminology from
|
51 |
+
* either Atom 0.3 or Atom 1.0. Atom 0.3 backward-compatibility is provided
|
52 |
+
* to allow existing software to easily begin accepting Atom 1.0 data; new
|
53 |
+
* software SHOULD NOT depend on the 0.3 terminology, but rather use the
|
54 |
+
* normalization as a convenient way to keep supporting 0.3 feeds while
|
55 |
+
* they linger in the world.)
|
56 |
+
*
|
57 |
+
* The upgraded MagpieRSS can also now handle some content constructs that
|
58 |
+
* had not been handled well by previous versions of Magpie (such as the
|
59 |
+
* use of namespaced XHTML in <xhtml:body> or <xhtml:div> elements to
|
60 |
+
* provide the full content of posts in RSS 2.0 feeds).
|
61 |
+
*
|
62 |
+
* Unlike previous versions of MagpieRSS, this version can parse multiple
|
63 |
+
* instances of the same child element in item/entry and channel/feed
|
64 |
+
* containers. This is done using simple counters next to the element
|
65 |
+
* names: the first <category> element on an RSS item, for example, can be
|
66 |
+
* found in $item['category'] (thus preserving backward compatibility); the
|
67 |
+
* second in $item['category#2'], the third in $item['category#3'], and so
|
68 |
+
* on. The number of categories applied to the item can be found in
|
69 |
+
* $item['category#']
|
70 |
+
*
|
71 |
+
* Also unlike previous versions of MagpieRSS, this version allows you to
|
72 |
+
* access the values of elements' attributes as well as the content they
|
73 |
+
* contain. This can be done using a simple syntax inspired by XPath: to
|
74 |
+
* access the type attribute of an RSS 2.0 enclosure, for example, you
|
75 |
+
* need only access `$item['enclosure@type']`. A comma-separated list of
|
76 |
+
* attributes for the enclosure element is stored in `$item['enclosure@']`.
|
77 |
+
* (This syntax interacts easily with the syntax for multiple categories;
|
78 |
+
* for example, the value of the `scheme` attribute for the fourth category
|
79 |
+
* element on a particular item is stored in `$item['category#4@scheme']`.)
|
80 |
+
*
|
81 |
+
* Note also that this implementation IS NOT backward-compatible with the
|
82 |
+
* kludges that were used to hack in support for multiple categories and
|
83 |
+
* for enclosures in upgraded versions of MagpieRSS distributed with
|
84 |
+
* previous versions of FeedWordPress. If your hacks or filter plugins
|
85 |
+
* depended on the old way of doing things... well, I warned you that they
|
86 |
+
* might not be permanent. Sorry!
|
87 |
+
*/
|
88 |
+
|
89 |
+
define('RSS', 'RSS');
|
90 |
+
define('ATOM', 'Atom');
|
91 |
+
|
92 |
+
################################################################################
|
93 |
+
## WordPress: make some settings WordPress-appropriate #########################
|
94 |
+
################################################################################
|
95 |
+
|
96 |
+
define('MAGPIE_USER_AGENT', 'WordPress/' . $wp_version . '(+http://www.wordpress.org)');
|
97 |
+
|
98 |
+
$wp_encoding = get_settings('blog_charset');
|
99 |
+
define('MAGPIE_OUTPUT_ENCODING', ($wp_encoding?$wp_encoding:'ISO-8859-1'));
|
100 |
+
|
101 |
+
################################################################################
|
102 |
+
## rss_parse.inc: from MagpieRSS 0.8a ##########################################
|
103 |
+
################################################################################
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
|
107 |
+
*
|
108 |
+
* see: rss_fetch.inc for a simpler interface with integrated caching support
|
109 |
+
*
|
110 |
+
*/
|
111 |
+
class MagpieRSS {
|
112 |
+
var $parser;
|
113 |
+
|
114 |
+
var $current_item = array(); // item currently being parsed
|
115 |
+
var $items = array(); // collection of parsed items
|
116 |
+
var $channel = array(); // hash of channel fields
|
117 |
+
var $textinput = array();
|
118 |
+
var $image = array();
|
119 |
+
var $feed_type;
|
120 |
+
var $feed_version;
|
121 |
+
var $encoding = ''; // output encoding of parsed rss
|
122 |
+
|
123 |
+
var $_source_encoding = ''; // only set if we have to parse xml prolog
|
124 |
+
|
125 |
+
var $ERROR = "";
|
126 |
+
var $WARNING = "";
|
127 |
+
|
128 |
+
// define some constants
|
129 |
+
|
130 |
+
var $_ATOM_CONTENT_CONSTRUCTS = array(
|
131 |
+
'content', 'summary', 'title', /* common */
|
132 |
+
'info', 'tagline', 'copyright', /* Atom 0.3 */
|
133 |
+
'rights', 'subtitle', /* Atom 1.0 */
|
134 |
+
);
|
135 |
+
var $_XHTML_CONTENT_CONSTRUCTS = array('body', 'div');
|
136 |
+
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
|
137 |
+
|
138 |
+
// parser variables, useless if you're not a parser, treat as private
|
139 |
+
var $stack = array(); // parser stack
|
140 |
+
var $inchannel = false;
|
141 |
+
var $initem = false;
|
142 |
+
|
143 |
+
var $incontent = array(); // non-empty if in namespaced XML content field
|
144 |
+
var $exclude_top = false; // true when Atom 1.0 type="xhtml"
|
145 |
+
|
146 |
+
var $intextinput = false;
|
147 |
+
var $inimage = false;
|
148 |
+
var $current_namespace = false;
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Set up XML parser, parse source, and return populated RSS object..
|
152 |
+
*
|
153 |
+
* @param string $source string containing the RSS to be parsed
|
154 |
+
*
|
155 |
+
* NOTE: Probably a good idea to leave the encoding options alone unless
|
156 |
+
* you know what you're doing as PHP's character set support is
|
157 |
+
* a little weird.
|
158 |
+
*
|
159 |
+
* NOTE: A lot of this is unnecessary but harmless with PHP5
|
160 |
+
*
|
161 |
+
*
|
162 |
+
* @param string $output_encoding output the parsed RSS in this character
|
163 |
+
* set defaults to ISO-8859-1 as this is PHP's
|
164 |
+
* default.
|
165 |
+
*
|
166 |
+
* NOTE: might be changed to UTF-8 in future
|
167 |
+
* versions.
|
168 |
+
*
|
169 |
+
* @param string $input_encoding the character set of the incoming RSS source.
|
170 |
+
* Leave blank and Magpie will try to figure it
|
171 |
+
* out.
|
172 |
+
*
|
173 |
+
*
|
174 |
+
* @param bool $detect_encoding if false Magpie won't attempt to detect
|
175 |
+
* source encoding. (caveat emptor)
|
176 |
+
*
|
177 |
+
*/
|
178 |
+
function MagpieRSS ($source, $output_encoding='ISO-8859-1',
|
179 |
+
$input_encoding=null, $detect_encoding=true)
|
180 |
+
{
|
181 |
+
# if PHP xml isn't compiled in, die
|
182 |
+
#
|
183 |
+
if (!function_exists('xml_parser_create')) {
|
184 |
+
$this->error( "Failed to load PHP's XML Extension. " .
|
185 |
+
"http://www.php.net/manual/en/ref.xml.php",
|
186 |
+
E_USER_ERROR );
|
187 |
+
}
|
188 |
+
|
189 |
+
list($parser, $source) = $this->create_parser($source,
|
190 |
+
$output_encoding, $input_encoding, $detect_encoding);
|
191 |
+
|
192 |
+
|
193 |
+
if (!is_resource($parser)) {
|
194 |
+
$this->error( "Failed to create an instance of PHP's XML parser. " .
|
195 |
+
"http://www.php.net/manual/en/ref.xml.php",
|
196 |
+
E_USER_ERROR );
|
197 |
+
}
|
198 |
+
|
199 |
+
|
200 |
+
$this->parser = $parser;
|
201 |
+
|
202 |
+
# pass in parser, and a reference to this object
|
203 |
+
# setup handlers
|
204 |
+
#
|
205 |
+
xml_set_object( $this->parser, $this );
|
206 |
+
xml_set_element_handler($this->parser,
|
207 |
+
'feed_start_element', 'feed_end_element' );
|
208 |
+
|
209 |
+
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
|
210 |
+
|
211 |
+
$status = xml_parse( $this->parser, $source );
|
212 |
+
|
213 |
+
if (! $status ) {
|
214 |
+
$errorcode = xml_get_error_code( $this->parser );
|
215 |
+
if ( $errorcode != XML_ERROR_NONE ) {
|
216 |
+
$xml_error = xml_error_string( $errorcode );
|
217 |
+
$error_line = xml_get_current_line_number($this->parser);
|
218 |
+
$error_col = xml_get_current_column_number($this->parser);
|
219 |
+
$errormsg = "$xml_error at line $error_line, column $error_col";
|
220 |
+
|
221 |
+
$this->error( $errormsg );
|
222 |
+
}
|
223 |
+
}
|
224 |
+
|
225 |
+
xml_parser_free( $this->parser );
|
226 |
+
|
227 |
+
$this->normalize();
|
228 |
+
}
|
229 |
+
|
230 |
+
function feed_start_element($p, $element, &$attrs) {
|
231 |
+
$el = $element = strtolower($element);
|
232 |
+
$attrs = array_change_key_case($attrs, CASE_LOWER);
|
233 |
+
|
234 |
+
// check for a namespace, and split if found
|
235 |
+
if ( empty($this->incontent) ) { // Don't munge content tags
|
236 |
+
$ns = false;
|
237 |
+
if ( strpos( $element, ':' ) ) {
|
238 |
+
list($ns, $el) = split( ':', $element, 2);
|
239 |
+
}
|
240 |
+
if ( $ns and $ns != 'rdf' ) {
|
241 |
+
$this->current_namespace = $ns;
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
+
# if feed type isn't set, then this is first element of feed
|
246 |
+
# identify feed from root element
|
247 |
+
#
|
248 |
+
if (!isset($this->feed_type) ) {
|
249 |
+
if ( $el == 'rdf' ) {
|
250 |
+
$this->feed_type = RSS;
|
251 |
+
$this->feed_version = '1.0';
|
252 |
+
}
|
253 |
+
elseif ( $el == 'rss' ) {
|
254 |
+
$this->feed_type = RSS;
|
255 |
+
$this->feed_version = $attrs['version'];
|
256 |
+
}
|
257 |
+
elseif ( $el == 'feed' ) {
|
258 |
+
$this->feed_type = ATOM;
|
259 |
+
if ($attrs['xmlns'] == 'http://www.w3.org/2005/Atom') { // Atom 1.0
|
260 |
+
$this->feed_version = '1.0';
|
261 |
+
}
|
262 |
+
else { // Atom 0.3, probably.
|
263 |
+
$this->feed_version = $attrs['version'];
|
264 |
+
}
|
265 |
+
$this->inchannel = true;
|
266 |
+
}
|
267 |
+
return;
|
268 |
+
}
|
269 |
+
|
270 |
+
// if we're inside a namespaced content construct, treat tags as text
|
271 |
+
if ( !empty($this->incontent) )
|
272 |
+
{
|
273 |
+
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
274 |
+
// if tags are inlined, then flatten
|
275 |
+
$attrs_str = join(' ',
|
276 |
+
array_map('map_attrs',
|
277 |
+
array_keys($attrs),
|
278 |
+
array_values($attrs) ) );
|
279 |
+
if (strlen($attrs_str) > 0) $attrs_str = ' '.$attrs_str;
|
280 |
+
|
281 |
+
$this->append_content( "<{$element}{$attrs_str}>" );
|
282 |
+
}
|
283 |
+
array_push($this->incontent, $el); // stack for parsing content XML
|
284 |
+
}
|
285 |
+
|
286 |
+
elseif ( $el == 'channel' )
|
287 |
+
{
|
288 |
+
$this->inchannel = true;
|
289 |
+
}
|
290 |
+
|
291 |
+
elseif ($el == 'item' or $el == 'entry' )
|
292 |
+
{
|
293 |
+
$this->initem = true;
|
294 |
+
if ( isset($attrs['rdf:about']) ) {
|
295 |
+
$this->current_item['about'] = $attrs['rdf:about'];
|
296 |
+
}
|
297 |
+
}
|
298 |
+
|
299 |
+
// if we're in the default namespace of an RSS feed,
|
300 |
+
// record textinput or image fields
|
301 |
+
elseif (
|
302 |
+
$this->feed_type == RSS and
|
303 |
+
$this->current_namespace == '' and
|
304 |
+
$el == 'textinput' )
|
305 |
+
{
|
306 |
+
$this->intextinput = true;
|
307 |
+
}
|
308 |
+
|
309 |
+
elseif (
|
310 |
+
$this->feed_type == RSS and
|
311 |
+
$this->current_namespace == '' and
|
312 |
+
$el == 'image' )
|
313 |
+
{
|
314 |
+
$this->inimage = true;
|
315 |
+
}
|
316 |
+
|
317 |
+
// set stack[0] to current element
|
318 |
+
else {
|
319 |
+
// Atom support many links per containing element.
|
320 |
+
// Magpie treats link elements of type rel='alternate'
|
321 |
+
// as being equivalent to RSS's simple link element.
|
322 |
+
|
323 |
+
$atom_link = false;
|
324 |
+
if ($this->feed_type == ATOM and $el == 'link') {
|
325 |
+
$atom_link = true;
|
326 |
+
if (isset($attrs['rel']) and $attrs['rel'] != 'alternate') {
|
327 |
+
$el = $el . "_" . $attrs['rel']; // pseudo-element names for Atom link elements
|
328 |
+
}
|
329 |
+
}
|
330 |
+
# handle atom content constructs
|
331 |
+
elseif ( $this->feed_type == ATOM and in_array($el, $this->_ATOM_CONTENT_CONSTRUCTS) )
|
332 |
+
{
|
333 |
+
// avoid clashing w/ RSS mod_content
|
334 |
+
if ($el == 'content' ) {
|
335 |
+
$el = 'atom_content';
|
336 |
+
}
|
337 |
+
|
338 |
+
// assume that everything accepts namespaced XML
|
339 |
+
// (that will pass through some non-validating feeds;
|
340 |
+
// but so what? this isn't a validating parser)
|
341 |
+
$this->incontent = array();
|
342 |
+
array_push($this->incontent, $el); // start a stack
|
343 |
+
|
344 |
+
if (
|
345 |
+
isset($attrs['type'])
|
346 |
+
and trim(strtolower($attrs['type']))=='xhtml'
|
347 |
+
) {
|
348 |
+
$this->exclude_top = true;
|
349 |
+
} else {
|
350 |
+
$this->exclude_top = false;
|
351 |
+
}
|
352 |
+
}
|
353 |
+
# Handle inline XHTML body elements --CWJ
|
354 |
+
elseif (
|
355 |
+
($this->current_namespace=='xhtml' or (isset($attrs['xmlns']) and $attrs['xmlns'] == 'http://www.w3.org/1999/xhtml'))
|
356 |
+
and in_array($el, $this->_XHTML_CONTENT_CONSTRUCTS) )
|
357 |
+
{
|
358 |
+
$this->current_namespace = 'xhtml';
|
359 |
+
$this->incontent = array();
|
360 |
+
array_push($this->incontent, $el); // start a stack
|
361 |
+
$this->exclude_top = false;
|
362 |
+
}
|
363 |
+
|
364 |
+
array_unshift($this->stack, $el);
|
365 |
+
$elpath = join('_', array_reverse($this->stack));
|
366 |
+
|
367 |
+
$n = $this->element_count($elpath);
|
368 |
+
$this->element_count($elpath, $n+1);
|
369 |
+
|
370 |
+
if ($n > 0) {
|
371 |
+
array_shift($this->stack);
|
372 |
+
array_unshift($this->stack, $el.'#'.($n+1));
|
373 |
+
$elpath = join('_', array_reverse($this->stack));
|
374 |
+
}
|
375 |
+
|
376 |
+
// this makes the baby Jesus cry, but we can't do it in normalize()
|
377 |
+
// because we've made the element name for Atom links unpredictable
|
378 |
+
// by tacking on the relation to the end. -CWJ
|
379 |
+
if ($atom_link and isset($attrs['href'])) {
|
380 |
+
$this->append($elpath, $attrs['href']);
|
381 |
+
}
|
382 |
+
|
383 |
+
// add attributes
|
384 |
+
if (count($attrs) > 0) {
|
385 |
+
$this->append($elpath.'@', join(',', array_keys($attrs)));
|
386 |
+
foreach ($attrs as $attr => $value) {
|
387 |
+
$this->append($elpath.'@'.$attr, $value);
|
388 |
+
}
|
389 |
+
}
|
390 |
+
}
|
391 |
+
}
|
392 |
+
|
393 |
+
|
394 |
+
|
395 |
+
function feed_cdata ($p, $text) {
|
396 |
+
|
397 |
+
if ($this->incontent) {
|
398 |
+
$this->append_content( $text );
|
399 |
+
}
|
400 |
+
else {
|
401 |
+
$current_el = join('_', array_reverse($this->stack));
|
402 |
+
$this->append($current_el, $text);
|
403 |
+
}
|
404 |
+
}
|
405 |
+
|
406 |
+
function feed_end_element ($p, $el) {
|
407 |
+
$el = strtolower($el);
|
408 |
+
|
409 |
+
if ( $this->incontent ) {
|
410 |
+
$opener = array_pop($this->incontent);
|
411 |
+
|
412 |
+
// Don't get bamboozled by namespace voodoo
|
413 |
+
if (strpos($el, ':')) { list($ns, $closer) = split(':', $el); }
|
414 |
+
else { $ns = false; $closer = $el; }
|
415 |
+
|
416 |
+
// Don't get bamboozled by our munging of <atom:content>, either
|
417 |
+
if ($this->feed_type == ATOM and $closer == 'content') {
|
418 |
+
$closer = 'atom_content';
|
419 |
+
}
|
420 |
+
|
421 |
+
// balance tags properly
|
422 |
+
// note: i don't think this is actually neccessary
|
423 |
+
if ($opener != $closer) {
|
424 |
+
array_push($this->incontent, $opener);
|
425 |
+
$this->append_content("<$el />");
|
426 |
+
} elseif ($this->incontent) { // are we in the content construct still?
|
427 |
+
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
428 |
+
$this->append_content("</$el>");
|
429 |
+
}
|
430 |
+
} else { // shift the opening of the content construct off the normal stack
|
431 |
+
array_shift( $this->stack );
|
432 |
+
}
|
433 |
+
}
|
434 |
+
elseif ( $el == 'item' or $el == 'entry' )
|
435 |
+
{
|
436 |
+
$this->items[] = $this->current_item;
|
437 |
+
$this->current_item = array();
|
438 |
+
$this->initem = false;
|
439 |
+
|
440 |
+
$this->current_category = 0;
|
441 |
+
}
|
442 |
+
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
|
443 |
+
{
|
444 |
+
$this->intextinput = false;
|
445 |
+
}
|
446 |
+
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
|
447 |
+
{
|
448 |
+
$this->inimage = false;
|
449 |
+
}
|
450 |
+
elseif ($el == 'channel' or $el == 'feed' )
|
451 |
+
{
|
452 |
+
$this->inchannel = false;
|
453 |
+
}
|
454 |
+
else {
|
455 |
+
array_shift( $this->stack );
|
456 |
+
}
|
457 |
+
|
458 |
+
if ( !$this->incontent ) { // Don't munge the namespace after finishing with elements in namespaced content constructs -CWJ
|
459 |
+
$this->current_namespace = false;
|
460 |
+
}
|
461 |
+
}
|
462 |
+
|
463 |
+
function concat (&$str1, $str2="") {
|
464 |
+
if (!isset($str1) ) {
|
465 |
+
$str1="";
|
466 |
+
}
|
467 |
+
$str1 .= $str2;
|
468 |
+
}
|
469 |
+
|
470 |
+
function append_content($text) {
|
471 |
+
if ( $this->initem ) {
|
472 |
+
if ($this->current_namespace) {
|
473 |
+
$this->concat( $this->current_item[$this->current_namespace][ reset($this->incontent) ], $text );
|
474 |
+
} else {
|
475 |
+
$this->concat( $this->current_item[ reset($this->incontent) ], $text );
|
476 |
+
}
|
477 |
+
}
|
478 |
+
elseif ( $this->inchannel ) {
|
479 |
+
if ($this->current_namespace) {
|
480 |
+
$this->concat( $this->channel[$this->current_namespace][ reset($this->incontent) ], $text );
|
481 |
+
} else {
|
482 |
+
$this->concat( $this->channel[ reset($this->incontent) ], $text );
|
483 |
+
}
|
484 |
+
}
|
485 |
+
}
|
486 |
+
|
487 |
+
// smart append - field and namespace aware
|
488 |
+
function append($el, $text) {
|
489 |
+
if (!$el) {
|
490 |
+
return;
|
491 |
+
}
|
492 |
+
if ( $this->current_namespace )
|
493 |
+
{
|
494 |
+
if ( $this->initem ) {
|
495 |
+
$this->concat(
|
496 |
+
$this->current_item[ $this->current_namespace ][ $el ], $text);
|
497 |
+
}
|
498 |
+
elseif ($this->inchannel) {
|
499 |
+
$this->concat(
|
500 |
+
$this->channel[ $this->current_namespace][ $el ], $text );
|
501 |
+
}
|
502 |
+
elseif ($this->intextinput) {
|
503 |
+
$this->concat(
|
504 |
+
$this->textinput[ $this->current_namespace][ $el ], $text );
|
505 |
+
}
|
506 |
+
elseif ($this->inimage) {
|
507 |
+
$this->concat(
|
508 |
+
$this->image[ $this->current_namespace ][ $el ], $text );
|
509 |
+
}
|
510 |
+
}
|
511 |
+
else {
|
512 |
+
if ( $this->initem ) {
|
513 |
+
$this->concat(
|
514 |
+
$this->current_item[ $el ], $text);
|
515 |
+
}
|
516 |
+
elseif ($this->intextinput) {
|
517 |
+
$this->concat(
|
518 |
+
$this->textinput[ $el ], $text );
|
519 |
+
}
|
520 |
+
elseif ($this->inimage) {
|
521 |
+
$this->concat(
|
522 |
+
$this->image[ $el ], $text );
|
523 |
+
}
|
524 |
+
elseif ($this->inchannel) {
|
525 |
+
$this->concat(
|
526 |
+
$this->channel[ $el ], $text );
|
527 |
+
}
|
528 |
+
|
529 |
+
}
|
530 |
+
}
|
531 |
+
|
532 |
+
// smart count - field and namespace aware
|
533 |
+
function element_count ($el, $set = NULL) {
|
534 |
+
if (!$el) {
|
535 |
+
return;
|
536 |
+
}
|
537 |
+
if ( $this->current_namespace )
|
538 |
+
{
|
539 |
+
if ( $this->initem ) {
|
540 |
+
if (!is_null($set)) { $this->current_item[ $this->current_namespace ][ $el.'#' ] = $set; }
|
541 |
+
$ret = (isset($this->current_item[ $this->current_namespace ][ $el.'#' ]) ?
|
542 |
+
$this->current_item[ $this->current_namespace ][ $el.'#' ] : 0);
|
543 |
+
}
|
544 |
+
elseif ($this->inchannel) {
|
545 |
+
if (!is_null($set)) { $this->channel[ $this->current_namespace ][ $el.'#' ] = $set; }
|
546 |
+
$ret = (isset($this->channel[ $this->current_namespace][ $el.'#' ]) ?
|
547 |
+
$this->channel[ $this->current_namespace][ $el.'#' ] : 0);
|
548 |
+
}
|
549 |
+
}
|
550 |
+
else {
|
551 |
+
if ( $this->initem ) {
|
552 |
+
if (!is_null($set)) { $this->current_item[ $el.'#' ] = $set; }
|
553 |
+
$ret = (isset($this->current_item[ $el.'#' ]) ?
|
554 |
+
$this->current_item[ $el.'#' ] : 0);
|
555 |
+
}
|
556 |
+
elseif ($this->inchannel) {
|
557 |
+
if (!is_null($set)) {$this->channel[ $el.'#' ] = $set; }
|
558 |
+
$ret = (isset($this->channel[ $el.'#' ]) ?
|
559 |
+
$this->channel[ $el.'#' ] : 0);
|
560 |
+
}
|
561 |
+
}
|
562 |
+
return $ret;
|
563 |
+
}
|
564 |
+
|
565 |
+
function normalize_enclosure (&$source, $from, &$dest, $to, $i) {
|
566 |
+
$id_from = $this->element_id($from, $i);
|
567 |
+
$id_to = $this->element_id($to, $i);
|
568 |
+
if (isset($source["{$id_from}@"])) {
|
569 |
+
foreach (explode(',', $source["{$id_from}@"]) as $attr) {
|
570 |
+
if ($from=='link_enclosure' and $attr=='href') { // from Atom
|
571 |
+
$dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"];
|
572 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
573 |
+
}
|
574 |
+
elseif ($from=='enclosure' and $attr=='url') { // from RSS
|
575 |
+
$dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"];
|
576 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
577 |
+
}
|
578 |
+
else {
|
579 |
+
$dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"];
|
580 |
+
}
|
581 |
+
}
|
582 |
+
}
|
583 |
+
}
|
584 |
+
|
585 |
+
function normalize_atom_person (&$source, $person, &$dest, $to, $i) {
|
586 |
+
$id = $this->element_id($person, $i);
|
587 |
+
$id_to = $this->element_id($to, $i);
|
588 |
+
|
589 |
+
// Atom 0.3 <=> Atom 1.0
|
590 |
+
if ($this->feed_version >= 1.0) { $used = 'uri'; $norm = 'url'; }
|
591 |
+
else { $used = 'url'; $norm = 'uri'; }
|
592 |
+
|
593 |
+
if (isset($source["{$id}_{$used}"])) {
|
594 |
+
$dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"];
|
595 |
+
}
|
596 |
+
|
597 |
+
// Atom to RSS 2.0 and Dublin Core
|
598 |
+
// RSS 2.0 person strings should be valid e-mail addresses if possible.
|
599 |
+
if (isset($source["{$id}_email"])) {
|
600 |
+
$rss_author = $source["{$id}_email"];
|
601 |
+
}
|
602 |
+
if (isset($source["{$id}_name"])) {
|
603 |
+
$rss_author = $source["{$id}_name"]
|
604 |
+
. (isset($rss_author) ? " <$rss_author>" : '');
|
605 |
+
}
|
606 |
+
if (isset($rss_author)) {
|
607 |
+
$source[$id] = $rss_author; // goes to top-level author or contributor
|
608 |
+
$dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor
|
609 |
+
}
|
610 |
+
}
|
611 |
+
|
612 |
+
// Normalize Atom 1.0 and RSS 2.0 categories to Dublin Core...
|
613 |
+
function normalize_category (&$source, $from, &$dest, $to, $i) {
|
614 |
+
$cat_id = $this->element_id($from, $i);
|
615 |
+
$dc_id = $this->element_id($to, $i);
|
616 |
+
|
617 |
+
// first normalize category elements: Atom 1.0 <=> RSS 2.0
|
618 |
+
if ( isset($source["{$cat_id}@term"]) ) { // category identifier
|
619 |
+
$source[$cat_id] = $source["{$cat_id}@term"];
|
620 |
+
} elseif ( $this->feed_type == RSS ) {
|
621 |
+
$source["{$cat_id}@term"] = $source[$cat_id];
|
622 |
+
}
|
623 |
+
|
624 |
+
if ( isset($source["{$cat_id}@scheme"]) ) { // URI to taxonomy
|
625 |
+
$source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"];
|
626 |
+
} elseif ( isset($source["{$cat_id}@domain"]) ) {
|
627 |
+
$source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"];
|
628 |
+
}
|
629 |
+
|
630 |
+
// Now put the identifier into dc:subject
|
631 |
+
$dest[$dc_id] = $source[$cat_id];
|
632 |
+
}
|
633 |
+
|
634 |
+
// ... or vice versa
|
635 |
+
function normalize_dc_subject (&$source, $from, &$dest, $to, $i) {
|
636 |
+
$dc_id = $this->element_id($from, $i);
|
637 |
+
$cat_id = $this->element_id($to, $i);
|
638 |
+
|
639 |
+
$dest[$cat_id] = $source[$dc_id]; // RSS 2.0
|
640 |
+
$dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0
|
641 |
+
}
|
642 |
+
|
643 |
+
// simplify the logic for normalize(). Makes sure that count of elements and
|
644 |
+
// each of multiple elements is normalized properly. If you need to mess
|
645 |
+
// with things like attributes or change formats or the like, pass it a
|
646 |
+
// callback to handle each element.
|
647 |
+
function normalize_element (&$source, $from, &$dest, $to, $via = NULL) {
|
648 |
+
if (isset($source[$from]) or isset($source["{$from}#"])) {
|
649 |
+
if (isset($source["{$from}#"])) {
|
650 |
+
$n = $source["{$from}#"];
|
651 |
+
$dest["{$to}#"] = $source["{$from}#"];
|
652 |
+
}
|
653 |
+
else { $n = 1; }
|
654 |
+
|
655 |
+
for ($i = 1; $i <= $n; $i++) {
|
656 |
+
if (isset($via)) { // custom callback for ninja attacks
|
657 |
+
$this->{$via}($source, $from, $dest, $to, $i);
|
658 |
+
}
|
659 |
+
else { // just make it the same
|
660 |
+
$from_id = $this->element_id($from, $i);
|
661 |
+
$to_id = $this->element_id($to, $i);
|
662 |
+
$dest[$to_id] = $source[$from_id];
|
663 |
+
}
|
664 |
+
}
|
665 |
+
}
|
666 |
+
}
|
667 |
+
|
668 |
+
function normalize () {
|
669 |
+
// if atom populate rss fields and normalize 0.3 and 1.0 feeds
|
670 |
+
if ( $this->is_atom() ) {
|
671 |
+
// Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!)
|
672 |
+
if ($this->feed_version < 1.0) {
|
673 |
+
$this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle');
|
674 |
+
$this->normalize_element($this->channel, 'copyright', $this->channel, 'rights');
|
675 |
+
$this->normalize_element($this->channel, 'modified', $this->channel, 'updated');
|
676 |
+
} else {
|
677 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline');
|
678 |
+
$this->normalize_element($this->channel, 'rights', $this->channel, 'copyright');
|
679 |
+
$this->normalize_element($this->channel, 'updated', $this->channel, 'modified');
|
680 |
+
}
|
681 |
+
$this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person');
|
682 |
+
$this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person');
|
683 |
+
|
684 |
+
// Atom elements to RSS elements
|
685 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'description');
|
686 |
+
|
687 |
+
if ( isset($this->channel['logo']) ) {
|
688 |
+
$this->normalize_element($this->channel, 'logo', $this->image, 'url');
|
689 |
+
$this->normalize_element($this->channel, 'link', $this->image, 'link');
|
690 |
+
$this->normalize_element($this->channel, 'title', $this->image, 'title');
|
691 |
+
}
|
692 |
+
|
693 |
+
for ( $i = 0; $i < count($this->items); $i++) {
|
694 |
+
$item = $this->items[$i];
|
695 |
+
|
696 |
+
// Atom 1.0 elements <=> Atom 0.3 elements
|
697 |
+
if ($this->feed_version < 1.0) {
|
698 |
+
$this->normalize_element($item, 'modified', $item, 'updated');
|
699 |
+
$this->normalize_element($item, 'issued', $item, 'published');
|
700 |
+
} else {
|
701 |
+
$this->normalize_element($item, 'updated', $item, 'modified');
|
702 |
+
$this->normalize_element($item, 'published', $item, 'issued');
|
703 |
+
}
|
704 |
+
|
705 |
+
// "If an atom:entry element does not contain
|
706 |
+
// atom:author elements, then the atom:author elements
|
707 |
+
// of the contained atom:source element are considered
|
708 |
+
// to apply. In an Atom Feed Document, the atom:author
|
709 |
+
// elements of the containing atom:feed element are
|
710 |
+
// considered to apply to the entry if there are no
|
711 |
+
// atom:author elements in the locations described
|
712 |
+
// above." <http://atompub.org/2005/08/17/draft-ietf-atompub-format-11.html#rfc.section.4.2.1>
|
713 |
+
if (!isset($item["author#"])) {
|
714 |
+
if (isset($item["source_author#"])) { // from aggregation source
|
715 |
+
$source = $item;
|
716 |
+
$author = "source_author";
|
717 |
+
} elseif (isset($this->channel["author#"])) { // from containing feed
|
718 |
+
$source = $this->channel;
|
719 |
+
$author = "author";
|
720 |
+
}
|
721 |
+
|
722 |
+
$item["author#"] = $source["{$author}#"];
|
723 |
+
for ($au = 1; $au <= $item["author#"]; $au++) {
|
724 |
+
$id_to = $this->element_id('author', $au);
|
725 |
+
$id_from = $this->element_id($author, $au);
|
726 |
+
|
727 |
+
$item[$id_to] = $source[$id_from];
|
728 |
+
foreach (array('name', 'email', 'uri', 'url') as $what) {
|
729 |
+
if (isset($source["{$id_from}_{$what}"])) {
|
730 |
+
$item["{$id_to}_{$what}"] = $source["{$id_from}_{$what}"];
|
731 |
+
}
|
732 |
+
}
|
733 |
+
}
|
734 |
+
}
|
735 |
+
|
736 |
+
// Atom elements to RSS elements
|
737 |
+
$this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person');
|
738 |
+
$this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person');
|
739 |
+
$this->normalize_element($item, 'summary', $item, 'description');
|
740 |
+
$this->normalize_element($item, 'atom_content', $item['content'], 'encoded');
|
741 |
+
$this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure');
|
742 |
+
|
743 |
+
// Categories
|
744 |
+
if ( isset($item['category#']) ) { // Atom 1.0 categories to dc:subject and RSS 2.0 categories
|
745 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
746 |
+
}
|
747 |
+
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
748 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
749 |
+
}
|
750 |
+
|
751 |
+
// Normalized item timestamp
|
752 |
+
$atom_date = (isset($item['published']) ) ? $item['published'] : $item['updated'];
|
753 |
+
if ( $atom_date ) {
|
754 |
+
$epoch = @parse_w3cdtf($atom_date);
|
755 |
+
if ($epoch and $epoch > 0) {
|
756 |
+
$item['date_timestamp'] = $epoch;
|
757 |
+
}
|
758 |
+
}
|
759 |
+
|
760 |
+
$this->items[$i] = $item;
|
761 |
+
}
|
762 |
+
}
|
763 |
+
elseif ( $this->is_rss() ) {
|
764 |
+
// RSS elements to Atom elements
|
765 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3
|
766 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!)
|
767 |
+
$this->normalize_element($this->image, 'url', $this->channel, 'logo');
|
768 |
+
|
769 |
+
for ( $i = 0; $i < count($this->items); $i++) {
|
770 |
+
$item = $this->items[$i];
|
771 |
+
|
772 |
+
// RSS elements to Atom elements
|
773 |
+
$this->normalize_element($item, 'description', $item, 'summary');
|
774 |
+
$this->normalize_element($item['content'], 'encoded', $item, 'atom_content');
|
775 |
+
$this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure');
|
776 |
+
|
777 |
+
// Categories
|
778 |
+
if ( isset($item['category#']) ) { // RSS 2.0 categories to dc:subject and Atom 1.0 categories
|
779 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
780 |
+
}
|
781 |
+
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
782 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
783 |
+
}
|
784 |
+
|
785 |
+
// Normalized item timestamp
|
786 |
+
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
|
787 |
+
$epoch = @parse_w3cdtf($item['dc']['date']);
|
788 |
+
if ($epoch and $epoch > 0) {
|
789 |
+
$item['date_timestamp'] = $epoch;
|
790 |
+
}
|
791 |
+
}
|
792 |
+
elseif ( isset($item['pubdate']) ) {
|
793 |
+
$epoch = @strtotime($item['pubdate']);
|
794 |
+
if ($epoch > 0) {
|
795 |
+
$item['date_timestamp'] = $epoch;
|
796 |
+
}
|
797 |
+
}
|
798 |
+
|
799 |
+
$this->items[$i] = $item;
|
800 |
+
}
|
801 |
+
}
|
802 |
+
}
|
803 |
+
|
804 |
+
|
805 |
+
function is_rss () {
|
806 |
+
if ( $this->feed_type == RSS ) {
|
807 |
+
return $this->feed_version;
|
808 |
+
}
|
809 |
+
else {
|
810 |
+
return false;
|
811 |
+
}
|
812 |
+
}
|
813 |
+
|
814 |
+
function is_atom() {
|
815 |
+
if ( $this->feed_type == ATOM ) {
|
816 |
+
return $this->feed_version;
|
817 |
+
}
|
818 |
+
else {
|
819 |
+
return false;
|
820 |
+
}
|
821 |
+
}
|
822 |
+
|
823 |
+
/**
|
824 |
+
* return XML parser, and possibly re-encoded source
|
825 |
+
*
|
826 |
+
*/
|
827 |
+
function create_parser($source, $out_enc, $in_enc, $detect) {
|
828 |
+
if ( substr(phpversion(),0,1) == 5) {
|
829 |
+
$parser = $this->php5_create_parser($in_enc, $detect);
|
830 |
+
}
|
831 |
+
else {
|
832 |
+
list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
|
833 |
+
}
|
834 |
+
if ($out_enc) {
|
835 |
+
$this->encoding = $out_enc;
|
836 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
|
837 |
+
}
|
838 |
+
|
839 |
+
return array($parser, $source);
|
840 |
+
}
|
841 |
+
|
842 |
+
/**
|
843 |
+
* Instantiate an XML parser under PHP5
|
844 |
+
*
|
845 |
+
* PHP5 will do a fine job of detecting input encoding
|
846 |
+
* if passed an empty string as the encoding.
|
847 |
+
*
|
848 |
+
* All hail libxml2!
|
849 |
+
*
|
850 |
+
*/
|
851 |
+
function php5_create_parser($in_enc, $detect) {
|
852 |
+
// by default php5 does a fine job of detecting input encodings
|
853 |
+
if(!$detect && $in_enc) {
|
854 |
+
return xml_parser_create($in_enc);
|
855 |
+
}
|
856 |
+
else {
|
857 |
+
return xml_parser_create('');
|
858 |
+
}
|
859 |
+
}
|
860 |
+
|
861 |
+
/**
|
862 |
+
* Instaniate an XML parser under PHP4
|
863 |
+
*
|
864 |
+
* Unfortunately PHP4's support for character encodings
|
865 |
+
* and especially XML and character encodings sucks. As
|
866 |
+
* long as the documents you parse only contain characters
|
867 |
+
* from the ISO-8859-1 character set (a superset of ASCII,
|
868 |
+
* and a subset of UTF-8) you're fine. However once you
|
869 |
+
* step out of that comfy little world things get mad, bad,
|
870 |
+
* and dangerous to know.
|
871 |
+
*
|
872 |
+
* The following code is based on SJM's work with FoF
|
873 |
+
* @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
|
874 |
+
*
|
875 |
+
*/
|
876 |
+
function php4_create_parser($source, $in_enc, $detect) {
|
877 |
+
if ( !$detect ) {
|
878 |
+
return array(xml_parser_create($in_enc), $source);
|
879 |
+
}
|
880 |
+
|
881 |
+
if (!$in_enc) {
|
882 |
+
if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
|
883 |
+
$in_enc = strtoupper($m[1]);
|
884 |
+
$this->source_encoding = $in_enc;
|
885 |
+
}
|
886 |
+
else {
|
887 |
+
$in_enc = 'UTF-8';
|
888 |
+
}
|
889 |
+
}
|
890 |
+
|
891 |
+
if ($this->known_encoding($in_enc)) {
|
892 |
+
return array(xml_parser_create($in_enc), $source);
|
893 |
+
}
|
894 |
+
|
895 |
+
// the dectected encoding is not one of the simple encodings PHP knows
|
896 |
+
|
897 |
+
// attempt to use the iconv extension to
|
898 |
+
// cast the XML to a known encoding
|
899 |
+
// @see http://php.net/iconv
|
900 |
+
|
901 |
+
if (function_exists('iconv')) {
|
902 |
+
$encoded_source = iconv($in_enc,'UTF-8', $source);
|
903 |
+
if ($encoded_source) {
|
904 |
+
return array(xml_parser_create('UTF-8'), $encoded_source);
|
905 |
+
}
|
906 |
+
}
|
907 |
+
|
908 |
+
// iconv didn't work, try mb_convert_encoding
|
909 |
+
// @see http://php.net/mbstring
|
910 |
+
if(function_exists('mb_convert_encoding')) {
|
911 |
+
$encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
|
912 |
+
if ($encoded_source) {
|
913 |
+
return array(xml_parser_create('UTF-8'), $encoded_source);
|
914 |
+
}
|
915 |
+
}
|
916 |
+
|
917 |
+
// else
|
918 |
+
$this->error("Feed is in an unsupported character encoding. ($in_enc) " .
|
919 |
+
"You may see strange artifacts, and mangled characters.",
|
920 |
+
E_USER_NOTICE);
|
921 |
+
|
922 |
+
return array(xml_parser_create(), $source);
|
923 |
+
}
|
924 |
+
|
925 |
+
function known_encoding($enc) {
|
926 |
+
$enc = strtoupper($enc);
|
927 |
+
if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) {
|
928 |
+
return $enc;
|
929 |
+
}
|
930 |
+
else {
|
931 |
+
return false;
|
932 |
+
}
|
933 |
+
}
|
934 |
+
|
935 |
+
function error ($errormsg, $lvl=E_USER_WARNING) {
|
936 |
+
// append PHP's error message if track_errors enabled
|
937 |
+
if ( isset($php_errormsg) ) {
|
938 |
+
$errormsg .= " ($php_errormsg)";
|
939 |
+
}
|
940 |
+
if ( MAGPIE_DEBUG ) {
|
941 |
+
trigger_error( $errormsg, $lvl);
|
942 |
+
}
|
943 |
+
else {
|
944 |
+
error_log( $errormsg, 0);
|
945 |
+
}
|
946 |
+
|
947 |
+
$notices = E_USER_NOTICE|E_NOTICE;
|
948 |
+
if ( $lvl&$notices ) {
|
949 |
+
$this->WARNING = $errormsg;
|
950 |
+
} else {
|
951 |
+
$this->ERROR = $errormsg;
|
952 |
+
}
|
953 |
+
}
|
954 |
+
|
955 |
+
// magic ID function for multiple elemenets.
|
956 |
+
// can be called as static MagpieRSS::element_id()
|
957 |
+
function element_id ($el, $counter) {
|
958 |
+
return $el . (($counter > 1) ? '#'.$counter : '');
|
959 |
+
}
|
960 |
+
} // end class RSS
|
961 |
+
|
962 |
+
function map_attrs($k, $v) {
|
963 |
+
return "$k=\"$v\"";
|
964 |
+
}
|
965 |
+
|
966 |
+
// patch to support medieval versions of PHP4.1.x,
|
967 |
+
// courtesy, Ryan Currie, ryan@digibliss.com
|
968 |
+
|
969 |
+
if (!function_exists('array_change_key_case')) {
|
970 |
+
define("CASE_UPPER",1);
|
971 |
+
define("CASE_LOWER",0);
|
972 |
+
|
973 |
+
|
974 |
+
function array_change_key_case($array,$case=CASE_LOWER) {
|
975 |
+
if ($case==CASE_LOWER) $cmd='strtolower';
|
976 |
+
elseif ($case==CASE_UPPER) $cmd='strtoupper';
|
977 |
+
foreach($array as $key=>$value) {
|
978 |
+
$output[$cmd($key)]=$value;
|
979 |
+
}
|
980 |
+
return $output;
|
981 |
+
}
|
982 |
+
|
983 |
+
}
|
984 |
+
|
985 |
+
################################################################################
|
986 |
+
## WordPress: Load in Snoopy from wp-includes ##################################
|
987 |
+
################################################################################
|
988 |
+
|
989 |
+
require_once( dirname(__FILE__) . '/class-snoopy.php');
|
990 |
+
|
991 |
+
################################################################################
|
992 |
+
## rss_fetch.inc: from MagpieRSS 0.8a ##########################################
|
993 |
+
################################################################################
|
994 |
+
|
995 |
+
/*=======================================================================*\
|
996 |
+
Function: fetch_rss:
|
997 |
+
Purpose: return RSS object for the give url
|
998 |
+
maintain the cache
|
999 |
+
Input: url of RSS file
|
1000 |
+
Output: parsed RSS object (see rss_parse.inc)
|
1001 |
+
|
1002 |
+
NOTES ON CACHEING:
|
1003 |
+
If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache.
|
1004 |
+
|
1005 |
+
NOTES ON RETRIEVING REMOTE FILES:
|
1006 |
+
If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will
|
1007 |
+
return a cached object, and touch the cache object upon recieving a
|
1008 |
+
304.
|
1009 |
+
|
1010 |
+
NOTES ON FAILED REQUESTS:
|
1011 |
+
If there is an HTTP error while fetching an RSS object, the cached
|
1012 |
+
version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off)
|
1013 |
+
\*=======================================================================*/
|
1014 |
+
|
1015 |
+
define('MAGPIE_VERSION', '0.7');
|
1016 |
+
|
1017 |
+
$MAGPIE_ERROR = "";
|
1018 |
+
|
1019 |
+
function fetch_rss ($url) {
|
1020 |
+
// initialize constants
|
1021 |
+
init();
|
1022 |
+
|
1023 |
+
if ( !isset($url) ) {
|
1024 |
+
error("fetch_rss called without a url");
|
1025 |
+
return false;
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
// if cache is disabled
|
1029 |
+
if ( !MAGPIE_CACHE_ON ) {
|
1030 |
+
// fetch file, and parse it
|
1031 |
+
$resp = _fetch_remote_file( $url );
|
1032 |
+
if ( is_success( $resp->status ) ) {
|
1033 |
+
return _response_to_rss( $resp );
|
1034 |
+
}
|
1035 |
+
else {
|
1036 |
+
error("Failed to fetch $url and cache is off");
|
1037 |
+
return false;
|
1038 |
+
}
|
1039 |
+
}
|
1040 |
+
// else cache is ON
|
1041 |
+
else {
|
1042 |
+
// Flow
|
1043 |
+
// 1. check cache
|
1044 |
+
// 2. if there is a hit, make sure its fresh
|
1045 |
+
// 3. if cached obj fails freshness check, fetch remote
|
1046 |
+
// 4. if remote fails, return stale object, or error
|
1047 |
+
|
1048 |
+
$cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
|
1049 |
+
|
1050 |
+
if (MAGPIE_DEBUG and $cache->ERROR) {
|
1051 |
+
debug($cache->ERROR, E_USER_WARNING);
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
|
1055 |
+
$cache_status = 0; // response of check_cache
|
1056 |
+
$request_headers = array(); // HTTP headers to send with fetch
|
1057 |
+
$rss = 0; // parsed RSS object
|
1058 |
+
$errormsg = 0; // errors, if any
|
1059 |
+
|
1060 |
+
// store parsed XML by desired output encoding
|
1061 |
+
// as character munging happens at parse time
|
1062 |
+
$cache_key = $url . MAGPIE_OUTPUT_ENCODING;
|
1063 |
+
|
1064 |
+
if (!$cache->ERROR) {
|
1065 |
+
// return cache HIT, MISS, or STALE
|
1066 |
+
$cache_status = $cache->check_cache( $cache_key);
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
// if object cached, and cache is fresh, return cached obj
|
1070 |
+
if ( $cache_status == 'HIT' ) {
|
1071 |
+
$rss = $cache->get( $cache_key );
|
1072 |
+
if ( isset($rss) and $rss ) {
|
1073 |
+
// should be cache age
|
1074 |
+
$rss->from_cache = 1;
|
1075 |
+
if ( MAGPIE_DEBUG > 1) {
|
1076 |
+
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
|
1077 |
+
}
|
1078 |
+
return $rss;
|
1079 |
+
}
|
1080 |
+
}
|
1081 |
+
|
1082 |
+
// else attempt a conditional get
|
1083 |
+
|
1084 |
+
// setup headers
|
1085 |
+
if ( $cache_status == 'STALE' ) {
|
1086 |
+
$rss = $cache->get( $cache_key );
|
1087 |
+
if ( $rss and $rss->etag and $rss->last_modified ) {
|
1088 |
+
$request_headers['If-None-Match'] = $rss->etag;
|
1089 |
+
$request_headers['If-Last-Modified'] = $rss->last_modified;
|
1090 |
+
}
|
1091 |
+
}
|
1092 |
+
|
1093 |
+
$resp = _fetch_remote_file( $url, $request_headers );
|
1094 |
+
|
1095 |
+
if (isset($resp) and $resp) {
|
1096 |
+
if ($resp->status == '304' ) {
|
1097 |
+
// we have the most current copy
|
1098 |
+
if ( MAGPIE_DEBUG > 1) {
|
1099 |
+
debug("Got 304 for $url");
|
1100 |
+
}
|
1101 |
+
// reset cache on 304 (at minutillo insistent prodding)
|
1102 |
+
$cache->set($cache_key, $rss);
|
1103 |
+
return $rss;
|
1104 |
+
}
|
1105 |
+
elseif ( is_success( $resp->status ) ) {
|
1106 |
+
$rss = _response_to_rss( $resp );
|
1107 |
+
if ( $rss ) {
|
1108 |
+
if (MAGPIE_DEBUG > 1) {
|
1109 |
+
debug("Fetch successful");
|
1110 |
+
}
|
1111 |
+
// add object to cache
|
1112 |
+
$cache->set( $cache_key, $rss );
|
1113 |
+
return $rss;
|
1114 |
+
}
|
1115 |
+
}
|
1116 |
+
else {
|
1117 |
+
$errormsg = "Failed to fetch $url ";
|
1118 |
+
if ( $resp->status == '-100' ) {
|
1119 |
+
$errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)";
|
1120 |
+
}
|
1121 |
+
elseif ( $resp->error ) {
|
1122 |
+
# compensate for Snoopy's annoying habbit to tacking
|
1123 |
+
# on '\n'
|
1124 |
+
$http_error = substr($resp->error, 0, -2);
|
1125 |
+
$errormsg .= "(HTTP Error: $http_error)";
|
1126 |
+
}
|
1127 |
+
else {
|
1128 |
+
$errormsg .= "(HTTP Response: " . $resp->response_code .')';
|
1129 |
+
}
|
1130 |
+
}
|
1131 |
+
}
|
1132 |
+
else {
|
1133 |
+
$errormsg = "Unable to retrieve RSS file for unknown reasons.";
|
1134 |
+
}
|
1135 |
+
|
1136 |
+
// else fetch failed
|
1137 |
+
|
1138 |
+
// attempt to return cached object
|
1139 |
+
if ($rss) {
|
1140 |
+
if ( MAGPIE_DEBUG ) {
|
1141 |
+
debug("Returning STALE object for $url");
|
1142 |
+
}
|
1143 |
+
return $rss;
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
// else we totally failed
|
1147 |
+
error( $errormsg );
|
1148 |
+
|
1149 |
+
return false;
|
1150 |
+
|
1151 |
+
} // end if ( !MAGPIE_CACHE_ON ) {
|
1152 |
+
} // end fetch_rss()
|
1153 |
+
|
1154 |
+
/*=======================================================================*\
|
1155 |
+
Function: error
|
1156 |
+
Purpose: set MAGPIE_ERROR, and trigger error
|
1157 |
+
\*=======================================================================*/
|
1158 |
+
|
1159 |
+
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1160 |
+
global $MAGPIE_ERROR;
|
1161 |
+
|
1162 |
+
// append PHP's error message if track_errors enabled
|
1163 |
+
if ( isset($php_errormsg) ) {
|
1164 |
+
$errormsg .= " ($php_errormsg)";
|
1165 |
+
}
|
1166 |
+
if ( $errormsg ) {
|
1167 |
+
$errormsg = "MagpieRSS: $errormsg";
|
1168 |
+
$MAGPIE_ERROR = $errormsg;
|
1169 |
+
trigger_error( $errormsg, $lvl);
|
1170 |
+
}
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1174 |
+
trigger_error("MagpieRSS [debug] $debugmsg", $lvl);
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
/*=======================================================================*\
|
1178 |
+
Function: magpie_error
|
1179 |
+
Purpose: accessor for the magpie error variable
|
1180 |
+
\*=======================================================================*/
|
1181 |
+
function magpie_error ($errormsg="") {
|
1182 |
+
global $MAGPIE_ERROR;
|
1183 |
+
|
1184 |
+
if ( isset($errormsg) and $errormsg ) {
|
1185 |
+
$MAGPIE_ERROR = $errormsg;
|
1186 |
+
}
|
1187 |
+
|
1188 |
+
return $MAGPIE_ERROR;
|
1189 |
+
}
|
1190 |
+
|
1191 |
+
/*=======================================================================*\
|
1192 |
+
Function: _fetch_remote_file
|
1193 |
+
Purpose: retrieve an arbitrary remote file
|
1194 |
+
Input: url of the remote file
|
1195 |
+
headers to send along with the request (optional)
|
1196 |
+
Output: an HTTP response object (see Snoopy.class.inc)
|
1197 |
+
\*=======================================================================*/
|
1198 |
+
function _fetch_remote_file ($url, $headers = "" ) {
|
1199 |
+
// Snoopy is an HTTP client in PHP
|
1200 |
+
$client = new Snoopy();
|
1201 |
+
$client->agent = MAGPIE_USER_AGENT;
|
1202 |
+
$client->read_timeout = MAGPIE_FETCH_TIME_OUT;
|
1203 |
+
$client->use_gzip = MAGPIE_USE_GZIP;
|
1204 |
+
if (is_array($headers) ) {
|
1205 |
+
$client->rawheaders = $headers;
|
1206 |
+
}
|
1207 |
+
|
1208 |
+
@$client->fetch($url);
|
1209 |
+
return $client;
|
1210 |
+
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
/*=======================================================================*\
|
1214 |
+
Function: _response_to_rss
|
1215 |
+
Purpose: parse an HTTP response object into an RSS object
|
1216 |
+
Input: an HTTP response object (see Snoopy)
|
1217 |
+
Output: parsed RSS object (see rss_parse)
|
1218 |
+
\*=======================================================================*/
|
1219 |
+
function _response_to_rss ($resp) {
|
1220 |
+
$rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
|
1221 |
+
|
1222 |
+
// if RSS parsed successfully
|
1223 |
+
if ( $rss and !$rss->ERROR) {
|
1224 |
+
|
1225 |
+
// find Etag, and Last-Modified
|
1226 |
+
foreach($resp->headers as $h) {
|
1227 |
+
// 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
|
1228 |
+
if (strpos($h, ": ")) {
|
1229 |
+
list($field, $val) = explode(": ", $h, 2);
|
1230 |
+
}
|
1231 |
+
else {
|
1232 |
+
$field = $h;
|
1233 |
+
$val = "";
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
if ( $field == 'ETag' ) {
|
1237 |
+
$rss->etag = $val;
|
1238 |
+
}
|
1239 |
+
|
1240 |
+
if ( $field == 'Last-Modified' ) {
|
1241 |
+
$rss->last_modified = $val;
|
1242 |
+
}
|
1243 |
+
}
|
1244 |
+
|
1245 |
+
return $rss;
|
1246 |
+
} // else construct error message
|
1247 |
+
else {
|
1248 |
+
$errormsg = "Failed to parse RSS file.";
|
1249 |
+
|
1250 |
+
if ($rss) {
|
1251 |
+
$errormsg .= " (" . $rss->ERROR . ")";
|
1252 |
+
}
|
1253 |
+
error($errormsg);
|
1254 |
+
|
1255 |
+
return false;
|
1256 |
+
} // end if ($rss and !$rss->error)
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
/*=======================================================================*\
|
1260 |
+
Function: init
|
1261 |
+
Purpose: setup constants with default values
|
1262 |
+
check for user overrides
|
1263 |
+
\*=======================================================================*/
|
1264 |
+
function init () {
|
1265 |
+
if ( defined('MAGPIE_INITALIZED') ) {
|
1266 |
+
return;
|
1267 |
+
}
|
1268 |
+
else {
|
1269 |
+
define('MAGPIE_INITALIZED', true);
|
1270 |
+
}
|
1271 |
+
|
1272 |
+
if ( !defined('MAGPIE_CACHE_ON') ) {
|
1273 |
+
define('MAGPIE_CACHE_ON', true);
|
1274 |
+
}
|
1275 |
+
|
1276 |
+
if ( !defined('MAGPIE_CACHE_DIR') ) {
|
1277 |
+
define('MAGPIE_CACHE_DIR', './cache');
|
1278 |
+
}
|
1279 |
+
|
1280 |
+
if ( !defined('MAGPIE_CACHE_AGE') ) {
|
1281 |
+
define('MAGPIE_CACHE_AGE', 60*60); // one hour
|
1282 |
+
}
|
1283 |
+
|
1284 |
+
if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
|
1285 |
+
define('MAGPIE_CACHE_FRESH_ONLY', false);
|
1286 |
+
}
|
1287 |
+
|
1288 |
+
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
|
1289 |
+
define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1');
|
1290 |
+
}
|
1291 |
+
|
1292 |
+
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
|
1293 |
+
define('MAGPIE_INPUT_ENCODING', null);
|
1294 |
+
}
|
1295 |
+
|
1296 |
+
if ( !defined('MAGPIE_DETECT_ENCODING') ) {
|
1297 |
+
define('MAGPIE_DETECT_ENCODING', true);
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
if ( !defined('MAGPIE_DEBUG') ) {
|
1301 |
+
define('MAGPIE_DEBUG', 0);
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
if ( !defined('MAGPIE_USER_AGENT') ) {
|
1305 |
+
$ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net';
|
1306 |
+
|
1307 |
+
if ( MAGPIE_CACHE_ON ) {
|
1308 |
+
$ua = $ua . ')';
|
1309 |
+
}
|
1310 |
+
else {
|
1311 |
+
$ua = $ua . '; No cache)';
|
1312 |
+
}
|
1313 |
+
|
1314 |
+
define('MAGPIE_USER_AGENT', $ua);
|
1315 |
+
}
|
1316 |
+
|
1317 |
+
if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
|
1318 |
+
define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
// use gzip encoding to fetch rss files if supported?
|
1322 |
+
if ( !defined('MAGPIE_USE_GZIP') ) {
|
1323 |
+
define('MAGPIE_USE_GZIP', true);
|
1324 |
+
}
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
// NOTE: the following code should really be in Snoopy, or at least
|
1328 |
+
// somewhere other then rss_fetch!
|
1329 |
+
|
1330 |
+
/*=======================================================================*\
|
1331 |
+
HTTP STATUS CODE PREDICATES
|
1332 |
+
These functions attempt to classify an HTTP status code
|
1333 |
+
based on RFC 2616 and RFC 2518.
|
1334 |
+
|
1335 |
+
All of them take an HTTP status code as input, and return true or false
|
1336 |
+
|
1337 |
+
All this code is adapted from LWP's HTTP::Status.
|
1338 |
+
\*=======================================================================*/
|
1339 |
+
|
1340 |
+
|
1341 |
+
/*=======================================================================*\
|
1342 |
+
Function: is_info
|
1343 |
+
Purpose: return true if Informational status code
|
1344 |
+
\*=======================================================================*/
|
1345 |
+
function is_info ($sc) {
|
1346 |
+
return $sc >= 100 && $sc < 200;
|
1347 |
+
}
|
1348 |
+
|
1349 |
+
/*=======================================================================*\
|
1350 |
+
Function: is_success
|
1351 |
+
Purpose: return true if Successful status code
|
1352 |
+
\*=======================================================================*/
|
1353 |
+
function is_success ($sc) {
|
1354 |
+
return $sc >= 200 && $sc < 300;
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
/*=======================================================================*\
|
1358 |
+
Function: is_redirect
|
1359 |
+
Purpose: return true if Redirection status code
|
1360 |
+
\*=======================================================================*/
|
1361 |
+
function is_redirect ($sc) {
|
1362 |
+
return $sc >= 300 && $sc < 400;
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
/*=======================================================================*\
|
1366 |
+
Function: is_error
|
1367 |
+
Purpose: return true if Error status code
|
1368 |
+
\*=======================================================================*/
|
1369 |
+
function is_error ($sc) {
|
1370 |
+
return $sc >= 400 && $sc < 600;
|
1371 |
+
}
|
1372 |
+
|
1373 |
+
/*=======================================================================*\
|
1374 |
+
Function: is_client_error
|
1375 |
+
Purpose: return true if Error status code, and its a client error
|
1376 |
+
\*=======================================================================*/
|
1377 |
+
function is_client_error ($sc) {
|
1378 |
+
return $sc >= 400 && $sc < 500;
|
1379 |
+
}
|
1380 |
+
|
1381 |
+
/*=======================================================================*\
|
1382 |
+
Function: is_client_error
|
1383 |
+
Purpose: return true if Error status code, and its a server error
|
1384 |
+
\*=======================================================================*/
|
1385 |
+
function is_server_error ($sc) {
|
1386 |
+
return $sc >= 500 && $sc < 600;
|
1387 |
+
}
|
1388 |
+
|
1389 |
+
################################################################################
|
1390 |
+
## rss_cache.inc: from WordPress 1.5 ###########################################
|
1391 |
+
################################################################################
|
1392 |
+
|
1393 |
+
class RSSCache {
|
1394 |
+
var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
|
1395 |
+
var $MAX_AGE = 43200; // when are files stale, default twelve hours
|
1396 |
+
var $ERROR = ''; // accumulate error messages
|
1397 |
+
|
1398 |
+
function RSSCache ($base='', $age='') {
|
1399 |
+
if ( $base ) {
|
1400 |
+
$this->BASE_CACHE = $base;
|
1401 |
+
}
|
1402 |
+
if ( $age ) {
|
1403 |
+
$this->MAX_AGE = $age;
|
1404 |
+
}
|
1405 |
+
|
1406 |
+
}
|
1407 |
+
|
1408 |
+
/*=======================================================================*\
|
1409 |
+
Function: set
|
1410 |
+
Purpose: add an item to the cache, keyed on url
|
1411 |
+
Input: url from wich the rss file was fetched
|
1412 |
+
Output: true on sucess
|
1413 |
+
\*=======================================================================*/
|
1414 |
+
function set ($url, $rss) {
|
1415 |
+
global $wpdb;
|
1416 |
+
$cache_option = 'rss_' . $this->file_name( $url );
|
1417 |
+
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1418 |
+
|
1419 |
+
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_option'") )
|
1420 |
+
add_option($cache_option, '', '', 'no');
|
1421 |
+
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_timestamp'") )
|
1422 |
+
add_option($cache_timestamp, '', '', 'no');
|
1423 |
+
|
1424 |
+
update_option($cache_option, $rss);
|
1425 |
+
update_option($cache_timestamp, time() );
|
1426 |
+
|
1427 |
+
return $cache_option;
|
1428 |
+
}
|
1429 |
+
|
1430 |
+
/*=======================================================================*\
|
1431 |
+
Function: get
|
1432 |
+
Purpose: fetch an item from the cache
|
1433 |
+
Input: url from wich the rss file was fetched
|
1434 |
+
Output: cached object on HIT, false on MISS
|
1435 |
+
\*=======================================================================*/
|
1436 |
+
function get ($url) {
|
1437 |
+
$this->ERROR = "";
|
1438 |
+
$cache_option = 'rss_' . $this->file_name( $url );
|
1439 |
+
|
1440 |
+
if ( ! get_option( $cache_option ) ) {
|
1441 |
+
$this->debug(
|
1442 |
+
"Cache doesn't contain: $url (cache option: $cache_option)"
|
1443 |
+
);
|
1444 |
+
return 0;
|
1445 |
+
}
|
1446 |
+
|
1447 |
+
$rss = get_option( $cache_option );
|
1448 |
+
|
1449 |
+
return $rss;
|
1450 |
+
}
|
1451 |
+
|
1452 |
+
/*=======================================================================*\
|
1453 |
+
Function: check_cache
|
1454 |
+
Purpose: check a url for membership in the cache
|
1455 |
+
and whether the object is older then MAX_AGE (ie. STALE)
|
1456 |
+
Input: url from wich the rss file was fetched
|
1457 |
+
Output: cached object on HIT, false on MISS
|
1458 |
+
\*=======================================================================*/
|
1459 |
+
function check_cache ( $url ) {
|
1460 |
+
$this->ERROR = "";
|
1461 |
+
$cache_option = $this->file_name( $url );
|
1462 |
+
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1463 |
+
|
1464 |
+
if ( $mtime = get_option($cache_timestamp) ) {
|
1465 |
+
// find how long ago the file was added to the cache
|
1466 |
+
// and whether that is longer then MAX_AGE
|
1467 |
+
$age = time() - $mtime;
|
1468 |
+
if ( $this->MAX_AGE > $age ) {
|
1469 |
+
// object exists and is current
|
1470 |
+
return 'HIT';
|
1471 |
+
}
|
1472 |
+
else {
|
1473 |
+
// object exists but is old
|
1474 |
+
return 'STALE';
|
1475 |
+
}
|
1476 |
+
}
|
1477 |
+
else {
|
1478 |
+
// object does not exist
|
1479 |
+
return 'MISS';
|
1480 |
+
}
|
1481 |
+
}
|
1482 |
+
|
1483 |
+
/*=======================================================================*\
|
1484 |
+
Function: serialize
|
1485 |
+
\*=======================================================================*/
|
1486 |
+
function serialize ( $rss ) {
|
1487 |
+
return serialize( $rss );
|
1488 |
+
}
|
1489 |
+
|
1490 |
+
/*=======================================================================*\
|
1491 |
+
Function: unserialize
|
1492 |
+
\*=======================================================================*/
|
1493 |
+
function unserialize ( $data ) {
|
1494 |
+
return unserialize( $data );
|
1495 |
+
}
|
1496 |
+
|
1497 |
+
/*=======================================================================*\
|
1498 |
+
Function: file_name
|
1499 |
+
Purpose: map url to location in cache
|
1500 |
+
Input: url from wich the rss file was fetched
|
1501 |
+
Output: a file name
|
1502 |
+
\*=======================================================================*/
|
1503 |
+
function file_name ($url) {
|
1504 |
+
return md5( $url );
|
1505 |
+
}
|
1506 |
+
|
1507 |
+
/*=======================================================================*\
|
1508 |
+
Function: error
|
1509 |
+
Purpose: register error
|
1510 |
+
\*=======================================================================*/
|
1511 |
+
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1512 |
+
// append PHP's error message if track_errors enabled
|
1513 |
+
if ( isset($php_errormsg) ) {
|
1514 |
+
$errormsg .= " ($php_errormsg)";
|
1515 |
+
}
|
1516 |
+
$this->ERROR = $errormsg;
|
1517 |
+
if ( MAGPIE_DEBUG ) {
|
1518 |
+
trigger_error( $errormsg, $lvl);
|
1519 |
+
}
|
1520 |
+
else {
|
1521 |
+
error_log( $errormsg, 0);
|
1522 |
+
}
|
1523 |
+
}
|
1524 |
+
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1525 |
+
if ( MAGPIE_DEBUG ) {
|
1526 |
+
$this->error("MagpieRSS [debug] $debugmsg", $lvl);
|
1527 |
+
}
|
1528 |
+
}
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
################################################################################
|
1532 |
+
## rss_utils.inc: from MagpieRSS 0.8a ##########################################
|
1533 |
+
################################################################################
|
1534 |
+
|
1535 |
+
/*======================================================================*\
|
1536 |
+
Function: parse_w3cdtf
|
1537 |
+
Purpose: parse a W3CDTF date into unix epoch
|
1538 |
+
|
1539 |
+
NOTE: http://www.w3.org/TR/NOTE-datetime
|
1540 |
+
\*======================================================================*/
|
1541 |
+
|
1542 |
+
function parse_w3cdtf ( $date_str ) {
|
1543 |
+
|
1544 |
+
# regex to match wc3dtf
|
1545 |
+
$pat = "/^\s*(\d{4})(-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(\.\d+)?)?(?:([-+])(\d{2}):?(\d{2})|(Z))?)?)?)?\s*\$/";
|
1546 |
+
|
1547 |
+
if ( preg_match( $pat, $date_str, $match ) ) {
|
1548 |
+
list( $year, $month, $day, $hours, $minutes, $seconds) =
|
1549 |
+
array( $match[1], $match[3], $match[5], $match[7], $match[8], $match[10]);
|
1550 |
+
|
1551 |
+
# W3C dates can omit the time, the day of the month, or even the month.
|
1552 |
+
# Fill in any blanks using information from the present moment. --CWJ
|
1553 |
+
$default['hr'] = (int) gmdate('H');
|
1554 |
+
$default['day'] = (int) gmdate('d');
|
1555 |
+
$default['month'] = (int) gmdate('m');
|
1556 |
+
|
1557 |
+
if (is_null($hours)) : $hours = $default['hr']; $minutes = 0; $seconds = 0; endif;
|
1558 |
+
if (is_null($day)) : $day = $default['day']; endif;
|
1559 |
+
if (is_null($month)) : $month = $default['month']; endif;
|
1560 |
+
|
1561 |
+
# calc epoch for current date assuming GMT
|
1562 |
+
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
|
1563 |
+
|
1564 |
+
$offset = 0;
|
1565 |
+
if ( $match[14] == 'Z' ) {
|
1566 |
+
# zulu time, aka GMT
|
1567 |
+
}
|
1568 |
+
else {
|
1569 |
+
list( $tz_mod, $tz_hour, $tz_min ) =
|
1570 |
+
array( $match[12], $match[13], $match[14]);
|
1571 |
+
|
1572 |
+
# zero out the variables
|
1573 |
+
if ( ! $tz_hour ) { $tz_hour = 0; }
|
1574 |
+
if ( ! $tz_min ) { $tz_min = 0; }
|
1575 |
+
|
1576 |
+
$offset_secs = (($tz_hour*60)+$tz_min)*60;
|
1577 |
+
|
1578 |
+
# is timezone ahead of GMT? then subtract offset
|
1579 |
+
#
|
1580 |
+
if ( $tz_mod == '+' ) {
|
1581 |
+
$offset_secs = $offset_secs * -1;
|
1582 |
+
}
|
1583 |
+
|
1584 |
+
$offset = $offset_secs;
|
1585 |
+
}
|
1586 |
+
$epoch = $epoch + $offset;
|
1587 |
+
return $epoch;
|
1588 |
+
}
|
1589 |
+
else {
|
1590 |
+
return -1;
|
1591 |
+
}
|
1592 |
+
}
|
1593 |
+
|
1594 |
+
################################################################################
|
1595 |
+
## WordPress: wp_rss(), get_rss() ##############################################
|
1596 |
+
################################################################################
|
1597 |
+
|
1598 |
+
function wp_rss ($url, $num) {
|
1599 |
+
//ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
|
1600 |
+
$num_items = $num;
|
1601 |
+
$rss = fetch_rss($url);
|
1602 |
+
if ( $rss ) {
|
1603 |
+
echo "<ul>";
|
1604 |
+
$rss->items = array_slice($rss->items, 0, $num_items);
|
1605 |
+
foreach ($rss->items as $item ) {
|
1606 |
+
echo "<li>\n";
|
1607 |
+
echo "<a href='$item[link]' title='$item[description]'>";
|
1608 |
+
echo htmlentities($item['title']);
|
1609 |
+
echo "</a><br />\n";
|
1610 |
+
echo "</li>\n";
|
1611 |
+
}
|
1612 |
+
echo "</ul>";
|
1613 |
+
}
|
1614 |
+
else {
|
1615 |
+
echo "an error has occured the feed is probably down, try again later.";
|
1616 |
+
}
|
1617 |
+
}
|
1618 |
+
|
1619 |
+
function get_rss ($uri, $num = 5) { // Like get posts, but for RSS
|
1620 |
+
$rss = fetch_rss($url);
|
1621 |
+
if ( $rss ) {
|
1622 |
+
$rss->items = array_slice($rss->items, 0, $num_items);
|
1623 |
+
foreach ($rss->items as $item ) {
|
1624 |
+
echo "<li>\n";
|
1625 |
+
echo "<a href='$item[link]' title='$item[description]'>";
|
1626 |
+
echo htmlentities($item['title']);
|
1627 |
+
echo "</a><br />\n";
|
1628 |
+
echo "</li>\n";
|
1629 |
+
}
|
1630 |
+
return $posts;
|
1631 |
+
} else {
|
1632 |
+
return false;
|
1633 |
+
}
|
1634 |
+
}
|
1635 |
+
?>
|
README.text
CHANGED
@@ -2,7 +2,7 @@ FeedWordPress
|
|
2 |
=============
|
3 |
|
4 |
* Author: [Charles Johnson](http://radgeek.com/contact)
|
5 |
-
* Version: 0.
|
6 |
* Project URI: <http://projects.radgeek.com/feedwordpress>
|
7 |
* License: GPL 2. See License below for copyright jots and tittles.
|
8 |
|
@@ -20,13 +20,14 @@ originally developed it because I needed a more flexible replacement for
|
|
20 |
|
21 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
22 |
configuration in mind. You'll need a working installation of WordPress (version
|
23 |
-
[2.0][] or [1.5][]), and also FTP or SFTP access to your web host. The
|
24 |
-
to create cron jobs on your web host would be very helpful but it's not
|
25 |
absolutely necessary. You *don't* need to tweak any plain-text configuration
|
26 |
files and you *don't* need shell access to your web host to make it work.
|
27 |
(Although, I should point out, web hosts that *don't* offer shell access are
|
28 |
*bad web hosts*.)
|
29 |
|
|
|
30 |
[2.0]: http://wordpress.org/development/2005/12/wp2/
|
31 |
[1.5]: http://wordpress.org/development/2005/02/strayhorn/
|
32 |
|
@@ -34,10 +35,11 @@ Installation
|
|
34 |
------------
|
35 |
### Requirements ###
|
36 |
|
37 |
-
To use version 0.
|
38 |
|
39 |
-
1. an installed configured copy of WordPress 2.0.x or 1.5.x.
|
40 |
-
*will not work* with
|
|
|
41 |
|
42 |
2. FTP or SFTP access to your web host
|
43 |
|
@@ -51,13 +53,13 @@ And you'll probably also want to have either:
|
|
51 |
|
52 |
#### Upgrades ####
|
53 |
|
54 |
-
To *upgrade* an existing installation of FeedWordPress to version 0.
|
55 |
|
56 |
1. Download the FeedWordPress archive in zip or gzipped tar format and
|
57 |
extract the files on your computer. Replace your existing FeedWordPress
|
58 |
-
files with the new files. Be sure to upgrade `rss
|
59 |
-
use the optional MagpieRSS upgrade, or don't
|
60 |
-
syndicate Atom 1.0 feeds.
|
61 |
|
62 |
2. If you are upgrading from version 0.96 or earlier, **immediately** log
|
63 |
in to the WordPress Dashboard, and go to Options --> Syndicated. Follow
|
@@ -88,7 +90,7 @@ To *upgrade* an existing installation of FeedWordPress to version 0.98:
|
|
88 |
and `update-feeds.php` in your WordPress `wp-content` directory.
|
89 |
|
90 |
2. (Optional) Upgrade the copy of MagpieRSS packaged with WordPress by
|
91 |
-
installing the new `rss-functions.php` (archived in
|
92 |
`OPTIONAL/wp-includes`) into your WordPress `wp-includes` directory.
|
93 |
Upgrading MagpieRSS is necessary if you want to take advantage of
|
94 |
support for Atom 1.0, multiple post categories, RSS enclosures, and
|
@@ -109,11 +111,11 @@ To *upgrade* an existing installation of FeedWordPress to version 0.98:
|
|
109 |
provides some light security by keeping passing ruffians from saying
|
110 |
"Update all the feeds" at will to your FeedWordPress installation.
|
111 |
|
112 |
-
5. Go to Links --> Syndicated to set up the list
|
113 |
-
FeedWordPress to syndicate onto your blog. (If
|
114 |
-
want to aggregate in a service such as Bloglines,
|
115 |
-
export them to an OPML file and use WordPress's Links
|
116 |
-
import them into the contributors category.)
|
117 |
|
118 |
#### Setting Up Feed Updates ####
|
119 |
|
2 |
=============
|
3 |
|
4 |
* Author: [Charles Johnson](http://radgeek.com/contact)
|
5 |
+
* Version: 0.981
|
6 |
* Project URI: <http://projects.radgeek.com/feedwordpress>
|
7 |
* License: GPL 2. See License below for copyright jots and tittles.
|
8 |
|
20 |
|
21 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
22 |
configuration in mind. You'll need a working installation of WordPress (version
|
23 |
+
[2.1][], [2.0][] or [1.5][]), and also FTP or SFTP access to your web host. The
|
24 |
+
ability to create cron jobs on your web host would be very helpful but it's not
|
25 |
absolutely necessary. You *don't* need to tweak any plain-text configuration
|
26 |
files and you *don't* need shell access to your web host to make it work.
|
27 |
(Although, I should point out, web hosts that *don't* offer shell access are
|
28 |
*bad web hosts*.)
|
29 |
|
30 |
+
[2.1]: http://wordpress.org/development/2007/01/ella-21/
|
31 |
[2.0]: http://wordpress.org/development/2005/12/wp2/
|
32 |
[1.5]: http://wordpress.org/development/2005/02/strayhorn/
|
33 |
|
35 |
------------
|
36 |
### Requirements ###
|
37 |
|
38 |
+
To use version 0.981 of FeedWordPress, you will need:
|
39 |
|
40 |
+
1. an installed and configured copy of WordPress 2.1, 2.0.x, or 1.5.x.
|
41 |
+
(FeedWordPress currently *will not work* with older versions of
|
42 |
+
WordPress, or with WordPress MU.)
|
43 |
|
44 |
2. FTP or SFTP access to your web host
|
45 |
|
53 |
|
54 |
#### Upgrades ####
|
55 |
|
56 |
+
To *upgrade* an existing installation of FeedWordPress to version 0.981:
|
57 |
|
58 |
1. Download the FeedWordPress archive in zip or gzipped tar format and
|
59 |
extract the files on your computer. Replace your existing FeedWordPress
|
60 |
+
files with the new files. Be sure to upgrade `rss.php` and
|
61 |
+
`rss-functions.php` if you use the optional MagpieRSS upgrade, or don't
|
62 |
+
use it yet but do want to syndicate Atom 1.0 feeds.
|
63 |
|
64 |
2. If you are upgrading from version 0.96 or earlier, **immediately** log
|
65 |
in to the WordPress Dashboard, and go to Options --> Syndicated. Follow
|
90 |
and `update-feeds.php` in your WordPress `wp-content` directory.
|
91 |
|
92 |
2. (Optional) Upgrade the copy of MagpieRSS packaged with WordPress by
|
93 |
+
installing the new `rss.php` and `rss-functions.php` (archived in
|
94 |
`OPTIONAL/wp-includes`) into your WordPress `wp-includes` directory.
|
95 |
Upgrading MagpieRSS is necessary if you want to take advantage of
|
96 |
support for Atom 1.0, multiple post categories, RSS enclosures, and
|
111 |
provides some light security by keeping passing ruffians from saying
|
112 |
"Update all the feeds" at will to your FeedWordPress installation.
|
113 |
|
114 |
+
5. Go to Blogroll --> Syndicated or Links --> Syndicated to set up the list
|
115 |
+
of sites that you want FeedWordPress to syndicate onto your blog. (If
|
116 |
+
you have the feeds you want to aggregate in a service such as Bloglines,
|
117 |
+
you may prefer to export them to an OPML file and use WordPress's Links
|
118 |
+
--> Import to import them into the contributors category.)
|
119 |
|
120 |
#### Setting Up Feed Updates ####
|
121 |
|
wp-content/plugins/feedwordpress.php
CHANGED
@@ -3,11 +3,11 @@
|
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
-
Version: 0.
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
10 |
-
Last modified:
|
11 |
*/
|
12 |
|
13 |
# This uses code derived from:
|
@@ -27,7 +27,7 @@ Last modified: 2005-09-28 4:40pm EDT
|
|
27 |
|
28 |
# -- Don't change these unless you know what you're doing...
|
29 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/');
|
30 |
-
define ('FEEDWORDPRESS_VERSION', '0.
|
31 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
32 |
|
33 |
define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
|
@@ -36,37 +36,24 @@ define ('FEEDWORDPRESS_CAT_SEPARATOR', "\n");
|
|
36 |
define ('FEEDVALIDATOR_URI', 'http://feedvalidator.org/check.cgi');
|
37 |
|
38 |
// Note that the rss-functions.php that comes prepackaged with WordPress is
|
39 |
-
// old & busted. For the new hotness, drop a copy of rss
|
40 |
-
// this archive into wp-includes/rss
|
41 |
-
require_once (ABSPATH . WPINC . '/rss-functions.php');
|
42 |
|
43 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
require_once (ABSPATH . WPINC . '/registration-functions.php');
|
|
|
45 |
endif;
|
46 |
|
47 |
// Is this being loaded from within WordPress 1.5 or later?
|
48 |
if (isset($wp_version) and $wp_version >= 1.5):
|
49 |
|
50 |
-
|
51 |
-
$feedwordpress_needs_upgrade = false; // innocent until proven guilty
|
52 |
-
if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
|
53 |
-
// check to see whether this is a fresh install or an upgrade
|
54 |
-
$syn = $wpdb->get_col("
|
55 |
-
SELECT post_id
|
56 |
-
FROM $wpdb->postmeta
|
57 |
-
WHERE meta_key = 'syndication_feed'
|
58 |
-
");
|
59 |
-
if (count($syn) > 0) : // contains at least one syndicated post
|
60 |
-
$feedwordpress_needs_upgrade = true;
|
61 |
-
else : // fresh install; brand it as ours
|
62 |
-
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
63 |
-
if (!get_settings('feedwordpress_rpc_secret')) :
|
64 |
-
update_option('feedwordpress_rpc_secret', substr(md5(uniqid(microtime())), 0, 6));
|
65 |
-
endif;
|
66 |
-
endif;
|
67 |
-
endif;
|
68 |
-
|
69 |
-
if (!$feedwordpress_needs_upgrade) : // only work if the conditions are safe!
|
70 |
|
71 |
# Syndicated items are generally received in output-ready (X)HTML and
|
72 |
# should not be folded, crumpled, mutilated, or spindled by WordPress
|
@@ -109,7 +96,7 @@ if (isset($wp_version) and $wp_version >= 1.5):
|
|
109 |
else :
|
110 |
# Hook in the menus, which will just point to the upgrade interface
|
111 |
add_action('admin_menu', 'fwp_add_pages');
|
112 |
-
endif; // if (
|
113 |
endif;
|
114 |
|
115 |
################################################################################
|
@@ -149,6 +136,34 @@ function log_feedwordpress_update_complete ($delta) {
|
|
149 |
: implode(' and ', $mesg)));
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
################################################################################
|
153 |
## TEMPLATE API: functions to make your templates syndication-aware ############
|
154 |
################################################################################
|
@@ -262,9 +277,9 @@ function fwp_upgrade_page () {
|
|
262 |
<h2>Upgrade FeedWordPress</h2>
|
263 |
|
264 |
<p>It appears that you have installed FeedWordPress
|
265 |
-
|
266 |
FeedWordPress. That's no problem, but you will need to take a minute out first
|
267 |
-
to upgrade your database: some
|
268 |
track of posts and feeds will cause problems such as duplicate posts and broken
|
269 |
templates if we were to continue without the upgrade.</p>
|
270 |
|
@@ -288,14 +303,26 @@ like me you may want to back up your database before you proceed.</p>
|
|
288 |
################################################################################
|
289 |
|
290 |
function fwp_add_pages () {
|
291 |
-
|
292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
} // function fwp_add_pages () */
|
294 |
|
295 |
function fwp_syndication_options_page () {
|
296 |
-
global $wpdb, $
|
297 |
|
298 |
-
if (
|
299 |
fwp_upgrade_page();
|
300 |
return;
|
301 |
endif;
|
@@ -304,7 +331,7 @@ function fwp_syndication_options_page () {
|
|
304 |
if (isset($_POST['action']) and $_POST['action']==$caption):
|
305 |
check_admin_referer();
|
306 |
|
307 |
-
if (
|
308 |
die (__("Cheatin' uh ?"));
|
309 |
else:
|
310 |
update_option('feedwordpress_rpc_secret', $_REQUEST['rpc_secret']);
|
@@ -392,7 +419,12 @@ function fwp_syndication_options_page () {
|
|
392 |
if (is_string($uc) and array_key_exists($uc, $unfamiliar_category)) :
|
393 |
$unfamiliar_category[$uc] = ' checked="checked"';
|
394 |
endif;
|
395 |
-
|
|
|
|
|
|
|
|
|
|
|
396 |
|
397 |
$cats = get_settings('feedwordpress_syndication_cats');
|
398 |
$dogs = get_nested_categories(-1, 0);
|
@@ -419,6 +451,8 @@ function fwp_syndication_options_page () {
|
|
419 |
<td width="67%"><?php
|
420 |
echo "\n<select name=\"syndication_category\" size=\"1\">";
|
421 |
foreach ($results as $row) {
|
|
|
|
|
422 |
echo "\n\t<option value=\"$row->cat_id\"";
|
423 |
if ($row->cat_id == $cat_id)
|
424 |
echo " selected='selected'";
|
@@ -433,9 +467,9 @@ function fwp_syndication_options_page () {
|
|
433 |
|
434 |
<tr><th width="33%" scope="row" style="vertical-align:top">Update live from feed:</th>
|
435 |
<td width="67%"><ul style="margin:0;list-style:none">
|
436 |
-
<li><input type="checkbox" name="hardcode_name" value="no"
|
437 |
-
<li><input type="checkbox" name="hardcode_description" value="no"
|
438 |
-
<li><input type="checkbox" name="hardcode_url" value="no"
|
439 |
</ul></td></tr>
|
440 |
</table>
|
441 |
</fieldset>
|
@@ -443,53 +477,48 @@ function fwp_syndication_options_page () {
|
|
443 |
<fieldset class="options">
|
444 |
<legend>Syndicated Posts</legend>
|
445 |
|
446 |
-
|
447 |
-
<legend>Categories</legend>
|
448 |
-
<p style="font-size:smaller;font-style:bold;margin:0">Place <em>all syndicated
|
449 |
-
posts</em> under...</p>
|
450 |
-
<div style="height: 20em"><?php write_nested_categories($dogs); ?></div>
|
451 |
-
</fieldset>
|
452 |
|
453 |
<table class="editform" width="75%" cellspacing="2" cellpadding="5">
|
454 |
<tr style="vertical-align: top"><th width="33%" scope="row">Publication:</th>
|
455 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
456 |
-
<li><label><input type="radio" name="post_status" value="publish"
|
457 |
-
<li><label><input type="radio" name="post_status" value="draft"
|
458 |
-
<li><label><input type="radio" name="post_status" value="private"
|
459 |
</ul></td></tr>
|
460 |
|
461 |
<tr style="vertical-align: top"><th width="33%" scope="row">Comments:</th>
|
462 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
463 |
-
<li><label><input type="radio" name="comment_status" value="open"
|
464 |
-
<li><label><input type="radio" name="comment_status" value="closed"
|
465 |
</ul></td></tr>
|
466 |
|
467 |
<tr style="vertical-align: top"><th width="33%" scope="row">Trackback and Pingback:</th>
|
468 |
<td width="67%"><ul style="margin:0; padding: 0; list-style:none">
|
469 |
-
<li><label><input type="radio" name="ping_status" value="open"
|
470 |
-
<li><label><input type="radio" name="ping_status" value="closed"
|
471 |
</ul></td></tr>
|
472 |
|
473 |
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
474 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
475 |
-
<li><label><input type="radio" name="unfamiliar_author" value="create"
|
476 |
-
<li><label><input type="radio" name="unfamiliar_author" value="default"
|
477 |
-
<li><label><input type="radio" name="unfamiliar_author" value="filter"
|
478 |
</ul></td></tr>
|
479 |
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
480 |
<td width="67%"><ul style="margin: 0; padding:0; list-style:none">
|
481 |
-
<li><label><input type="radio" name="unfamiliar_category" value="create"
|
482 |
-
<li><label><input type="radio" name="unfamiliar_category" value="default"
|
483 |
-
<li><label><input type="radio" name="unfamiliar_category" value="filter"
|
484 |
</ul></td></tr>
|
485 |
|
486 |
<tr style="vertical-align: top"><th width="33%" scope="row">Permalinks point to:</th>
|
487 |
<td width="67%"><select name="munge_permalink" size="1">
|
488 |
-
<option value="yes"
|
489 |
-
<option value="no"
|
490 |
</select></td></tr>
|
491 |
</table>
|
492 |
-
<div class="submit"><input type="submit" name="action" value="
|
493 |
</fieldset>
|
494 |
|
495 |
<fieldset class="options">
|
@@ -497,28 +526,59 @@ posts</em> under...</p>
|
|
497 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
498 |
<tr>
|
499 |
<th width="33%" scope="row">XML-RPC update secret word:</th>
|
500 |
-
<td width="67%"><input id="rpc_secret" name="rpc_secret" value="
|
501 |
</td>
|
502 |
</tr>
|
503 |
<tr>
|
504 |
<th scope="row">Write update notices to PHP logs:</th>
|
505 |
<td><select name="update_logging" size="1">
|
506 |
-
<option value="yes"
|
507 |
-
<option value="no"
|
508 |
</select></td>
|
509 |
</tr>
|
510 |
</table>
|
511 |
-
<div class="submit"><input type="submit" name="action" value="
|
512 |
</fieldset>
|
513 |
</form>
|
514 |
</div>
|
515 |
<?php
|
516 |
}
|
517 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
518 |
function fwp_syndication_manage_page () {
|
519 |
-
global $
|
520 |
|
521 |
-
if (
|
522 |
fwp_upgrade_page();
|
523 |
return;
|
524 |
endif;
|
@@ -536,10 +596,10 @@ endif;
|
|
536 |
if ($cont):
|
537 |
?>
|
538 |
<?php
|
539 |
-
$links =
|
540 |
?>
|
541 |
<div class="wrap">
|
542 |
-
<form action="link-manager.php?page
|
543 |
<h2>Syndicate a new site:</h2>
|
544 |
<div>
|
545 |
<label for="add-uri">Website or newsfeed:</label>
|
@@ -550,7 +610,7 @@ if ($cont):
|
|
550 |
</form>
|
551 |
</div>
|
552 |
|
553 |
-
<form action="link-manager.php?page
|
554 |
<div class="wrap">
|
555 |
<h2>Syndicated Sites</h2>
|
556 |
<?php $alt_row = true;
|
@@ -565,8 +625,8 @@ if ($cont):
|
|
565 |
|
566 |
<?php foreach ($links as $link):
|
567 |
$alt_row = !$alt_row; ?>
|
568 |
-
<tr
|
569 |
-
<td><a href="
|
570 |
<?php
|
571 |
if (strlen($link->link_rss) > 0):
|
572 |
$caption='Switch Feed';
|
@@ -581,7 +641,7 @@ if ($cont):
|
|
581 |
if (strlen($display_uri) > 32) : $display_uri = substr($display_uri, 0, 32).'…'; endif;
|
582 |
?>
|
583 |
<td>
|
584 |
-
<strong><a href="
|
585 |
<?php
|
586 |
else:
|
587 |
$caption='Find Feed';
|
@@ -590,17 +650,12 @@ if ($cont):
|
|
590 |
feed assigned</strong></p></td>
|
591 |
<?php
|
592 |
endif;
|
593 |
-
|
594 |
-
if (($link->user_level <= $user_level)):
|
595 |
?>
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
<?php
|
601 |
-
else:
|
602 |
-
echo "<td> </td><td> </td><td> </td><td> </td>\n";
|
603 |
-
endif;
|
604 |
echo "\n\t</tr>";
|
605 |
endforeach;
|
606 |
else:
|
@@ -624,7 +679,7 @@ endif;
|
|
624 |
}
|
625 |
|
626 |
function fwp_feedfinder_page () {
|
627 |
-
global $
|
628 |
|
629 |
$lookup = (isset($_REQUEST['lookup'])?$_REQUEST['lookup']:NULL);
|
630 |
|
@@ -643,8 +698,9 @@ function fwp_feedfinder_page () {
|
|
643 |
endif;
|
644 |
?>
|
645 |
<div class="wrap">
|
646 |
-
<h2>Feed Finder:
|
647 |
-
<?php
|
|
|
648 |
$feeds = $f->find();
|
649 |
if (count($feeds) > 0):
|
650 |
foreach ($feeds as $key => $f):
|
@@ -653,17 +709,17 @@ function fwp_feedfinder_page () {
|
|
653 |
$feed_title = isset($rss->channel['title'])?$rss->channel['title']:$rss->channel['link'];
|
654 |
$feed_link = isset($rss->channel['link'])?$rss->channel['link']:'';
|
655 |
?>
|
656 |
-
<form action="link-manager.php?page
|
657 |
<fieldset style="clear: both">
|
658 |
-
<legend
|
659 |
|
660 |
<?php if ($link_id===0): ?>
|
661 |
-
<input type="hidden" name="feed_title" value="
|
662 |
-
<input type="hidden" name="feed_link" value="
|
663 |
<?php endif; ?>
|
664 |
|
665 |
-
<input type="hidden" name="link_id" value="
|
666 |
-
<input type="hidden" name="feed" value="
|
667 |
<input type="hidden" name="action" value="switchfeed" />
|
668 |
|
669 |
<div>
|
@@ -672,11 +728,11 @@ function fwp_feedfinder_page () {
|
|
672 |
<?php $item = $rss->items[0]; ?>
|
673 |
<h3>Sample Item</h3>
|
674 |
<ul>
|
675 |
-
<li><strong>Title:</strong> <a href="
|
676 |
-
<li><strong>Date:</strong>
|
677 |
</ul>
|
678 |
<div class="entry">
|
679 |
-
|
680 |
</div>
|
681 |
<?php else: ?>
|
682 |
<h3>No Items</h3>
|
@@ -687,10 +743,10 @@ function fwp_feedfinder_page () {
|
|
687 |
<div>
|
688 |
<h3>Feed Information</h3>
|
689 |
<ul>
|
690 |
-
<li><strong>Website:</strong> <a href="
|
691 |
-
<li><strong>Feed URI:</strong> <a href="
|
692 |
-
<li><strong>Encoding:</strong>
|
693 |
-
<li><strong>Description:</strong>
|
694 |
</ul>
|
695 |
<div class="submit"><input type="submit" name="Use" value="« Use this feed" /></div>
|
696 |
<div class="submit"><input type="submit" name="Cancel" value="« Cancel" /></div>
|
@@ -706,12 +762,12 @@ function fwp_feedfinder_page () {
|
|
706 |
?>
|
707 |
</div>
|
708 |
|
709 |
-
<form action="link-manager.php?page
|
710 |
<div class="wrap">
|
711 |
<h2>Use another feed</h2>
|
712 |
<div><label>Feed:</label>
|
713 |
<input type="text" name="lookup" value="URI" />
|
714 |
-
<input type="hidden" name="link_id" value="
|
715 |
<input type="hidden" name="action" value="feedfinder" /></div>
|
716 |
<div class="submit"><input type="submit" value="Use this feed »" /></div>
|
717 |
</div>
|
@@ -721,29 +777,19 @@ function fwp_feedfinder_page () {
|
|
721 |
}
|
722 |
|
723 |
function fwp_switchfeed_page () {
|
724 |
-
global $wpdb, $
|
725 |
|
726 |
check_admin_referer();
|
727 |
if (!isset($_REQUEST['Cancel'])):
|
728 |
-
if (
|
729 |
die (__("Cheatin' uh ?"));
|
730 |
elseif (isset($_REQUEST['link_id']) and ($_REQUEST['link_id']==0)):
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
SET
|
736 |
-
link_name = '".$wpdb->escape($_REQUEST['feed_title'])."',
|
737 |
-
link_url = '".$wpdb->escape($_REQUEST['feed_link'])."',
|
738 |
-
link_category = '".$wpdb->escape($cat_id)."',
|
739 |
-
link_rss = '".$wpdb->escape($_REQUEST['feed'])."'
|
740 |
-
");
|
741 |
-
|
742 |
-
if ($result): ?>
|
743 |
-
<div class="updated"><p><a href="<?=$_REQUEST['feed_link']?>"><?=wp_specialchars($_REQUEST['feed_title'])?></a>
|
744 |
-
has been added as a contributing site, using the newsfeed at <<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['feed'])?></a>>.</p></div>
|
745 |
<?php else: ?>
|
746 |
-
<div class="updated"><p>There was a problem adding the newsfeed. [SQL:
|
747 |
<?php endif;
|
748 |
elseif (isset($_REQUEST['link_id'])):
|
749 |
// Update link_rss
|
@@ -760,8 +806,8 @@ has been added as a contributing site, using the newsfeed at <<a href="<?=$_R
|
|
760 |
WHERE link_id = '".$wpdb->escape($_REQUEST['link_id'])."'
|
761 |
");
|
762 |
?>
|
763 |
-
<div class="updated"><p>Feed for <a href="
|
764 |
-
updated to <<a href="
|
765 |
<?php else: ?>
|
766 |
<div class="updated"><p>Nothing was changed.</p></div>
|
767 |
<?php endif;
|
@@ -771,7 +817,7 @@ updated to <<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['fe
|
|
771 |
}
|
772 |
|
773 |
function fwp_linkedit_page () {
|
774 |
-
global $wpdb
|
775 |
|
776 |
check_admin_referer(); // Make sure we arrived here from the Dashboard
|
777 |
|
@@ -791,7 +837,7 @@ function fwp_linkedit_page () {
|
|
791 |
'link/.*',
|
792 |
);
|
793 |
|
794 |
-
if (
|
795 |
die (__("Cheatin' uh ?"));
|
796 |
elseif (isset($_REQUEST['feedfinder'])) :
|
797 |
return fwp_feedfinder_page(); // re-route to Feed Finder page
|
@@ -993,9 +1039,9 @@ function fwp_linkedit_page () {
|
|
993 |
<div class="updated"><p>Syndicated feed settings updated.</p></div>
|
994 |
<?php endif; ?>
|
995 |
|
996 |
-
<form action="link-manager.php?page
|
997 |
<div class="wrap">
|
998 |
-
<input type="hidden" name="link_id" value="
|
999 |
<input type="hidden" name="action" value="linkedit" />
|
1000 |
<input type="hidden" name="save" value="link" />
|
1001 |
|
@@ -1004,9 +1050,9 @@ function fwp_linkedit_page () {
|
|
1004 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1005 |
<tr>
|
1006 |
<th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1007 |
-
<td width="60%"><a href="
|
1008 |
-
<a href="
|
1009 |
-
title="Check feed <
|
1010 |
</td>
|
1011 |
<td width="20%"><input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /></td>
|
1012 |
</tr>
|
@@ -1014,12 +1060,12 @@ title="Check feed <<?=wp_specialchars($link_rss_uri)?>> for validity"><img
|
|
1014 |
<th scope="row" width="20%"><?php _e('Link Name:') ?></th>
|
1015 |
<td width="60%"><input type="text" id="basics-name-edit" name="name"
|
1016 |
value="<?php echo $link_name; ?>" style="width: 95%" />
|
1017 |
-
<span id="basics-name-view"><strong
|
1018 |
</td>
|
1019 |
<td>
|
1020 |
<select id="basics-hardcode-name" onchange="flip_hardcode('name')" name="hardcode_name">
|
1021 |
-
<option value="no"
|
1022 |
-
<option value="yes"
|
1023 |
</select>
|
1024 |
</td>
|
1025 |
</tr>
|
@@ -1027,24 +1073,24 @@ value="<?php echo $link_name; ?>" style="width: 95%" />
|
|
1027 |
<th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1028 |
<td width="60%">
|
1029 |
<input id="basics-description-edit" type="text" name="description" value="<?php echo $link_description; ?>" style="width: 95%" />
|
1030 |
-
<span id="basics-description-view"><strong
|
1031 |
</td>
|
1032 |
<td>
|
1033 |
<select id="basics-hardcode-description" onchange="flip_hardcode('description')"
|
1034 |
name="hardcode_description">
|
1035 |
-
<option value="no"
|
1036 |
-
<option value="yes"
|
1037 |
</select></td>
|
1038 |
</tr>
|
1039 |
<tr>
|
1040 |
<th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1041 |
<td width="60%">
|
1042 |
<input id="basics-url-edit" type="text" name="linkurl" value="<?php echo $link_url; ?>" style="width: 95%;" />
|
1043 |
-
<a id="basics-url-view" href="
|
1044 |
<td>
|
1045 |
<select id="basics-hardcode-url" onchange="flip_hardcode('url')" name="hardcode_url">
|
1046 |
-
<option value="no"
|
1047 |
-
<option value="yes"
|
1048 |
</select></td></tr>
|
1049 |
|
1050 |
<tr>
|
@@ -1061,7 +1107,7 @@ name="hardcode_description">
|
|
1061 |
$holdem = (isset($meta['update/hold']) ? $meta['update/hold'] : 'scheduled');
|
1062 |
?>
|
1063 |
<select name="update_schedule">
|
1064 |
-
<option value="scheduled"
|
1065 |
echo " (";
|
1066 |
if (isset($meta['update/ttl']) and is_numeric($meta['update/ttl'])) :
|
1067 |
if (isset($meta['update/timed']) and $meta['update/timed']=='automatically') :
|
@@ -1079,8 +1125,8 @@ name="hardcode_description">
|
|
1079 |
endif;
|
1080 |
echo ")";
|
1081 |
?></option>
|
1082 |
-
<option value="next"
|
1083 |
-
<option value="ping"
|
1084 |
</select></tr>
|
1085 |
</table>
|
1086 |
</fieldset>
|
@@ -1098,49 +1144,44 @@ flip_hardcode('url');
|
|
1098 |
<fieldset>
|
1099 |
<legend>Syndicated Posts</legend>
|
1100 |
|
1101 |
-
|
1102 |
-
<legend>Categories</legend>
|
1103 |
-
<p style="font-size:smaller;font-style:bold;margin:0">Place all syndicated posts from this feed
|
1104 |
-
under...</p>
|
1105 |
-
<div style="height: 16em"><?php write_nested_categories($dogs); ?></div>
|
1106 |
-
</fieldset>
|
1107 |
|
1108 |
<table class="editform" width="80%" cellspacing="2" cellpadding="5">
|
1109 |
<tr><th width="20%" scope="row" style="vertical-align:top">Publication:</th>
|
1110 |
<td width="80%" style="vertical-align:top"><ul style="margin:0; list-style:none">
|
1111 |
<li><label><input type="radio" name="feed_post_status" value="site-default"
|
1112 |
-
|
1113 |
-
(currently: <strong
|
1114 |
<li><label><input type="radio" name="feed_post_status" value="publish"
|
1115 |
-
|
1116 |
<li><label><input type="radio" name="feed_post_status" value="private"
|
1117 |
-
|
1118 |
<li><label><input type="radio" name="feed_post_status" value="draft"
|
1119 |
-
|
1120 |
</ul></td>
|
1121 |
</tr>
|
1122 |
|
1123 |
<tr><th width="20%" scope="row" style="vertical-align:top">Comments:</th>
|
1124 |
<td width="80%"><ul style="margin:0; list-style:none">
|
1125 |
<li><label><input type="radio" name="feed_comment_status" value="site-default"
|
1126 |
-
|
1127 |
-
(currently: <strong
|
1128 |
<li><label><input type="radio" name="feed_comment_status" value="open"
|
1129 |
-
|
1130 |
<li><label><input type="radio" name="feed_comment_status" value="closed"
|
1131 |
-
|
1132 |
</ul></td>
|
1133 |
</tr>
|
1134 |
|
1135 |
<tr><th width="20%" scope="row" style="vertical-align:top">Trackback and Pingback:</th>
|
1136 |
<td width="80%"><ul style="margin:0; list-style:none">
|
1137 |
<li><label><input type="radio" name="feed_ping_status" value="site-default"
|
1138 |
-
|
1139 |
-
(currently: <strong
|
1140 |
<li><label><input type="radio" name="feed_ping_status" value="open"
|
1141 |
-
|
1142 |
<li><label><input type="radio" name="feed_ping_status" value="closed"
|
1143 |
-
|
1144 |
</ul></td>
|
1145 |
</tr>
|
1146 |
</table>
|
@@ -1156,22 +1197,22 @@ under...</p>
|
|
1156 |
<tr>
|
1157 |
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
1158 |
<td width="80%"><ul style="margin: 0; list-style:none">
|
1159 |
-
<li><label><input type="radio" name="unfamiliar_author" value="site-default"
|
1160 |
-
(currently <strong
|
1161 |
-
<li><label><input type="radio" name="unfamiliar_author" value="create"
|
1162 |
-
<li><label><input type="radio" name="unfamiliar_author" value="default"
|
1163 |
-
<li><label><input type="radio" name="unfamiliar_author" value="filter"
|
1164 |
</ul></td>
|
1165 |
</tr>
|
1166 |
|
1167 |
<tr>
|
1168 |
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
1169 |
<td width="80%"><ul style="margin: 0; list-style:none">
|
1170 |
-
<li><label><input type="radio" name="unfamiliar_category" value="site-default"
|
1171 |
-
(currently <strong
|
1172 |
-
<li><label><input type="radio" name="unfamiliar_category" value="create"
|
1173 |
-
<li><label><input type="radio" name="unfamiliar_category" value="default"
|
1174 |
-
<li><label><input type="radio" name="unfamiliar_category" value="filter"
|
1175 |
</ul></td>
|
1176 |
</tr></table>
|
1177 |
</fieldset>
|
@@ -1196,10 +1237,10 @@ under...</p>
|
|
1196 |
if (!preg_match("\007^((".implode(')|(', $special_settings)."))$\007i", $key)) :
|
1197 |
?>
|
1198 |
<tr style="vertical-align:top">
|
1199 |
-
<th width="30%" scope="row"><input type="hidden" name="notes[
|
1200 |
-
<input id="notes
|
1201 |
-
<td width="60%"><textarea rows="2" cols="40" id="notes
|
1202 |
-
<td width="10%"><select name="notes[
|
1203 |
<option value="update">save changes</option>
|
1204 |
<option value="delete">delete this setting</option>
|
1205 |
</select></td>
|
@@ -1210,9 +1251,9 @@ under...</p>
|
|
1210 |
endforeach;
|
1211 |
?>
|
1212 |
<tr>
|
1213 |
-
<th scope="row"><input type="text" size="10" name="notes[
|
1214 |
-
<td><textarea name="notes[
|
1215 |
-
<td><em>add new setting...</em><input type="hidden" name="notes[
|
1216 |
</tr>
|
1217 |
</table>
|
1218 |
</fieldset>
|
@@ -1228,14 +1269,14 @@ under...</p>
|
|
1228 |
}
|
1229 |
|
1230 |
function fwp_multidelete_page () {
|
1231 |
-
global $wpdb
|
1232 |
|
1233 |
check_admin_referer(); // Make sure the referers are kosher
|
1234 |
|
1235 |
$link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array());
|
1236 |
if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif;
|
1237 |
|
1238 |
-
if (
|
1239 |
die (__("Cheatin' uh ?"));
|
1240 |
elseif (isset($_POST['confirm']) and $_POST['confirm']=='Delete'):
|
1241 |
foreach ($_POST['link_action'] as $link_id => $what) :
|
@@ -1318,7 +1359,7 @@ function fwp_multidelete_page () {
|
|
1318 |
WHERE link_id IN (".implode(",",$link_ids).")
|
1319 |
");
|
1320 |
?>
|
1321 |
-
<form action="link-manager.php?page
|
1322 |
<div class="wrap">
|
1323 |
<input type="hidden" name="action" value="Unsubscribe" />
|
1324 |
<input type="hidden" name="confirm" value="Delete" />
|
@@ -1332,34 +1373,34 @@ function fwp_multidelete_page () {
|
|
1332 |
$meta = FeedWordPress::notes_to_settings($link->link_notes);
|
1333 |
?>
|
1334 |
<fieldset>
|
1335 |
-
<legend
|
1336 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1337 |
<tr><th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1338 |
-
<td width="80%"><a href="
|
1339 |
<tr><th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1340 |
-
<td width="80%"
|
1341 |
<tr><th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1342 |
-
<td width="80%"><a href="
|
1343 |
<tr style="vertical-align:top"><th width="20%" scope="row">Subscription <?php _e('Options') ?>:</th>
|
1344 |
<td width="80%"><ul style="margin:0; padding: 0; list-style: none">
|
1345 |
-
<li><input type="radio" id="hide
|
1346 |
-
name="link_action[
|
1347 |
-
<label for="hide
|
1348 |
syndicated link<br/><span style="font-size:smaller">(Keep the feed information
|
1349 |
and all the posts from this feed in the database, but don't syndicate any
|
1350 |
new posts from the feed.)</span></label></li>
|
1351 |
-
<li><input type="radio" id="nuke
|
1352 |
-
name="link_action[
|
1353 |
-
<label for="nuke
|
1354 |
posts that were syndicated from it</label></li>
|
1355 |
-
<li><input type="radio" id="delete
|
1356 |
-
name="link_action[
|
1357 |
-
<label for="delete
|
1358 |
<em>keep</em> posts that were syndicated from it (as if they were authored
|
1359 |
locally).</label></li>
|
1360 |
-
<li><input type="radio" id="nothing
|
1361 |
-
name="link_action[
|
1362 |
-
<label for="nothing
|
1363 |
my mind.</label></li>
|
1364 |
</ul>
|
1365 |
</table>
|
@@ -1479,7 +1520,7 @@ class FeedWordPress {
|
|
1479 |
# the function `get_feed_meta($key)` if this plugin is activated.
|
1480 |
|
1481 |
function FeedWordPress () {
|
1482 |
-
$result =
|
1483 |
|
1484 |
$feeds = array ();
|
1485 |
if ($result): foreach ($result as $link):
|
@@ -1601,7 +1642,7 @@ class FeedWordPress {
|
|
1601 |
|
1602 |
$uri = trim($uri);
|
1603 |
|
1604 |
-
if (
|
1605 |
return NULL;
|
1606 |
endif;
|
1607 |
|
@@ -1636,14 +1677,14 @@ class FeedWordPress {
|
|
1636 |
endif;
|
1637 |
|
1638 |
if ($pinged_that and $timely) :
|
1639 |
-
do_action('feedwordpress_check_feed',
|
1640 |
$added = $this->feed2wp($wpdb, $feed);
|
1641 |
if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
|
1642 |
if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
|
1643 |
endif;
|
1644 |
endforeach;
|
1645 |
|
1646 |
-
do_action('feedwordpress_update_complete',
|
1647 |
fwp_release_pings(); // Now that we're done, send the one ping
|
1648 |
|
1649 |
return $delta;
|
@@ -1905,7 +1946,7 @@ class FeedWordPress {
|
|
1905 |
$channel = $rss->channel;
|
1906 |
|
1907 |
$post = array();
|
1908 |
-
|
1909 |
// This is ugly as all hell. I'd like to use apply_filters()'s
|
1910 |
// alleged support for a variable argument count, but this seems
|
1911 |
// to have been broken in WordPress 1.5. It'll be fixed somehow
|
@@ -2051,7 +2092,7 @@ class FeedWordPress {
|
|
2051 |
elseif (isset($item['pubdate'])): // RSS 2.0
|
2052 |
$post['epoch']['issued'] = strtotime($item['pubdate']);
|
2053 |
else:
|
2054 |
-
$post['epoch']['issued'] =
|
2055 |
endif;
|
2056 |
|
2057 |
# And again, for the created date
|
@@ -2067,13 +2108,15 @@ class FeedWordPress {
|
|
2067 |
$post['epoch']['modified'] = @parse_w3cdtf($item['modified']);
|
2068 |
elseif (isset($item['updated'])): // Atom 1.0
|
2069 |
$post['epoch']['modified'] = @parse_w3cdtf($item['updated']);
|
2070 |
-
|
2071 |
$post['epoch']['modified'] = $post['epoch']['issued'];
|
|
|
|
|
2072 |
endif;
|
2073 |
|
2074 |
-
$post['post_date'] = date('Y-m-d H:i:s', $post['epoch']['issued']);
|
2075 |
$post['post_modified'] = date('Y-m-d H:i:s', $post['epoch']['modified']);
|
2076 |
-
$post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $post['epoch']['issued']);
|
2077 |
$post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $post['epoch']['modified']);
|
2078 |
|
2079 |
# Use feed-level preferences or the global default.
|
@@ -2119,7 +2162,9 @@ class FeedWordPress {
|
|
2119 |
if ($fc) : $post['named']['preset/category'] = explode("\n", $fc);
|
2120 |
else : $post['named']['preset/category'] = array();
|
2121 |
endif;
|
2122 |
-
|
|
|
|
|
2123 |
|
2124 |
// Now add categories from the post, if we have 'em
|
2125 |
$post['named']['category'] = array();
|
@@ -2573,55 +2618,151 @@ class FeedWordPress {
|
|
2573 |
return $ret;
|
2574 |
} // function FeedWordPress::on_unfamiliar()
|
2575 |
|
2576 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2577 |
global $wpdb;
|
2578 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2579 |
$cat_id = get_settings('feedwordpress_cat_id');
|
2580 |
|
2581 |
// If we don't yet *have* the category, we'll have to create it
|
2582 |
if ($cat_id === false) {
|
2583 |
$cat = $wpdb->escape(DEFAULT_SYNDICATION_CATEGORY);
|
2584 |
-
|
2585 |
-
// Look for something with the right name...
|
2586 |
-
$cat_id = $wpdb->get_var("
|
2587 |
-
SELECT cat_id FROM $wpdb->linkcategories
|
2588 |
-
WHERE cat_name='$cat'
|
2589 |
-
");
|
2590 |
|
|
|
|
|
|
|
2591 |
// If you still can't find anything, make it for yourself.
|
2592 |
if (!$cat_id) {
|
2593 |
-
$
|
2594 |
-
INSERT INTO $wpdb->linkcategories
|
2595 |
-
SET
|
2596 |
-
cat_id = 0,
|
2597 |
-
cat_name='$cat',
|
2598 |
-
show_images='N',
|
2599 |
-
show_description='N',
|
2600 |
-
show_rating='N',
|
2601 |
-
show_updated='N',
|
2602 |
-
sort_order='name'
|
2603 |
-
");
|
2604 |
-
$cat_id = $wpdb->insert_id;
|
2605 |
}
|
2606 |
-
|
2607 |
update_option('feedwordpress_cat_id', $cat_id);
|
2608 |
}
|
2609 |
return $cat_id;
|
2610 |
}
|
2611 |
|
2612 |
function link_category () {
|
2613 |
-
global $wpdb;
|
2614 |
|
2615 |
$cat_id = FeedWordPress::link_category_id();
|
2616 |
|
2617 |
// Get the ID# for the category name...
|
2618 |
-
$
|
2619 |
-
|
2620 |
-
|
2621 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2622 |
return $cat_name;
|
2623 |
}
|
2624 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2625 |
function upgrade_database ($from = NULL) {
|
2626 |
global $wpdb;
|
2627 |
|
@@ -2629,7 +2770,7 @@ class FeedWordPress {
|
|
2629 |
|
2630 |
switch ($from) :
|
2631 |
case 0.96: // account for changes to syndication custom values and guid
|
2632 |
-
echo "<p>Upgrading database from {$from} to
|
2633 |
|
2634 |
$cat_id = FeedWordPress::link_category_id();
|
2635 |
|
@@ -2801,7 +2942,7 @@ class FeedFinder {
|
|
2801 |
$client->rawheaders['Connection'] = 'close';
|
2802 |
$client->accept = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
|
2803 |
$client->agent = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
|
2804 |
-
$client->read_timeout =
|
2805 |
|
2806 |
// Fetch the HTML or feed
|
2807 |
@$client->fetch($this->uri);
|
@@ -2896,7 +3037,7 @@ class Relative_URI
|
|
2896 |
$parts = Relative_URI::_parse_url($url);
|
2897 |
|
2898 |
$uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
|
2899 |
-
$uri_parts['query'] = $parts['query'];
|
2900 |
|
2901 |
// if path is empty, and scheme, host, and query are undefined,
|
2902 |
// the URL is referring the base URL
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
+
Version: 0.981
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
10 |
+
Last modified: 2007-02-17 4:23pm EST
|
11 |
*/
|
12 |
|
13 |
# This uses code derived from:
|
27 |
|
28 |
# -- Don't change these unless you know what you're doing...
|
29 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/');
|
30 |
+
define ('FEEDWORDPRESS_VERSION', '0.981');
|
31 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
32 |
|
33 |
define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
|
36 |
define ('FEEDVALIDATOR_URI', 'http://feedvalidator.org/check.cgi');
|
37 |
|
38 |
// Note that the rss-functions.php that comes prepackaged with WordPress is
|
39 |
+
// old & busted. For the new hotness, drop a copy of rss.php from
|
40 |
+
// this archive into wp-includes/rss.php
|
|
|
41 |
|
42 |
+
if (is_readable(ABSPATH . WPINC . '/rss.php')) :
|
43 |
+
require_once (ABSPATH . WPINC . '/rss.php');
|
44 |
+
else :
|
45 |
+
require_once (ABSPATH . WPINC . '/rss-functions.php');
|
46 |
+
endif;
|
47 |
+
|
48 |
+
if (isset($wp_db_version) and $wp_db_version >= 3308) :
|
49 |
require_once (ABSPATH . WPINC . '/registration-functions.php');
|
50 |
+
require_once (ABSPATH . 'wp-admin/admin-db.php');
|
51 |
endif;
|
52 |
|
53 |
// Is this being loaded from within WordPress 1.5 or later?
|
54 |
if (isset($wp_version) and $wp_version >= 1.5):
|
55 |
|
56 |
+
if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
# Syndicated items are generally received in output-ready (X)HTML and
|
59 |
# should not be folded, crumpled, mutilated, or spindled by WordPress
|
96 |
else :
|
97 |
# Hook in the menus, which will just point to the upgrade interface
|
98 |
add_action('admin_menu', 'fwp_add_pages');
|
99 |
+
endif; // if (!FeedWordPress::needs_upgrade())
|
100 |
endif;
|
101 |
|
102 |
################################################################################
|
136 |
: implode(' and ', $mesg)));
|
137 |
}
|
138 |
|
139 |
+
################################################################################
|
140 |
+
## LEGACY API: Replicate or mock up functions for legacy support purposes ######
|
141 |
+
################################################################################
|
142 |
+
|
143 |
+
if (!function_exists('current_user_can')) {
|
144 |
+
$legacy_capability_hack = true;
|
145 |
+
function current_user_can ($task) {
|
146 |
+
global $user_level;
|
147 |
+
|
148 |
+
$can = false;
|
149 |
+
|
150 |
+
// This is **not** a full replacement for current_user_can. It
|
151 |
+
// is only for checking the capabilities we care about via the
|
152 |
+
// WordPress 1.5 user levels.
|
153 |
+
switch ($task) {
|
154 |
+
case 'manage_options':
|
155 |
+
$can = ($user_level >= 6);
|
156 |
+
break;
|
157 |
+
case 'manage_links':
|
158 |
+
$can = ($user_level >= 5);
|
159 |
+
break;
|
160 |
+
} /* switch */
|
161 |
+
return $can;
|
162 |
+
}
|
163 |
+
} else {
|
164 |
+
$legacy_capability_hack = false;
|
165 |
+
}
|
166 |
+
|
167 |
################################################################################
|
168 |
## TEMPLATE API: functions to make your templates syndication-aware ############
|
169 |
################################################################################
|
277 |
<h2>Upgrade FeedWordPress</h2>
|
278 |
|
279 |
<p>It appears that you have installed FeedWordPress
|
280 |
+
<?php echo FEEDWORDPRESS_VERSION; ?> as an upgrade to an existing installation of
|
281 |
FeedWordPress. That's no problem, but you will need to take a minute out first
|
282 |
+
to upgrade your database: some necessary changes in how the software keeps
|
283 |
track of posts and feeds will cause problems such as duplicate posts and broken
|
284 |
templates if we were to continue without the upgrade.</p>
|
285 |
|
303 |
################################################################################
|
304 |
|
305 |
function fwp_add_pages () {
|
306 |
+
global $legacy_capability_hack;
|
307 |
+
|
308 |
+
if ($legacy_capability_hack) :
|
309 |
+
// old & busted: numeric user levels
|
310 |
+
$manage_links = 5;
|
311 |
+
$manage_options = 6;
|
312 |
+
else :
|
313 |
+
// new hotness: named capabilities
|
314 |
+
$manage_links = 'manage_links';
|
315 |
+
$manage_options = 'manage_options';
|
316 |
+
endif;
|
317 |
+
|
318 |
+
add_submenu_page('link-manager.php', 'Syndicated Sites', 'Syndicated', $manage_links, basename(__FILE__), 'fwp_syndication_manage_page');
|
319 |
+
add_options_page('Syndication Options', 'Syndication', $manage_options, basename(__FILE__), 'fwp_syndication_options_page');
|
320 |
} // function fwp_add_pages () */
|
321 |
|
322 |
function fwp_syndication_options_page () {
|
323 |
+
global $wpdb, $wp_db_version;
|
324 |
|
325 |
+
if (FeedWordPress::needs_upgrade()) :
|
326 |
fwp_upgrade_page();
|
327 |
return;
|
328 |
endif;
|
331 |
if (isset($_POST['action']) and $_POST['action']==$caption):
|
332 |
check_admin_referer();
|
333 |
|
334 |
+
if (!current_user_can('manage_options')):
|
335 |
die (__("Cheatin' uh ?"));
|
336 |
else:
|
337 |
update_option('feedwordpress_rpc_secret', $_REQUEST['rpc_secret']);
|
419 |
if (is_string($uc) and array_key_exists($uc, $unfamiliar_category)) :
|
420 |
$unfamiliar_category[$uc] = ' checked="checked"';
|
421 |
endif;
|
422 |
+
|
423 |
+
if (isset($wp_db_version) and $wp_db_version >= 4772) :
|
424 |
+
$results = get_categories('type=link');
|
425 |
+
else :
|
426 |
+
$results = $wpdb->get_results("SELECT cat_id, cat_name, auto_toggle FROM $wpdb->linkcategories ORDER BY cat_id");
|
427 |
+
endif;
|
428 |
|
429 |
$cats = get_settings('feedwordpress_syndication_cats');
|
430 |
$dogs = get_nested_categories(-1, 0);
|
451 |
<td width="67%"><?php
|
452 |
echo "\n<select name=\"syndication_category\" size=\"1\">";
|
453 |
foreach ($results as $row) {
|
454 |
+
if (!isset($row->cat_id)) { $row->cat_id = $row->cat_ID; }
|
455 |
+
|
456 |
echo "\n\t<option value=\"$row->cat_id\"";
|
457 |
if ($row->cat_id == $cat_id)
|
458 |
echo " selected='selected'";
|
467 |
|
468 |
<tr><th width="33%" scope="row" style="vertical-align:top">Update live from feed:</th>
|
469 |
<td width="67%"><ul style="margin:0;list-style:none">
|
470 |
+
<li><input type="checkbox" name="hardcode_name" value="no"<?php echo (($hardcode_name=='yes')?'':' checked="checked"');?>/> Contributor name (feed title)</li>
|
471 |
+
<li><input type="checkbox" name="hardcode_description" value="no"<?php echo (($hardcode_description=='yes')?'':' checked="checked"');?>/> Contributor description (feed tagline)</li>
|
472 |
+
<li><input type="checkbox" name="hardcode_url" value="no"<?php echo (($hardcode_url=='yes')?'':' checked="checked"');?>/> Homepage (feed link)</li>
|
473 |
</ul></td></tr>
|
474 |
</table>
|
475 |
</fieldset>
|
477 |
<fieldset class="options">
|
478 |
<legend>Syndicated Posts</legend>
|
479 |
|
480 |
+
<?php fwp_category_box($dogs, '<em>all syndicated posts</em>'); ?>
|
|
|
|
|
|
|
|
|
|
|
481 |
|
482 |
<table class="editform" width="75%" cellspacing="2" cellpadding="5">
|
483 |
<tr style="vertical-align: top"><th width="33%" scope="row">Publication:</th>
|
484 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
485 |
+
<li><label><input type="radio" name="post_status" value="publish"<?php echo ($post_status=='publish')?' checked="checked"':''; ?> /> Publish syndicated posts immediately</label></li>
|
486 |
+
<li><label><input type="radio" name="post_status" value="draft"<?php echo ($post_status=='draft')?' checked="checked"':''; ?> /> Hold syndicated posts as drafts</label></li>
|
487 |
+
<li><label><input type="radio" name="post_status" value="private"<?php echo ($post_status=='private')?' checked="checked"':''; ?> /> Hold syndicated posts as private posts</label></li>
|
488 |
</ul></td></tr>
|
489 |
|
490 |
<tr style="vertical-align: top"><th width="33%" scope="row">Comments:</th>
|
491 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
492 |
+
<li><label><input type="radio" name="comment_status" value="open"<?php echo ($comment_status=='open')?' checked="checked"':''; ?> /> Allow comments on syndicated posts</label></li>
|
493 |
+
<li><label><input type="radio" name="comment_status" value="closed"<?php echo ($comment_status!='open')?' checked="checked"':''; ?> /> Don't allow comments on syndicated posts</label></li>
|
494 |
</ul></td></tr>
|
495 |
|
496 |
<tr style="vertical-align: top"><th width="33%" scope="row">Trackback and Pingback:</th>
|
497 |
<td width="67%"><ul style="margin:0; padding: 0; list-style:none">
|
498 |
+
<li><label><input type="radio" name="ping_status" value="open"<?php echo ($ping_status=='open')?' checked="checked"':''; ?> /> Accept pings on syndicated posts</label></li>
|
499 |
+
<li><label><input type="radio" name="ping_status" value="closed"<?php echo ($ping_status!='open')?' checked="checked"':''; ?> /> Don't accept pings on syndicated posts</label></li>
|
500 |
</ul></td></tr>
|
501 |
|
502 |
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
503 |
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
504 |
+
<li><label><input type="radio" name="unfamiliar_author" value="create"<?php echo $unfamiliar_author['create']; ?>/> create a new author account</label></li>
|
505 |
+
<li><label><input type="radio" name="unfamiliar_author" value="default"<?php echo $unfamiliar_author['default']; ?> /> attribute the post to the default author</label></li>
|
506 |
+
<li><label><input type="radio" name="unfamiliar_author" value="filter"<?php echo $unfamiliar_author['filter']; ?> /> don't syndicate the post</label></li>
|
507 |
</ul></td></tr>
|
508 |
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
509 |
<td width="67%"><ul style="margin: 0; padding:0; list-style:none">
|
510 |
+
<li><label><input type="radio" name="unfamiliar_category" value="create"<?php echo $unfamiliar_category['create']; ?>/> create any categories the post is in</label></li>
|
511 |
+
<li><label><input type="radio" name="unfamiliar_category" value="default"<?php echo $unfamiliar_category['default']; ?>/> don't create new categories</li>
|
512 |
+
<li><label><input type="radio" name="unfamiliar_category" value="filter"<?php echo $unfamiliar_category['filter']; ?>/> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
|
513 |
</ul></td></tr>
|
514 |
|
515 |
<tr style="vertical-align: top"><th width="33%" scope="row">Permalinks point to:</th>
|
516 |
<td width="67%"><select name="munge_permalink" size="1">
|
517 |
+
<option value="yes"<?php echo ($munge_permalink=='yes')?' selected="selected"':''; ?>>original website</option>
|
518 |
+
<option value="no"<?php echo ($munge_permalink=='no')?' selected="selected"':''; ?>>this website</option>
|
519 |
</select></td></tr>
|
520 |
</table>
|
521 |
+
<div class="submit"><input type="submit" name="action" value="<?php echo $caption; ?>" /></div>
|
522 |
</fieldset>
|
523 |
|
524 |
<fieldset class="options">
|
526 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
527 |
<tr>
|
528 |
<th width="33%" scope="row">XML-RPC update secret word:</th>
|
529 |
+
<td width="67%"><input id="rpc_secret" name="rpc_secret" value="<?php echo $rpc_secret; ?>" />
|
530 |
</td>
|
531 |
</tr>
|
532 |
<tr>
|
533 |
<th scope="row">Write update notices to PHP logs:</th>
|
534 |
<td><select name="update_logging" size="1">
|
535 |
+
<option value="yes"<?php echo (($update_logging=='yes')?' selected="selected"':''); ?>>yes</option>
|
536 |
+
<option value="no"<?php echo (($update_logging!='yes')?' selected="selected"':''); ?>>no</option>
|
537 |
</select></td>
|
538 |
</tr>
|
539 |
</table>
|
540 |
+
<div class="submit"><input type="submit" name="action" value="<?php echo $caption; ?>" /></div>
|
541 |
</fieldset>
|
542 |
</form>
|
543 |
</div>
|
544 |
<?php
|
545 |
}
|
546 |
|
547 |
+
function fwp_category_box ($checked, $object) {
|
548 |
+
global $wp_db_version;
|
549 |
+
|
550 |
+
if (isset($wp_db_version) and $wp_db_version >= 3308) : // WordPress 2.x
|
551 |
+
?>
|
552 |
+
<div id="poststuff">
|
553 |
+
|
554 |
+
<div id="moremeta">
|
555 |
+
<div id="grabit" class="dbx-group">
|
556 |
+
<fieldset id="categorydiv" class="dbx-box">
|
557 |
+
<h3 class="dbx-handle"><?php _e('Categories') ?></h3>
|
558 |
+
<div class="dbx-content">
|
559 |
+
<p style="font-size:smaller;font-style:bold;margin:0">Place <?php print $object; ?> under...</p>
|
560 |
+
<p id="jaxcat"></p>
|
561 |
+
<ul id="categorychecklist"><?php write_nested_categories($checked); ?></ul></div>
|
562 |
+
</fieldset>
|
563 |
+
</div>
|
564 |
+
</div>
|
565 |
+
</div>
|
566 |
+
<?php
|
567 |
+
else : // WordPress 1.5
|
568 |
+
?>
|
569 |
+
<fieldset id="categorydiv" style="width: 20%; margin-right: 2em">
|
570 |
+
<legend><?php _e('Categories') ?></legend>
|
571 |
+
<p style="font-size:smaller;font-style:bold;margin:0">Place <?php print $object; ?> under...</p>
|
572 |
+
<div style="height: 20em"><?php write_nested_categories($checked); ?></div>
|
573 |
+
</fieldset>
|
574 |
+
<?php
|
575 |
+
endif;
|
576 |
+
}
|
577 |
+
|
578 |
function fwp_syndication_manage_page () {
|
579 |
+
global $wpdb;
|
580 |
|
581 |
+
if (FeedWordPress::needs_upgrade()) :
|
582 |
fwp_upgrade_page();
|
583 |
return;
|
584 |
endif;
|
596 |
if ($cont):
|
597 |
?>
|
598 |
<?php
|
599 |
+
$links = FeedWordPress::syndicated_links();
|
600 |
?>
|
601 |
<div class="wrap">
|
602 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
603 |
<h2>Syndicate a new site:</h2>
|
604 |
<div>
|
605 |
<label for="add-uri">Website or newsfeed:</label>
|
610 |
</form>
|
611 |
</div>
|
612 |
|
613 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
614 |
<div class="wrap">
|
615 |
<h2>Syndicated Sites</h2>
|
616 |
<?php $alt_row = true;
|
625 |
|
626 |
<?php foreach ($links as $link):
|
627 |
$alt_row = !$alt_row; ?>
|
628 |
+
<tr<?php echo ($alt_row?' class="alternate"':''); ?>>
|
629 |
+
<td><a href="<?php echo wp_specialchars($link->link_url); ?>"><?php echo wp_specialchars($link->link_name); ?></a></td>
|
630 |
<?php
|
631 |
if (strlen($link->link_rss) > 0):
|
632 |
$caption='Switch Feed';
|
641 |
if (strlen($display_uri) > 32) : $display_uri = substr($display_uri, 0, 32).'…'; endif;
|
642 |
?>
|
643 |
<td>
|
644 |
+
<strong><a href="<?php echo $link->link_rss; ?>"><?php echo wp_specialchars($display_uri); ?></a></strong></td>
|
645 |
<?php
|
646 |
else:
|
647 |
$caption='Find Feed';
|
650 |
feed assigned</strong></p></td>
|
651 |
<?php
|
652 |
endif;
|
|
|
|
|
653 |
?>
|
654 |
+
<td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=linkedit" class="edit"><?php _e('Edit')?></a></td>
|
655 |
+
<td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=feedfinder" class="edit"><?php echo $caption; ?></a></td>
|
656 |
+
<td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=Unsubscribe" class="delete"><?php _e('Unsubscribe'); ?></a></td>
|
657 |
+
<td><input type="checkbox" name="link_ids[]" value="<?php echo $link->link_id; ?>" /></td>
|
658 |
<?php
|
|
|
|
|
|
|
659 |
echo "\n\t</tr>";
|
660 |
endforeach;
|
661 |
else:
|
679 |
}
|
680 |
|
681 |
function fwp_feedfinder_page () {
|
682 |
+
global $wpdb;
|
683 |
|
684 |
$lookup = (isset($_REQUEST['lookup'])?$_REQUEST['lookup']:NULL);
|
685 |
|
698 |
endif;
|
699 |
?>
|
700 |
<div class="wrap">
|
701 |
+
<h2>Feed Finder: <?php echo $name; ?></h2>
|
702 |
+
<?php
|
703 |
+
$f =& new FeedFinder($lookup);
|
704 |
$feeds = $f->find();
|
705 |
if (count($feeds) > 0):
|
706 |
foreach ($feeds as $key => $f):
|
709 |
$feed_title = isset($rss->channel['title'])?$rss->channel['title']:$rss->channel['link'];
|
710 |
$feed_link = isset($rss->channel['link'])?$rss->channel['link']:'';
|
711 |
?>
|
712 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
713 |
<fieldset style="clear: both">
|
714 |
+
<legend><?php echo $rss->feed_type; ?> <?php echo $rss->feed_version; ?> feed</legend>
|
715 |
|
716 |
<?php if ($link_id===0): ?>
|
717 |
+
<input type="hidden" name="feed_title" value="<?php echo wp_specialchars($feed_title); ?>" />
|
718 |
+
<input type="hidden" name="feed_link" value="<?php echo wp_specialchars($feed_link); ?>" />
|
719 |
<?php endif; ?>
|
720 |
|
721 |
+
<input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
|
722 |
+
<input type="hidden" name="feed" value="<?php echo wp_specialchars($f); ?>" />
|
723 |
<input type="hidden" name="action" value="switchfeed" />
|
724 |
|
725 |
<div>
|
728 |
<?php $item = $rss->items[0]; ?>
|
729 |
<h3>Sample Item</h3>
|
730 |
<ul>
|
731 |
+
<li><strong>Title:</strong> <a href="<?php echo $item['link']; ?>"><?php echo $item['title']; ?></a></li>
|
732 |
+
<li><strong>Date:</strong> <?php echo isset($item['date_timestamp']) ? date('d-M-y g:i:s a', $item['date_timestamp']) : 'unknown'; ?></li>
|
733 |
</ul>
|
734 |
<div class="entry">
|
735 |
+
<?php echo (isset($item['content']['encoded'])?$item['content']['encoded']:$item['description']); ?>
|
736 |
</div>
|
737 |
<?php else: ?>
|
738 |
<h3>No Items</h3>
|
743 |
<div>
|
744 |
<h3>Feed Information</h3>
|
745 |
<ul>
|
746 |
+
<li><strong>Website:</strong> <a href="<?php echo $feed_link; ?>"><?php echo is_null($feed_title)?'<em>Unknown</em>':$feed_title; ?></a></li>
|
747 |
+
<li><strong>Feed URI:</strong> <a href="<?php echo wp_specialchars($f); ?>"><?php echo wp_specialchars($f); ?></a> <a title="Check feed <<?php echo wp_specialchars($f); ?>> for validity" href="http://feedvalidator.org/check.cgi?url=<?php echo urlencode($f); ?>"><img src="../wp-images/smilies/icon_arrow.gif" alt="(→)" /></a></li>
|
748 |
+
<li><strong>Encoding:</strong> <?php echo isset($rss->encoding)?wp_specialchars($rss->encoding):"<em>Unknown</em>"; ?></li>
|
749 |
+
<li><strong>Description:</strong> <?php echo isset($rss->channel['description'])?wp_specialchars($rss->channel['description']):"<em>Unknown</em>"; ?></li>
|
750 |
</ul>
|
751 |
<div class="submit"><input type="submit" name="Use" value="« Use this feed" /></div>
|
752 |
<div class="submit"><input type="submit" name="Cancel" value="« Cancel" /></div>
|
762 |
?>
|
763 |
</div>
|
764 |
|
765 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
766 |
<div class="wrap">
|
767 |
<h2>Use another feed</h2>
|
768 |
<div><label>Feed:</label>
|
769 |
<input type="text" name="lookup" value="URI" />
|
770 |
+
<input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
|
771 |
<input type="hidden" name="action" value="feedfinder" /></div>
|
772 |
<div class="submit"><input type="submit" value="Use this feed »" /></div>
|
773 |
</div>
|
777 |
}
|
778 |
|
779 |
function fwp_switchfeed_page () {
|
780 |
+
global $wpdb, $wp_db_version;
|
781 |
|
782 |
check_admin_referer();
|
783 |
if (!isset($_REQUEST['Cancel'])):
|
784 |
+
if (!current_user_can('manage_links')):
|
785 |
die (__("Cheatin' uh ?"));
|
786 |
elseif (isset($_REQUEST['link_id']) and ($_REQUEST['link_id']==0)):
|
787 |
+
$link_id = FeedWordPress::syndicate_link($_REQUEST['feed_title'], $_REQUEST['feed_link'], $_REQUEST['feed']);
|
788 |
+
if ($link_id): ?>
|
789 |
+
<div class="updated"><p><a href="<?php echo $_REQUEST['feed_link']; ?>"><?php echo wp_specialchars($_REQUEST['feed_title']); ?></a>
|
790 |
+
has been added as a contributing site, using the newsfeed at <<a href="<?php echo $_REQUEST['feed']; ?>"><?php echo wp_specialchars($_REQUEST['feed']); ?></a>>.</p></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
791 |
<?php else: ?>
|
792 |
+
<div class="updated"><p>There was a problem adding the newsfeed. [SQL: <?php echo wp_specialchars(mysql_error()); ?>]</p></div>
|
793 |
<?php endif;
|
794 |
elseif (isset($_REQUEST['link_id'])):
|
795 |
// Update link_rss
|
806 |
WHERE link_id = '".$wpdb->escape($_REQUEST['link_id'])."'
|
807 |
");
|
808 |
?>
|
809 |
+
<div class="updated"><p>Feed for <a href="<?php echo $result->link_url; ?>"><?php echo wp_specialchars($result->link_name); ?></a>
|
810 |
+
updated to <<a href="<?php echo $_REQUEST['feed']; ?>"><?php echo wp_specialchars($_REQUEST['feed']); ?></a>>.</p></div>
|
811 |
<?php else: ?>
|
812 |
<div class="updated"><p>Nothing was changed.</p></div>
|
813 |
<?php endif;
|
817 |
}
|
818 |
|
819 |
function fwp_linkedit_page () {
|
820 |
+
global $wpdb;
|
821 |
|
822 |
check_admin_referer(); // Make sure we arrived here from the Dashboard
|
823 |
|
837 |
'link/.*',
|
838 |
);
|
839 |
|
840 |
+
if (!current_user_can('manage_links')) :
|
841 |
die (__("Cheatin' uh ?"));
|
842 |
elseif (isset($_REQUEST['feedfinder'])) :
|
843 |
return fwp_feedfinder_page(); // re-route to Feed Finder page
|
1039 |
<div class="updated"><p>Syndicated feed settings updated.</p></div>
|
1040 |
<?php endif; ?>
|
1041 |
|
1042 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
1043 |
<div class="wrap">
|
1044 |
+
<input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
|
1045 |
<input type="hidden" name="action" value="linkedit" />
|
1046 |
<input type="hidden" name="save" value="link" />
|
1047 |
|
1050 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1051 |
<tr>
|
1052 |
<th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1053 |
+
<td width="60%"><a href="<?php echo wp_specialchars($link_rss_uri); ?>"><?php echo $link_rss_uri; ?></a>
|
1054 |
+
<a href="<?php echo FEEDVALIDATOR_URI; ?>?url=<?php echo urlencode($link_rss_uri); ?>"
|
1055 |
+
title="Check feed <<?php echo wp_specialchars($link_rss_uri); ?>> for validity"><img src="../wp-images/smilies/icon_arrow.gif" alt="→" /></a>
|
1056 |
</td>
|
1057 |
<td width="20%"><input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /></td>
|
1058 |
</tr>
|
1060 |
<th scope="row" width="20%"><?php _e('Link Name:') ?></th>
|
1061 |
<td width="60%"><input type="text" id="basics-name-edit" name="name"
|
1062 |
value="<?php echo $link_name; ?>" style="width: 95%" />
|
1063 |
+
<span id="basics-name-view"><strong><?php echo $link_name; ?></strong></span>
|
1064 |
</td>
|
1065 |
<td>
|
1066 |
<select id="basics-hardcode-name" onchange="flip_hardcode('name')" name="hardcode_name">
|
1067 |
+
<option value="no" <?php echo FeedWordPress::hardcode('name', $meta)?'':'selected="selected"'; ?>>update automatically</option>
|
1068 |
+
<option value="yes" <?php echo FeedWordPress::hardcode('name', $meta)?'selected="selected"':''; ?>>edit manually</option>
|
1069 |
</select>
|
1070 |
</td>
|
1071 |
</tr>
|
1073 |
<th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1074 |
<td width="60%">
|
1075 |
<input id="basics-description-edit" type="text" name="description" value="<?php echo $link_description; ?>" style="width: 95%" />
|
1076 |
+
<span id="basics-description-view"><strong><?php echo $link_description; ?></strong></span>
|
1077 |
</td>
|
1078 |
<td>
|
1079 |
<select id="basics-hardcode-description" onchange="flip_hardcode('description')"
|
1080 |
name="hardcode_description">
|
1081 |
+
<option value="no" <?php echo FeedWordPress::hardcode('description', $meta)?'':'selected="selected"'; ?>>update automatically</option>
|
1082 |
+
<option value="yes" <?php echo FeedWordPress::hardcode('description', $meta)?'selected="selected"':''; ?>>edit manually</option>
|
1083 |
</select></td>
|
1084 |
</tr>
|
1085 |
<tr>
|
1086 |
<th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1087 |
<td width="60%">
|
1088 |
<input id="basics-url-edit" type="text" name="linkurl" value="<?php echo $link_url; ?>" style="width: 95%;" />
|
1089 |
+
<a id="basics-url-view" href="<?php echo $link_url; ?>"><?php echo $link_url; ?></a></td>
|
1090 |
<td>
|
1091 |
<select id="basics-hardcode-url" onchange="flip_hardcode('url')" name="hardcode_url">
|
1092 |
+
<option value="no"<?php echo FeedWordPress::hardcode('url', $meta)?'':' selected="selected"'; ?>>update live from feed</option>
|
1093 |
+
<option value="yes"<?php echo FeedWordPress::hardcode('url', $meta)?' selected="selected"':''; ?>>edit manually</option>
|
1094 |
</select></td></tr>
|
1095 |
|
1096 |
<tr>
|
1107 |
$holdem = (isset($meta['update/hold']) ? $meta['update/hold'] : 'scheduled');
|
1108 |
?>
|
1109 |
<select name="update_schedule">
|
1110 |
+
<option value="scheduled"<?php echo ($holdem=='scheduled')?' selected="selected"':''; ?>>update on schedule <?php
|
1111 |
echo " (";
|
1112 |
if (isset($meta['update/ttl']) and is_numeric($meta['update/ttl'])) :
|
1113 |
if (isset($meta['update/timed']) and $meta['update/timed']=='automatically') :
|
1125 |
endif;
|
1126 |
echo ")";
|
1127 |
?></option>
|
1128 |
+
<option value="next"<?php echo ($holdem=='next')?' selected="selected"':''; ?>>update ASAP</option>
|
1129 |
+
<option value="ping"<?php echo ($holdem=='ping')?' selected="selected"':''; ?>>update only when pinged</option>
|
1130 |
</select></tr>
|
1131 |
</table>
|
1132 |
</fieldset>
|
1144 |
<fieldset>
|
1145 |
<legend>Syndicated Posts</legend>
|
1146 |
|
1147 |
+
<?php fwp_category_box($dogs, 'all syndicated posts from this feed'); ?>
|
|
|
|
|
|
|
|
|
|
|
1148 |
|
1149 |
<table class="editform" width="80%" cellspacing="2" cellpadding="5">
|
1150 |
<tr><th width="20%" scope="row" style="vertical-align:top">Publication:</th>
|
1151 |
<td width="80%" style="vertical-align:top"><ul style="margin:0; list-style:none">
|
1152 |
<li><label><input type="radio" name="feed_post_status" value="site-default"
|
1153 |
+
<?php echo $status['post']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
|
1154 |
+
(currently: <strong><?php echo FeedWordPress::syndicated_status('post', array(), 'publish'); ?></strong>)</label></li>
|
1155 |
<li><label><input type="radio" name="feed_post_status" value="publish"
|
1156 |
+
<?php echo $status['post']['publish']; ?> /> Publish posts from this feed immediately</label></li>
|
1157 |
<li><label><input type="radio" name="feed_post_status" value="private"
|
1158 |
+
<?php echo $status['post']['private']; ?> /> Hold posts from this feed as private posts</label></li>
|
1159 |
<li><label><input type="radio" name="feed_post_status" value="draft"
|
1160 |
+
<?php echo $status['post']['draft']; ?> /> Hold posts from this feed as drafts</label></li>
|
1161 |
</ul></td>
|
1162 |
</tr>
|
1163 |
|
1164 |
<tr><th width="20%" scope="row" style="vertical-align:top">Comments:</th>
|
1165 |
<td width="80%"><ul style="margin:0; list-style:none">
|
1166 |
<li><label><input type="radio" name="feed_comment_status" value="site-default"
|
1167 |
+
<?php echo $status['comment']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
|
1168 |
+
(currently: <strong><?php echo FeedWordPress::syndicated_status('comment', array(), 'closed'); ?>)</strong></label></li>
|
1169 |
<li><label><input type="radio" name="feed_comment_status" value="open"
|
1170 |
+
<?php echo $status['comment']['open']; ?> /> Allow comments on syndicated posts from this feed</label></li>
|
1171 |
<li><label><input type="radio" name="feed_comment_status" value="closed"
|
1172 |
+
<?php echo $status['comment']['closed']; ?> /> Don't allow comments on syndicated posts from this feed</label></li>
|
1173 |
</ul></td>
|
1174 |
</tr>
|
1175 |
|
1176 |
<tr><th width="20%" scope="row" style="vertical-align:top">Trackback and Pingback:</th>
|
1177 |
<td width="80%"><ul style="margin:0; list-style:none">
|
1178 |
<li><label><input type="radio" name="feed_ping_status" value="site-default"
|
1179 |
+
<?php echo $status['ping']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
|
1180 |
+
(currently: <strong><?php echo FeedWordPress::syndicated_status('ping', array(), 'closed'); ?>)</strong></label></li>
|
1181 |
<li><label><input type="radio" name="feed_ping_status" value="open"
|
1182 |
+
<?php echo $status['ping']['open']; ?> /> Accept pings on syndicated posts from this feed</label></li>
|
1183 |
<li><label><input type="radio" name="feed_ping_status" value="closed"
|
1184 |
+
<?php echo $status['ping']['closed']; ?> /> Don't accept pings on syndicated posts from this feed</label></li>
|
1185 |
</ul></td>
|
1186 |
</tr>
|
1187 |
</table>
|
1197 |
<tr>
|
1198 |
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
1199 |
<td width="80%"><ul style="margin: 0; list-style:none">
|
1200 |
+
<li><label><input type="radio" name="unfamiliar_author" value="site-default"<?php echo $unfamiliar['author']['site-default']; ?> /> use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
|
1201 |
+
(currently <strong><?php echo FeedWordPress::on_unfamiliar('author');; ?></strong>)</label></li>
|
1202 |
+
<li><label><input type="radio" name="unfamiliar_author" value="create"<?php echo $unfamiliar['author']['create']; ?>/> create a new author account</label></li>
|
1203 |
+
<li><label><input type="radio" name="unfamiliar_author" value="default"<?php echo $unfamiliar['author']['default']; ?> /> attribute the post to the default author</label></li>
|
1204 |
+
<li><label><input type="radio" name="unfamiliar_author" value="filter"<?php echo $unfamiliar['author']['filter']; ?> /> don't syndicate the post</label></li>
|
1205 |
</ul></td>
|
1206 |
</tr>
|
1207 |
|
1208 |
<tr>
|
1209 |
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
1210 |
<td width="80%"><ul style="margin: 0; list-style:none">
|
1211 |
+
<li><label><input type="radio" name="unfamiliar_category" value="site-default"<?php echo $unfamiliar['category']['site-default']; ?> /> use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
|
1212 |
+
(currently <strong><?php echo FeedWordPress::on_unfamiliar('category');; ?></strong>)</label></li>
|
1213 |
+
<li><label><input type="radio" name="unfamiliar_category" value="create"<?php echo $unfamiliar['category']['create']; ?> /> create any categories the post is in</label></li>
|
1214 |
+
<li><label><input type="radio" name="unfamiliar_category" value="default"<?php echo $unfamiliar['category']['default']; ?> /> don't create new categories</label></li>
|
1215 |
+
<li><label><input type="radio" name="unfamiliar_category" value="filter"<?php echo $unfamiliar['category']['filter']; ?> /> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
|
1216 |
</ul></td>
|
1217 |
</tr></table>
|
1218 |
</fieldset>
|
1237 |
if (!preg_match("\007^((".implode(')|(', $special_settings)."))$\007i", $key)) :
|
1238 |
?>
|
1239 |
<tr style="vertical-align:top">
|
1240 |
+
<th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo wp_specialchars($key); ?>" />
|
1241 |
+
<input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo wp_specialchars($key); ?>" /></th>
|
1242 |
+
<td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo wp_specialchars($value); ?></textarea></td>
|
1243 |
+
<td width="10%"><select name="notes[<?php echo $i; ?>][action]">
|
1244 |
<option value="update">save changes</option>
|
1245 |
<option value="delete">delete this setting</option>
|
1246 |
</select></td>
|
1251 |
endforeach;
|
1252 |
?>
|
1253 |
<tr>
|
1254 |
+
<th scope="row"><input type="text" size="10" name="notes[<?php echo $i; ?>][key1]" value="" /></th>
|
1255 |
+
<td><textarea name="notes[<?php echo $i; ?>][value]" rows="2" cols="40"></textarea></td>
|
1256 |
+
<td><em>add new setting...</em><input type="hidden" name="notes[<?php echo $i; ?>][action]" value="update" /></td>
|
1257 |
</tr>
|
1258 |
</table>
|
1259 |
</fieldset>
|
1269 |
}
|
1270 |
|
1271 |
function fwp_multidelete_page () {
|
1272 |
+
global $wpdb;
|
1273 |
|
1274 |
check_admin_referer(); // Make sure the referers are kosher
|
1275 |
|
1276 |
$link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array());
|
1277 |
if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif;
|
1278 |
|
1279 |
+
if (!current_user_can('manage_links')):
|
1280 |
die (__("Cheatin' uh ?"));
|
1281 |
elseif (isset($_POST['confirm']) and $_POST['confirm']=='Delete'):
|
1282 |
foreach ($_POST['link_action'] as $link_id => $what) :
|
1359 |
WHERE link_id IN (".implode(",",$link_ids).")
|
1360 |
");
|
1361 |
?>
|
1362 |
+
<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
|
1363 |
<div class="wrap">
|
1364 |
<input type="hidden" name="action" value="Unsubscribe" />
|
1365 |
<input type="hidden" name="confirm" value="Delete" />
|
1373 |
$meta = FeedWordPress::notes_to_settings($link->link_notes);
|
1374 |
?>
|
1375 |
<fieldset>
|
1376 |
+
<legend><?php echo $link_name; ?></legend>
|
1377 |
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1378 |
<tr><th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1379 |
+
<td width="80%"><a href="<?php echo $link_rss; ?>"><?php echo $link_rss; ?></a></td></tr>
|
1380 |
<tr><th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1381 |
+
<td width="80%"><?php echo $link_description; ?></span></td></tr>
|
1382 |
<tr><th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1383 |
+
<td width="80%"><a href="<?php echo $link_url; ?>"><?php echo $link_url; ?></a></td></tr>
|
1384 |
<tr style="vertical-align:top"><th width="20%" scope="row">Subscription <?php _e('Options') ?>:</th>
|
1385 |
<td width="80%"><ul style="margin:0; padding: 0; list-style: none">
|
1386 |
+
<li><input type="radio" id="hide-<?php echo $link->link_id; ?>"
|
1387 |
+
name="link_action[<?php echo $link->link_id; ?>]" value="hide" />
|
1388 |
+
<label for="hide-<?php echo $link->link_id; ?>">Turn off the subscription for this
|
1389 |
syndicated link<br/><span style="font-size:smaller">(Keep the feed information
|
1390 |
and all the posts from this feed in the database, but don't syndicate any
|
1391 |
new posts from the feed.)</span></label></li>
|
1392 |
+
<li><input type="radio" id="nuke-<?php echo $link->link_id; ?>"
|
1393 |
+
name="link_action[<?php echo $link->link_id; ?>]" value="nuke" />
|
1394 |
+
<label for="nuke-<?php echo $link->link_id; ?>">Delete this syndicated link and all the
|
1395 |
posts that were syndicated from it</label></li>
|
1396 |
+
<li><input type="radio" id="delete-<?php echo $link->link_id; ?>"
|
1397 |
+
name="link_action[<?php echo $link->link_id; ?>]" value="delete" />
|
1398 |
+
<label for="delete-<?php echo $link->link_id; ?>">Delete this syndicated link, but
|
1399 |
<em>keep</em> posts that were syndicated from it (as if they were authored
|
1400 |
locally).</label></li>
|
1401 |
+
<li><input type="radio" id="nothing-<?php echo $link->link_id; ?>"
|
1402 |
+
name="link_action[<?php echo $link->link_id; ?>]" value="nothing" />
|
1403 |
+
<label for="nothing-<?php echo $link->link_id; ?>">Keep this feed as it is. I changed
|
1404 |
my mind.</label></li>
|
1405 |
</ul>
|
1406 |
</table>
|
1520 |
# the function `get_feed_meta($key)` if this plugin is activated.
|
1521 |
|
1522 |
function FeedWordPress () {
|
1523 |
+
$result = FeedWordPress::syndicated_links();
|
1524 |
|
1525 |
$feeds = array ();
|
1526 |
if ($result): foreach ($result as $link):
|
1642 |
|
1643 |
$uri = trim($uri);
|
1644 |
|
1645 |
+
if (FeedWordPress::needs_upgrade()) : // Will make duplicate posts if we don't hold off
|
1646 |
return NULL;
|
1647 |
endif;
|
1648 |
|
1677 |
endif;
|
1678 |
|
1679 |
if ($pinged_that and $timely) :
|
1680 |
+
do_action('feedwordpress_check_feed', $feed);
|
1681 |
$added = $this->feed2wp($wpdb, $feed);
|
1682 |
if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
|
1683 |
if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
|
1684 |
endif;
|
1685 |
endforeach;
|
1686 |
|
1687 |
+
do_action('feedwordpress_update_complete', $delta);
|
1688 |
fwp_release_pings(); // Now that we're done, send the one ping
|
1689 |
|
1690 |
return $delta;
|
1946 |
$channel = $rss->channel;
|
1947 |
|
1948 |
$post = array();
|
1949 |
+
|
1950 |
// This is ugly as all hell. I'd like to use apply_filters()'s
|
1951 |
// alleged support for a variable argument count, but this seems
|
1952 |
// to have been broken in WordPress 1.5. It'll be fixed somehow
|
2092 |
elseif (isset($item['pubdate'])): // RSS 2.0
|
2093 |
$post['epoch']['issued'] = strtotime($item['pubdate']);
|
2094 |
else:
|
2095 |
+
$post['epoch']['issued'] = null;
|
2096 |
endif;
|
2097 |
|
2098 |
# And again, for the created date
|
2108 |
$post['epoch']['modified'] = @parse_w3cdtf($item['modified']);
|
2109 |
elseif (isset($item['updated'])): // Atom 1.0
|
2110 |
$post['epoch']['modified'] = @parse_w3cdtf($item['updated']);
|
2111 |
+
elseif (isset($post['epoch']['issued'])) : // Fall back to issued / dc:date
|
2112 |
$post['epoch']['modified'] = $post['epoch']['issued'];
|
2113 |
+
else :
|
2114 |
+
$post['epoch']['modified'] = time();
|
2115 |
endif;
|
2116 |
|
2117 |
+
$post['post_date'] = date('Y-m-d H:i:s', (!is_null($post['epoch']['issued']) ? $post['epoch']['issued'] : $post['epoch']['modified']));
|
2118 |
$post['post_modified'] = date('Y-m-d H:i:s', $post['epoch']['modified']);
|
2119 |
+
$post['post_date_gmt'] = gmdate('Y-m-d H:i:s', (!is_null($post['epoch']['issued']) ? $post['epoch']['issued'] : $post['epoch']['modified']));
|
2120 |
$post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $post['epoch']['modified']);
|
2121 |
|
2122 |
# Use feed-level preferences or the global default.
|
2162 |
if ($fc) : $post['named']['preset/category'] = explode("\n", $fc);
|
2163 |
else : $post['named']['preset/category'] = array();
|
2164 |
endif;
|
2165 |
+
if (is_array($f['cats'])) :
|
2166 |
+
$post['named']['preset/category'] = array_merge($post['named']['preset/category'], $f['cats']);
|
2167 |
+
endif;
|
2168 |
|
2169 |
// Now add categories from the post, if we have 'em
|
2170 |
$post['named']['category'] = array();
|
2618 |
return $ret;
|
2619 |
} // function FeedWordPress::on_unfamiliar()
|
2620 |
|
2621 |
+
function syndicated_links () {
|
2622 |
+
$contributors = FeedWordPress::link_category_id();
|
2623 |
+
if (function_exists('get_bookmarks')) {
|
2624 |
+
$links = get_bookmarks(array("category" => $contributors));
|
2625 |
+
} else {
|
2626 |
+
$links = get_linkobjects($contributors); // deprecated as of WP 2.1
|
2627 |
+
} // if
|
2628 |
+
return $links;
|
2629 |
+
} // function syndicated_links()
|
2630 |
+
|
2631 |
+
function syndicate_link ($name, $uri, $rss) {
|
2632 |
global $wpdb;
|
2633 |
|
2634 |
+
// Get the category ID#
|
2635 |
+
$cat_id = FeedWordPress::link_category_id();
|
2636 |
+
|
2637 |
+
if (function_exists('wp_insert_link')) { // WordPress 2.x
|
2638 |
+
$link_id = wp_insert_link(array(
|
2639 |
+
"link_name" => $name,
|
2640 |
+
"link_url" => $uri,
|
2641 |
+
"link_category" => array($cat_id),
|
2642 |
+
"link_rss" => $rss
|
2643 |
+
));
|
2644 |
+
} else { // WordPress 1.5.x
|
2645 |
+
$result = $wpdb->query("
|
2646 |
+
INSERT INTO $wpdb->links
|
2647 |
+
SET
|
2648 |
+
link_name = '".$wpdb->escape($name)."',
|
2649 |
+
link_url = '".$wpdb->escape($uri)."',
|
2650 |
+
link_category = '".$wpdb->escape($cat_id)."',
|
2651 |
+
link_rss = '".$wpdb->escape($rss)."'
|
2652 |
+
");
|
2653 |
+
$link_id = $wpdb->insert_id;
|
2654 |
+
} // if
|
2655 |
+
return $link_id;
|
2656 |
+
} // function insert_syndicated_link()
|
2657 |
+
|
2658 |
+
function link_category_named ($name) {
|
2659 |
+
global $wp_db_version, $wpdb;
|
2660 |
+
|
2661 |
+
if (!isset($wp_db_version) or $wp_db_version < 4772) {
|
2662 |
+
// WordPress 1.5 and 2.0.x have segregated post and link categories
|
2663 |
+
$ct = $wpdb->linkcategories;
|
2664 |
+
} else {
|
2665 |
+
// WordPress 2.1 has a unified category table for both
|
2666 |
+
$ct = $wpdb->categories;
|
2667 |
+
}
|
2668 |
+
return $wpdb->get_var("SELECT cat_id FROM $ct WHERE cat_name='$name'");
|
2669 |
+
}
|
2670 |
+
|
2671 |
+
function create_link_category ($name) {
|
2672 |
+
global $wp_db_version, $wpdb;
|
2673 |
+
|
2674 |
+
if (!isset($wp_db_version) or $wp_db_version < 4772) {
|
2675 |
+
$result = $wpdb->query("
|
2676 |
+
INSERT INTO $wpdb->linkcategories
|
2677 |
+
SET
|
2678 |
+
cat_id = 0,
|
2679 |
+
cat_name='$name',
|
2680 |
+
show_images='N',
|
2681 |
+
show_description='N',
|
2682 |
+
show_rating='N',
|
2683 |
+
show_updated='N',
|
2684 |
+
sort_order='name'
|
2685 |
+
");
|
2686 |
+
$cat_id = $wpdb->insert_id;
|
2687 |
+
} else {
|
2688 |
+
// Why the fuck is this API function only available in a wp-admin module?
|
2689 |
+
$cat_id = wp_insert_category(array('cat_name' => $name));
|
2690 |
+
}
|
2691 |
+
}
|
2692 |
+
|
2693 |
+
function link_category_id () {
|
2694 |
+
global $wpdb, $wp_db_version;
|
2695 |
+
|
2696 |
$cat_id = get_settings('feedwordpress_cat_id');
|
2697 |
|
2698 |
// If we don't yet *have* the category, we'll have to create it
|
2699 |
if ($cat_id === false) {
|
2700 |
$cat = $wpdb->escape(DEFAULT_SYNDICATION_CATEGORY);
|
|
|
|
|
|
|
|
|
|
|
|
|
2701 |
|
2702 |
+
// Look for something with the right name...
|
2703 |
+
$cat_id = FeedWordPress::link_category_named($cat);
|
2704 |
+
|
2705 |
// If you still can't find anything, make it for yourself.
|
2706 |
if (!$cat_id) {
|
2707 |
+
$cat_id = FeedWordPress::create_link_category($cat);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2708 |
}
|
2709 |
+
|
2710 |
update_option('feedwordpress_cat_id', $cat_id);
|
2711 |
}
|
2712 |
return $cat_id;
|
2713 |
}
|
2714 |
|
2715 |
function link_category () {
|
2716 |
+
global $wpdb, $wp_db_version;
|
2717 |
|
2718 |
$cat_id = FeedWordPress::link_category_id();
|
2719 |
|
2720 |
// Get the ID# for the category name...
|
2721 |
+
if (!isset($wp_db_version) or $wp_db_version < 4772) {
|
2722 |
+
// WordPress 1.5 and 2.0.x
|
2723 |
+
$cat_name = $wpdb->get_var("
|
2724 |
+
SELECT cat_name FROM $wpdb->linkcategories
|
2725 |
+
WHERE cat_id='$cat_id'
|
2726 |
+
");
|
2727 |
+
} else {
|
2728 |
+
// WordPress 2.1
|
2729 |
+
$category = get_category($cat_id);
|
2730 |
+
$cat_name = $category->cat_name;
|
2731 |
+
}
|
2732 |
return $cat_name;
|
2733 |
}
|
2734 |
+
|
2735 |
+
function needs_upgrade () {
|
2736 |
+
global $wpdb;
|
2737 |
+
$fwp_db_version = get_settings('feedwordpress_version');
|
2738 |
+
$ret = false; // innocent until proven guilty
|
2739 |
+
if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
|
2740 |
+
// This is an older version or a fresh install. Does it
|
2741 |
+
// require a database upgrade or database initialization?
|
2742 |
+
if ($fwp_db_version > 0.96) :
|
2743 |
+
// No. Just brand it with the new version.
|
2744 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
2745 |
+
else :
|
2746 |
+
// Yes. Check to see whether this is a fresh install or an upgrade.
|
2747 |
+
$syn = $wpdb->get_col("
|
2748 |
+
SELECT post_id
|
2749 |
+
FROM $wpdb->postmeta
|
2750 |
+
WHERE meta_key = 'syndication_feed'
|
2751 |
+
");
|
2752 |
+
if (count($syn) > 0) : // contains at least one syndicated post
|
2753 |
+
$ret = true;
|
2754 |
+
else : // fresh install; brand it as ours
|
2755 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
2756 |
+
if (!get_settings('feedwordpress_rpc_secret')) :
|
2757 |
+
update_option('feedwordpress_rpc_secret', substr(md5(uniqid(microtime())), 0, 6));
|
2758 |
+
endif;
|
2759 |
+
endif;
|
2760 |
+
endif;
|
2761 |
+
endif;
|
2762 |
+
return $ret;
|
2763 |
+
}
|
2764 |
+
|
2765 |
+
|
2766 |
function upgrade_database ($from = NULL) {
|
2767 |
global $wpdb;
|
2768 |
|
2770 |
|
2771 |
switch ($from) :
|
2772 |
case 0.96: // account for changes to syndication custom values and guid
|
2773 |
+
echo "<p>Upgrading database from {$from} to ".FEEDWORDPRESS_VERSION."...</p>\n";
|
2774 |
|
2775 |
$cat_id = FeedWordPress::link_category_id();
|
2776 |
|
2942 |
$client->rawheaders['Connection'] = 'close';
|
2943 |
$client->accept = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
|
2944 |
$client->agent = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
|
2945 |
+
$client->read_timeout = 25;
|
2946 |
|
2947 |
// Fetch the HTML or feed
|
2948 |
@$client->fetch($this->uri);
|
3037 |
$parts = Relative_URI::_parse_url($url);
|
3038 |
|
3039 |
$uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
|
3040 |
+
$uri_parts['query'] = (isset($parts['query']) ? $parts['query'] : null);
|
3041 |
|
3042 |
// if path is empty, and scheme, host, and query are undefined,
|
3043 |
// the URL is referring the base URL
|