FeedWordPress - Version 2011.0706

Version Description

  • WP 3.2 COMPATIBILITY: ELIMINATES FATAL ERROR "Call to undefined method WP_SimplePie_File::WP_SimplePie_File() in [...]/wp-content/plugins/feedwordpress/feedwordpress.php on line 1841." The latest release of WordPress, version 3.2, has shifted the minimum requirements up to PHP 5.2, and in line with the shift to PHP5 they have rewritten a number of code segments that made use of now-obsolete PHP4 idioms. Unfortunately, this caused a fatal error whenever FeedWordPress attempted to make use of the cache, since FWP's caching plugin was written to match the older idiom. FeedWordPress has been updated to follow the new, PHP5 idiom when possible, thus eliminating the fatal error.

  • PERFORMANCE: The handling of queries to determine whether posts had been previously syndicated produced some very slow queries (usually, but not always, involving a scan over the MD5(post_guid) column of the table). The code that prepares MySQL queries for previously-syndicated checks has been revised to eliminate the MD5(post_guid) scan entirely, and to significantly improve performance by eliminating other unnecessary clauses.

  • BUGFIX: NO LONGER DESTROYS STICKY POSTS. Previous versions could destroy (or, more precisely, replace the content of) sticky posts due to some queries mashed together in unexpected ways by WordPress. Version 2011.0706 accounts for and eliminates the problem; your sticky posts should be safe once again.

  • BUGFIX: GUIDS CONTAINING MYSQL-ESCAPED CHARACTERS NO LONGER CAUSE DUPLICATE POSTS TO APPEAR. One remaining source of duplicate post issues in 2011.0602 was guids that contained characters that needed to be escaped for MySQL, such as single quotes and double quotes. The work-around for handling filtered URIs has now been corrected to ensure that these do not cause duplicate posts.

Download this release

Release Info

Developer radgeek
Plugin Icon wp plugin FeedWordPress
Version 2011.0706
Comparing to
See all releases

Code changes from version 2011.0602 to 2011.0706

admin-ui.php CHANGED
@@ -946,6 +946,12 @@ class FeedWordPressSettingsUI {
946
  background-position:0 top;
947
  background-repeat:repeat-x;
948
  }
 
 
 
 
 
 
949
  </style>
950
  <?php
951
  } /* FeedWordPressSettingsUI::admin_styles () */
946
  background-position:0 top;
947
  background-repeat:repeat-x;
948
  }
949
+
950
+ .update-results {
951
+ max-width: 100%;
952
+ overflow: auto;
953
+ }
954
+
955
  </style>
956
  <?php
957
  } /* FeedWordPressSettingsUI::admin_styles () */
diagnostics-page.php CHANGED
@@ -70,6 +70,7 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
70
  if (isset($post['submit'])
71
  or isset($post['save'])) :
72
  update_option('feedwordpress_debug', $post['feedwordpress_debug']);
 
73
 
74
  if (!isset($post['diagnostics_output'])
75
  or !is_array($post['diagnostics_output'])) :
@@ -106,8 +107,9 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
106
  } /* FeedWordPressDiagnosticsPage::accept_POST () */
107
 
108
  function info_box ($page, $box = NULL) {
109
- $link_category_id = FeedWordPress::link_category_id();
110
- ?>
 
111
  <table class="edit-form narrow">
112
  <thead style="display: none">
113
  <th scope="col">Topic</th>
@@ -146,6 +148,14 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
146
  </table>
147
  <?php endif; ?></td>
148
  </tr>
 
 
 
 
 
 
 
 
149
  </table>
150
 
151
  <?php
70
  if (isset($post['submit'])
71
  or isset($post['save'])) :
72
  update_option('feedwordpress_debug', $post['feedwordpress_debug']);
73
+ update_option('feedwordpress_secret_key', $post['feedwordpress_secret_key']);
74
 
75
  if (!isset($post['diagnostics_output'])
76
  or !is_array($post['diagnostics_output'])) :
107
  } /* FeedWordPressDiagnosticsPage::accept_POST () */
108
 
109
  function info_box ($page, $box = NULL) {
110
+ global $feedwordpress;
111
+ $link_category_id = FeedWordPress::link_category_id();
112
+ ?>
113
  <table class="edit-form narrow">
114
  <thead style="display: none">
115
  <th scope="col">Topic</th>
148
  </table>
149
  <?php endif; ?></td>
150
  </tr>
151
+
152
+ <tr>
153
+ <th scope="row"><?php _e('Secret Key:'); ?></th>
154
+ <td><input type="text" name="feedwordpress_secret_key" value="<?php print esc_attr($feedwordpress->secret_key()); ?>" />
155
+ <p class="setting-description">This is used to control access to some diagnostic testing functions. You can change it to any string you want,
156
+ but only tell it to people you trust to help you troubleshoot your
157
+ FeedWordPress installation. Keep it secret&#8212;keep it safe.</p></td>
158
+ </tr>
159
  </table>
160
 
161
  <?php
feedwordpress.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: FeedWordPress
4
  Plugin URI: http://feedwordpress.radgeek.com/
5
  Description: simple and flexible Atom/RSS syndication for WordPress
6
- Version: 2011.0602
7
  Author: Charles Johnson
8
  Author URI: http://radgeek.com/
9
  License: GPL
@@ -11,7 +11,7 @@ License: GPL
11
 
12
  /**
13
  * @package FeedWordPress
14
- * @version 2011.0602
15
  */
16
 
17
  # This uses code derived from:
@@ -34,7 +34,7 @@ License: GPL
34
 
35
  # -- Don't change these unless you know what you're doing...
36
 
37
- define ('FEEDWORDPRESS_VERSION', '2011.0602');
38
  define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
39
 
40
  if (!defined('FEEDWORDPRESS_BLEG')) :
@@ -119,6 +119,9 @@ require_once("${dir}/feedwordpresshtml.class.php");
119
  require_once("${dir}/feedwordpress-content-type-sniffer.class.php");
120
  require_once("${dir}/inspectpostmeta.class.php");
121
  require_once("${dir}/syndicationdataqueries.class.php");
 
 
 
122
 
123
  // Magic quotes are just about the stupidest thing ever.
124
  if (is_array($_POST)) :
@@ -226,11 +229,11 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
226
  $feedwordpress = new FeedWordPress;
227
 
228
  # Cron-less auto-update. Hooray!
229
- $autoUpdateHook = get_option('feedwordpress_automatic_updates');
230
- if ($autoUpdateHook != 'init') :
231
- $autoUpdateHook = 'shutdown';
232
  endif;
233
- add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
234
  add_action('init', array(&$feedwordpress, 'init'));
235
  add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
236
  add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
@@ -1042,12 +1045,49 @@ class FeedWordPress {
1042
  return $crash_ts;
1043
  }
1044
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1045
  function stale () {
1046
- if (get_option('feedwordpress_automatic_updates')) :
1047
  // Do our best to avoid possible simultaneous
1048
  // updates by getting up-to-the-minute settings.
1049
 
1050
- $last = get_option('feedwordpress_last_update_all');
1051
 
1052
  // If we haven't updated all yet, give it a time window
1053
  if (false === $last) :
@@ -1060,9 +1100,9 @@ class FeedWordPress {
1060
  if (false === $freshness) : // Use default
1061
  $freshness = FEEDWORDPRESS_FRESHNESS_INTERVAL;
1062
  endif;
1063
- $ret = ( (time() - $last) > $freshness);
1064
-
1065
- // This should never happen.
1066
  else :
1067
  FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__, __FILE__);
1068
  endif;
@@ -1507,7 +1547,6 @@ class FeedWordPress {
1507
  $feed->set_cache_class($cache_class);
1508
  $feed->set_timeout($timeout);
1509
 
1510
- //$feed->set_file_class('WP_SimplePie_File');
1511
  $feed->set_content_type_sniffer_class($sniffer_class);
1512
  $feed->set_file_class($file_class);
1513
  $feed->set_parser_class($parser_class);
@@ -1673,11 +1712,31 @@ class FeedWordPress {
1673
  update_option('feedwordpress_diagnostics_log', $dlog);
1674
  } /* FeedWordPress::diagnostic () */
1675
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1676
  function email_diagnostic_log () {
1677
  $dlog = get_option('feedwordpress_diagnostics_log', array());
1678
 
1679
- if (isset($dlog['schedule']) and isset($dlog['schedule']['last'])) :
1680
- if (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq'])) :
1681
  // No news is good news; only send if
1682
  // there are some messages to send.
1683
  $body = NULL;
@@ -1711,9 +1770,10 @@ class FeedWordPress {
1711
  endif;
1712
  endforeach;
1713
 
 
1714
  if (!is_null($body)) :
1715
  $home = feedwordpress_display_url(get_bloginfo('url'));
1716
- $subj = $home . " syndication issues for ".date('j-M-y', time());
1717
  $agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION;
1718
  $body = <<<EOMAIL
1719
  <html>
@@ -1836,344 +1896,8 @@ EOMAIL;
1836
  }
1837
  } // class FeedWordPress
1838
 
1839
- class FeedWordPress_File extends WP_SimplePie_File {
1840
- function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
1841
- WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
1842
-
1843
- // SimplePie makes a strongly typed check against integers with
1844
- // this, but WordPress puts a string in. Which causes caching
1845
- // to break and fall on its ass when SimplePie is getting a 304,
1846
- // but doesn't realize it because this member is "304" instead.
1847
- $this->status_code = (int) $this->status_code;
1848
- }
1849
- } /* class FeedWordPress_File () */
1850
-
1851
- class FeedWordPress_Parser extends SimplePie_Parser {
1852
- function parse (&$data, $encoding) {
1853
- // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
1854
- if (strtoupper($encoding) === 'US-ASCII')
1855
- {
1856
- $this->encoding = 'UTF-8';
1857
- }
1858
- else
1859
- {
1860
- $this->encoding = $encoding;
1861
- }
1862
-
1863
- // Strip BOM:
1864
- // UTF-32 Big Endian BOM
1865
- if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
1866
- {
1867
- $data = substr($data, 4);
1868
- }
1869
- // UTF-32 Little Endian BOM
1870
- elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
1871
- {
1872
- $data = substr($data, 4);
1873
- }
1874
- // UTF-16 Big Endian BOM
1875
- elseif (substr($data, 0, 2) === "\xFE\xFF")
1876
- {
1877
- $data = substr($data, 2);
1878
- }
1879
- // UTF-16 Little Endian BOM
1880
- elseif (substr($data, 0, 2) === "\xFF\xFE")
1881
- {
1882
- $data = substr($data, 2);
1883
- }
1884
- // UTF-8 BOM
1885
- elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
1886
- {
1887
- $data = substr($data, 3);
1888
- }
1889
-
1890
- if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
1891
- {
1892
- $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
1893
- if ($declaration->parse())
1894
- {
1895
- $data = substr($data, $pos + 2);
1896
- $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
1897
- }
1898
- else
1899
- {
1900
- $this->error_string = 'SimplePie bug! Please report this!';
1901
- return false;
1902
- }
1903
- }
1904
-
1905
- $return = true;
1906
-
1907
- static $xml_is_sane = null;
1908
- if ($xml_is_sane === null)
1909
- {
1910
- $parser_check = xml_parser_create();
1911
- xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1912
- xml_parser_free($parser_check);
1913
- $xml_is_sane = isset($values[0]['value']);
1914
- }
1915
-
1916
- // Create the parser
1917
- if ($xml_is_sane)
1918
- {
1919
- $xml = xml_parser_create_ns($this->encoding, $this->separator);
1920
- xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
1921
- xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
1922
- xml_set_object($xml, $this);
1923
- xml_set_character_data_handler($xml, 'cdata');
1924
- xml_set_element_handler($xml, 'tag_open', 'tag_close');
1925
- xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
1926
-
1927
- // Parse!
1928
- if (!xml_parse($xml, $data, true))
1929
- {
1930
- $this->error_code = xml_get_error_code($xml);
1931
- $this->error_string = xml_error_string($this->error_code);
1932
- $return = false;
1933
- }
1934
-
1935
- $this->current_line = xml_get_current_line_number($xml);
1936
- $this->current_column = xml_get_current_column_number($xml);
1937
- $this->current_byte = xml_get_current_byte_index($xml);
1938
- xml_parser_free($xml);
1939
-
1940
- return $return;
1941
- }
1942
- else
1943
- {
1944
- libxml_clear_errors();
1945
- $xml =& new XMLReader();
1946
- $xml->xml($data);
1947
- while (@$xml->read())
1948
- {
1949
- switch ($xml->nodeType)
1950
- {
1951
-
1952
- case constant('XMLReader::END_ELEMENT'):
1953
- if ($xml->namespaceURI !== '')
1954
- {
1955
- $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1956
- }
1957
- else
1958
- {
1959
- $tagName = $xml->localName;
1960
- }
1961
- $this->tag_close(null, $tagName);
1962
- break;
1963
- case constant('XMLReader::ELEMENT'):
1964
- $empty = $xml->isEmptyElement;
1965
- if ($xml->namespaceURI !== '')
1966
- {
1967
- $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1968
- }
1969
- else
1970
- {
1971
- $tagName = $xml->localName;
1972
- }
1973
- $attributes = array();
1974
- while ($xml->moveToNextAttribute())
1975
- {
1976
- if ($xml->namespaceURI !== '')
1977
- {
1978
- $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1979
- }
1980
- else
1981
- {
1982
- $attrName = $xml->localName;
1983
- }
1984
- $attributes[$attrName] = $xml->value;
1985
- }
1986
-
1987
- foreach ($attributes as $attr => $value) :
1988
- list($ns, $local) = $this->split_ns($attr);
1989
- if ($ns=='http://www.w3.org/2000/xmlns/') :
1990
- if ('xmlns' == $local) : $local = false; endif;
1991
- $this->start_xmlns(null, $local, $value);
1992
- endif;
1993
- endforeach;
1994
-
1995
- $this->tag_open(null, $tagName, $attributes);
1996
- if ($empty)
1997
- {
1998
- $this->tag_close(null, $tagName);
1999
- }
2000
- break;
2001
- case constant('XMLReader::TEXT'):
2002
-
2003
- case constant('XMLReader::CDATA'):
2004
- $this->cdata(null, $xml->value);
2005
- break;
2006
- }
2007
- }
2008
- if ($error = libxml_get_last_error())
2009
- {
2010
- $this->error_code = $error->code;
2011
- $this->error_string = $error->message;
2012
- $this->current_line = $error->line;
2013
- $this->current_column = $error->column;
2014
- return false;
2015
- }
2016
- else
2017
- {
2018
- return true;
2019
- }
2020
- }
2021
- } /* FeedWordPress_Parser::parse() */
2022
-
2023
- var $xmlns_stack = array();
2024
- var $xmlns_current = array();
2025
- function tag_open ($parser, $tag, $attributes) {
2026
- $ret = parent::tag_open($parser, $tag, $attributes);
2027
- if ($this->current_xhtml_construct < 0) :
2028
- $this->data['xmlns'] = $this->xmlns_current;
2029
- $this->xmlns_stack[] = $this->xmlns_current;
2030
- endif;
2031
- return $ret;
2032
- }
2033
-
2034
- function tag_close($parser, $tag) {
2035
- if ($this->current_xhtml_construct < 0) :
2036
- $this->xmlns_current = array_pop($this->xmlns_stack);
2037
- endif;
2038
- $ret = parent::tag_close($parser, $tag);
2039
- return $ret;
2040
- }
2041
-
2042
- function start_xmlns ($parser, $prefix, $uri) {
2043
- if (!$prefix) :
2044
- $prefix = '';
2045
- endif;
2046
- if ($this->current_xhtml_construct < 0) :
2047
- $this->xmlns_current[$prefix] = $uri;
2048
- endif;
2049
- return true;
2050
- } /* FeedWordPress_Parser::start_xmlns() */
2051
- }
2052
-
2053
  $feedwordpress_admin_footer = array();
2054
 
2055
- ################################################################################
2056
- ## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
2057
- ################################################################################
2058
-
2059
- class FeedWordPressRPC {
2060
- function FeedWordPressRPC () {
2061
- add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
2062
- }
2063
-
2064
- function xmlrpc_methods ($args = array()) {
2065
- $args['weblogUpdates.ping'] = array(&$this, 'ping');
2066
- $args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
2067
- $args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
2068
- $args['feedwordpress.delete'] = array(&$this, 'delete');
2069
- $args['feedwordpress.nuke'] = array(&$this, 'nuke');
2070
- return $args;
2071
- }
2072
-
2073
- function ping ($args) {
2074
- global $feedwordpress;
2075
-
2076
- $delta = @$feedwordpress->update($args[1]);
2077
- if (is_null($delta)):
2078
- return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
2079
- else:
2080
- $mesg = array();
2081
- if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
2082
- if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
2083
-
2084
- return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
2085
- endif;
2086
- }
2087
-
2088
- function validate (&$args) {
2089
- global $wp_xmlrpc_server;
2090
-
2091
- // First two params are username/password
2092
- $username = $wp_xmlrpc_server->escape(array_shift($args));
2093
- $password = $wp_xmlrpc_server->escape(array_shift($args));
2094
-
2095
- $ret = array();
2096
- if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
2097
- $ret = $wp_xmlrpc_server->error;
2098
- elseif (!current_user_can('manage_links')) :
2099
- $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
2100
- endif;
2101
- return $ret;
2102
- }
2103
-
2104
- function subscribe ($args) {
2105
- $ret = $this->validate($args);
2106
- if (is_array($ret)) : // Success
2107
- // The remaining params are feed URLs
2108
- foreach ($args as $arg) :
2109
- $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
2110
- $feeds = array_values(array_unique($finder->find()));
2111
-
2112
- if (count($feeds) > 0) :
2113
- $link_id = FeedWordPress::syndicate_link(
2114
- /*title=*/ feedwordpress_display_url($feeds[0]),
2115
- /*homepage=*/ $feeds[0],
2116
- /*feed=*/ $feeds[0]
2117
- );
2118
- $ret[] = array(
2119
- 'added',
2120
- $feeds[0],
2121
- $arg,
2122
- );
2123
- else :
2124
- $ret[] = array(
2125
- 'error',
2126
- $arg
2127
- );
2128
- endif;
2129
- endforeach;
2130
- endif;
2131
- return $ret;
2132
- } /* FeedWordPressRPC::subscribe () */
2133
-
2134
- function unsubscribe ($method, $args) {
2135
- $ret = $this->validate($args);
2136
- if (is_array($ret)) : // Success
2137
- // The remaining params are feed URLs
2138
- foreach ($args as $arg) :
2139
- $link_id = FeedWordPress::find_link($arg);
2140
-
2141
- if (!$link_id) :
2142
- $link_id = FeedWordPress::find_link($arg, 'link_url');
2143
- endif;
2144
-
2145
- if ($link_id) :
2146
- $link = new SyndicatedLink($link_id);
2147
-
2148
- $link->{$method}();
2149
- $ret[] = array(
2150
- 'deactivated',
2151
- $arg,
2152
- );
2153
- else :
2154
- $ret[] = array(
2155
- 'error',
2156
- $arg,
2157
- );
2158
- endif;
2159
- endforeach;
2160
- endif;
2161
- return $ret;
2162
- } /* FeedWordPress::unsubscribe () */
2163
-
2164
- function deactivate ($args) {
2165
- return $this->unsubscribe('deactivate', $args);
2166
- } /* FeedWordPressRPC::deactivate () */
2167
-
2168
- function delete ($args) {
2169
- return $this->unsubscribe('delete', $args);
2170
- } /* FeedWordPressRPC::delete () */
2171
-
2172
- function nuke ($args) {
2173
- return $this->unsubscribe('nuke', $args);
2174
- } /* FeedWordPressRPC::nuke () */
2175
- } /* class FeedWordPressRPC */
2176
-
2177
  // take your best guess at the realname and e-mail, given a string
2178
  define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
2179
  define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');
3
  Plugin Name: FeedWordPress
4
  Plugin URI: http://feedwordpress.radgeek.com/
5
  Description: simple and flexible Atom/RSS syndication for WordPress
6
+ Version: 2011.0706
7
  Author: Charles Johnson
8
  Author URI: http://radgeek.com/
9
  License: GPL
11
 
12
  /**
13
  * @package FeedWordPress
14
+ * @version 2011.0706
15
  */
16
 
17
  # This uses code derived from:
34
 
35
  # -- Don't change these unless you know what you're doing...
36
 
37
+ define ('FEEDWORDPRESS_VERSION', '2011.0706');
38
  define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
39
 
40
  if (!defined('FEEDWORDPRESS_BLEG')) :
119
  require_once("${dir}/feedwordpress-content-type-sniffer.class.php");
120
  require_once("${dir}/inspectpostmeta.class.php");
121
  require_once("${dir}/syndicationdataqueries.class.php");
122
+ require_once("${dir}/feedwordpress_file.class.php");
123
+ require_once("${dir}/feedwordpress_parser.class.php");
124
+ require_once("${dir}/feedwordpressrpc.class.php");
125
 
126
  // Magic quotes are just about the stupidest thing ever.
127
  if (is_array($_POST)) :
229
  $feedwordpress = new FeedWordPress;
230
 
231
  # Cron-less auto-update. Hooray!
232
+ $autoUpdateHook = $feedwordpress->automatic_update_hook();
233
+ if (!is_null($autoUpdateHook)) :
234
+ add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
235
  endif;
236
+
237
  add_action('init', array(&$feedwordpress, 'init'));
238
  add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
239
  add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
1045
  return $crash_ts;
1046
  }
1047
 
1048
+ function secret_key () {
1049
+ $secret = get_option('feedwordpress_secret_key', false);
1050
+ if (!$secret) : // Generate random key.
1051
+ $secret = substr(md5(uniqid(microtime())), 0, 6);
1052
+ update_option('feedwordpress_secret_key', $secret);
1053
+ endif;
1054
+ return $secret;
1055
+ }
1056
+
1057
+ function has_secret () {
1058
+ return (isset($_REQUEST['feedwordpress_key']) and ($_REQUEST['feedwordpress_key']==$this->secret_key()));
1059
+ }
1060
+
1061
+ function automatic_update_hook () {
1062
+ $hook = get_option('feedwordpress_automatic_updates', NULL);
1063
+ if ($this->has_secret() and isset($_REQUEST['automatic_update'])) : // For forced behavior in testing.
1064
+ $hook = $_REQUEST['automatic_update'];
1065
+ endif;
1066
+
1067
+ if (!is_null($hook)) :
1068
+ if ($hook != 'init') : // Constrain values.
1069
+ $hook = 'shutdown';
1070
+ endif;
1071
+ endif;
1072
+ return $hook;
1073
+ }
1074
+ function last_update_all () {
1075
+ $last = get_option('feedwordpress_last_update_all');
1076
+ if ($this->has_secret() and isset($_REQUEST['automatic_update']) and ((strlen($_REQUEST['automatic_update']) > 0))) :
1077
+ $last = 1; // A long, long time ago.
1078
+ endif;
1079
+ return $last;
1080
+ }
1081
+ function force_update_all () {
1082
+ return ($this->has_secret() and isset($_REQUEST['force_update_feeds']) and !!$_REQUEST['force_update_feeds']);
1083
+ }
1084
+
1085
  function stale () {
1086
+ if (!is_null($this->automatic_update_hook())) :
1087
  // Do our best to avoid possible simultaneous
1088
  // updates by getting up-to-the-minute settings.
1089
 
1090
+ $last = $this->last_update_all();
1091
 
1092
  // If we haven't updated all yet, give it a time window
1093
  if (false === $last) :
1100
  if (false === $freshness) : // Use default
1101
  $freshness = FEEDWORDPRESS_FRESHNESS_INTERVAL;
1102
  endif;
1103
+ $ret = ( (time() - $last) > $freshness );
1104
+
1105
+ // This should never happen.
1106
  else :
1107
  FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__, __FILE__);
1108
  endif;
1547
  $feed->set_cache_class($cache_class);
1548
  $feed->set_timeout($timeout);
1549
 
 
1550
  $feed->set_content_type_sniffer_class($sniffer_class);
1551
  $feed->set_file_class($file_class);
1552
  $feed->set_parser_class($parser_class);
1712
  update_option('feedwordpress_diagnostics_log', $dlog);
1713
  } /* FeedWordPress::diagnostic () */
1714
 
1715
+ function email_diagnostics_override () {
1716
+ return ($this->has_secret() and isset($_REQUEST['feedwordpress_email_diagnostics']) and !!$_REQUEST['feedwordpress_email_diagnostics']);
1717
+ }
1718
+ function has_emailed_diagnostics ($dlog) {
1719
+ $ret = false;
1720
+ if ($this->email_diagnostics_override()
1721
+ or (isset($dlog['schedule']) and isset($dlog['schedule']['last']))) :
1722
+ $ret = true;
1723
+ endif;
1724
+ return $ret;
1725
+ }
1726
+ function ready_to_email_diagnostics ($dlog) {
1727
+ $ret = false;
1728
+ if ($this->email_diagnostics_override()
1729
+ or (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq']))) :
1730
+ $ret = true;
1731
+ endif;
1732
+ return $ret;
1733
+ }
1734
+
1735
  function email_diagnostic_log () {
1736
  $dlog = get_option('feedwordpress_diagnostics_log', array());
1737
 
1738
+ if ($this->has_emailed_diagnostics($dlog)) :
1739
+ if ($this->ready_to_email_diagnostics($dlog)) :
1740
  // No news is good news; only send if
1741
  // there are some messages to send.
1742
  $body = NULL;
1770
  endif;
1771
  endforeach;
1772
 
1773
+ $body = apply_filters('feedwordpress_diagnostic_email_body', $body, $dlog);
1774
  if (!is_null($body)) :
1775
  $home = feedwordpress_display_url(get_bloginfo('url'));
1776
+ $subj = apply_filters('feedwordpress_diagnostic_email_subject', $home . " syndication issues", $dlog);
1777
  $agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION;
1778
  $body = <<<EOMAIL
1779
  <html>
1896
  }
1897
  } // class FeedWordPress
1898
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1899
  $feedwordpress_admin_footer = array();
1900
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1901
  // take your best guess at the realname and e-mail, given a string
1902
  define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
1903
  define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');
feedwordpress_file.class.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FeedWordPress_File extends WP_SimplePie_File {
3
+ function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
4
+ self::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
5
+ }
6
+
7
+ function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
8
+ if (is_callable(array('WP_SimplePie_File', 'WP_SimplePie_File'))) : // PHP 4 idiom
9
+ WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
10
+ else : // PHP 5+
11
+ parent::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
12
+ endif;
13
+
14
+ // SimplePie makes a strongly typed check against integers with
15
+ // this, but WordPress puts a string in. Which causes caching
16
+ // to break and fall on its ass when SimplePie is getting a 304,
17
+ // but doesn't realize it because this member is "304" instead.
18
+ $this->status_code = (int) $this->status_code;
19
+ }
20
+ } /* class FeedWordPress_File () */
21
+
feedwordpress_parser.class.php ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FeedWordPress_Parser extends SimplePie_Parser {
3
+ function parse (&$data, $encoding) {
4
+ // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
5
+ if (strtoupper($encoding) === 'US-ASCII')
6
+ {
7
+ $this->encoding = 'UTF-8';
8
+ }
9
+ else
10
+ {
11
+ $this->encoding = $encoding;
12
+ }
13
+
14
+ // Strip BOM:
15
+ // UTF-32 Big Endian BOM
16
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
17
+ {
18
+ $data = substr($data, 4);
19
+ }
20
+ // UTF-32 Little Endian BOM
21
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
22
+ {
23
+ $data = substr($data, 4);
24
+ }
25
+ // UTF-16 Big Endian BOM
26
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
27
+ {
28
+ $data = substr($data, 2);
29
+ }
30
+ // UTF-16 Little Endian BOM
31
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
32
+ {
33
+ $data = substr($data, 2);
34
+ }
35
+ // UTF-8 BOM
36
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
37
+ {
38
+ $data = substr($data, 3);
39
+ }
40
+
41
+ if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
42
+ {
43
+ $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
44
+ if ($declaration->parse())
45
+ {
46
+ $data = substr($data, $pos + 2);
47
+ $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
48
+ }
49
+ else
50
+ {
51
+ $this->error_string = 'SimplePie bug! Please report this!';
52
+ return false;
53
+ }
54
+ }
55
+
56
+ $return = true;
57
+
58
+ static $xml_is_sane = null;
59
+ if ($xml_is_sane === null)
60
+ {
61
+ $parser_check = xml_parser_create();
62
+ xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
63
+ xml_parser_free($parser_check);
64
+ $xml_is_sane = isset($values[0]['value']);
65
+ }
66
+
67
+ // Create the parser
68
+ if ($xml_is_sane)
69
+ {
70
+ $xml = xml_parser_create_ns($this->encoding, $this->separator);
71
+ xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
72
+ xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
73
+ xml_set_object($xml, $this);
74
+ xml_set_character_data_handler($xml, 'cdata');
75
+ xml_set_element_handler($xml, 'tag_open', 'tag_close');
76
+ xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
77
+
78
+ // Parse!
79
+ if (!xml_parse($xml, $data, true))
80
+ {
81
+ $this->error_code = xml_get_error_code($xml);
82
+ $this->error_string = xml_error_string($this->error_code);
83
+ $return = false;
84
+ }
85
+
86
+ $this->current_line = xml_get_current_line_number($xml);
87
+ $this->current_column = xml_get_current_column_number($xml);
88
+ $this->current_byte = xml_get_current_byte_index($xml);
89
+ xml_parser_free($xml);
90
+
91
+ return $return;
92
+ }
93
+ else
94
+ {
95
+ libxml_clear_errors();
96
+ $xml =& new XMLReader();
97
+ $xml->xml($data);
98
+ while (@$xml->read())
99
+ {
100
+ switch ($xml->nodeType)
101
+ {
102
+
103
+ case constant('XMLReader::END_ELEMENT'):
104
+ if ($xml->namespaceURI !== '')
105
+ {
106
+ $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
107
+ }
108
+ else
109
+ {
110
+ $tagName = $xml->localName;
111
+ }
112
+ $this->tag_close(null, $tagName);
113
+ break;
114
+ case constant('XMLReader::ELEMENT'):
115
+ $empty = $xml->isEmptyElement;
116
+ if ($xml->namespaceURI !== '')
117
+ {
118
+ $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
119
+ }
120
+ else
121
+ {
122
+ $tagName = $xml->localName;
123
+ }
124
+ $attributes = array();
125
+ while ($xml->moveToNextAttribute())
126
+ {
127
+ if ($xml->namespaceURI !== '')
128
+ {
129
+ $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
130
+ }
131
+ else
132
+ {
133
+ $attrName = $xml->localName;
134
+ }
135
+ $attributes[$attrName] = $xml->value;
136
+ }
137
+
138
+ foreach ($attributes as $attr => $value) :
139
+ list($ns, $local) = $this->split_ns($attr);
140
+ if ($ns=='http://www.w3.org/2000/xmlns/') :
141
+ if ('xmlns' == $local) : $local = false; endif;
142
+ $this->start_xmlns(null, $local, $value);
143
+ endif;
144
+ endforeach;
145
+
146
+ $this->tag_open(null, $tagName, $attributes);
147
+ if ($empty)
148
+ {
149
+ $this->tag_close(null, $tagName);
150
+ }
151
+ break;
152
+ case constant('XMLReader::TEXT'):
153
+
154
+ case constant('XMLReader::CDATA'):
155
+ $this->cdata(null, $xml->value);
156
+ break;
157
+ }
158
+ }
159
+ if ($error = libxml_get_last_error())
160
+ {
161
+ $this->error_code = $error->code;
162
+ $this->error_string = $error->message;
163
+ $this->current_line = $error->line;
164
+ $this->current_column = $error->column;
165
+ return false;
166
+ }
167
+ else
168
+ {
169
+ return true;
170
+ }
171
+ }
172
+ } /* FeedWordPress_Parser::parse() */
173
+
174
+ var $xmlns_stack = array();
175
+ var $xmlns_current = array();
176
+ function tag_open ($parser, $tag, $attributes) {
177
+ $ret = parent::tag_open($parser, $tag, $attributes);
178
+ if ($this->current_xhtml_construct < 0) :
179
+ $this->data['xmlns'] = $this->xmlns_current;
180
+ $this->xmlns_stack[] = $this->xmlns_current;
181
+ endif;
182
+ return $ret;
183
+ }
184
+
185
+ function tag_close($parser, $tag) {
186
+ if ($this->current_xhtml_construct < 0) :
187
+ $this->xmlns_current = array_pop($this->xmlns_stack);
188
+ endif;
189
+ $ret = parent::tag_close($parser, $tag);
190
+ return $ret;
191
+ }
192
+
193
+ function start_xmlns ($parser, $prefix, $uri) {
194
+ if (!$prefix) :
195
+ $prefix = '';
196
+ endif;
197
+ if ($this->current_xhtml_construct < 0) :
198
+ $this->xmlns_current[$prefix] = $uri;
199
+ endif;
200
+ return true;
201
+ } /* FeedWordPress_Parser::start_xmlns() */
202
+ }
203
+
feedwordpressrpc.class.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ ################################################################################
3
+ ## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
4
+ ################################################################################
5
+
6
+ class FeedWordPressRPC {
7
+ function FeedWordPressRPC () {
8
+ add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
9
+ }
10
+
11
+ function xmlrpc_methods ($args = array()) {
12
+ $args['weblogUpdates.ping'] = array(&$this, 'ping');
13
+ $args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
14
+ $args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
15
+ $args['feedwordpress.delete'] = array(&$this, 'delete');
16
+ $args['feedwordpress.nuke'] = array(&$this, 'nuke');
17
+ return $args;
18
+ }
19
+
20
+ function ping ($args) {
21
+ global $feedwordpress;
22
+
23
+ $delta = @$feedwordpress->update($args[1]);
24
+ if (is_null($delta)):
25
+ return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
26
+ else:
27
+ $mesg = array();
28
+ if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
29
+ if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
30
+
31
+ return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
32
+ endif;
33
+ }
34
+
35
+ function validate (&$args) {
36
+ global $wp_xmlrpc_server;
37
+
38
+ // First two params are username/password
39
+ $username = $wp_xmlrpc_server->escape(array_shift($args));
40
+ $password = $wp_xmlrpc_server->escape(array_shift($args));
41
+
42
+ $ret = array();
43
+ if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
44
+ $ret = $wp_xmlrpc_server->error;
45
+ elseif (!current_user_can('manage_links')) :
46
+ $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
47
+ endif;
48
+ return $ret;
49
+ }
50
+
51
+ function subscribe ($args) {
52
+ $ret = $this->validate($args);
53
+ if (is_array($ret)) : // Success
54
+ // The remaining params are feed URLs
55
+ foreach ($args as $arg) :
56
+ $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
57
+ $feeds = array_values(array_unique($finder->find()));
58
+
59
+ if (count($feeds) > 0) :
60
+ $link_id = FeedWordPress::syndicate_link(
61
+ /*title=*/ feedwordpress_display_url($feeds[0]),
62
+ /*homepage=*/ $feeds[0],
63
+ /*feed=*/ $feeds[0]
64
+ );
65
+ $ret[] = array(
66
+ 'added',
67
+ $feeds[0],
68
+ $arg,
69
+ );
70
+ else :
71
+ $ret[] = array(
72
+ 'error',
73
+ $arg
74
+ );
75
+ endif;
76
+ endforeach;
77
+ endif;
78
+ return $ret;
79
+ } /* FeedWordPressRPC::subscribe () */
80
+
81
+ function unsubscribe ($method, $args) {
82
+ $ret = $this->validate($args);
83
+ if (is_array($ret)) : // Success
84
+ // The remaining params are feed URLs
85
+ foreach ($args as $arg) :
86
+ $link_id = FeedWordPress::find_link($arg);
87
+
88
+ if (!$link_id) :
89
+ $link_id = FeedWordPress::find_link($arg, 'link_url');
90
+ endif;
91
+
92
+ if ($link_id) :
93
+ $link = new SyndicatedLink($link_id);
94
+
95
+ $link->{$method}();
96
+ $ret[] = array(
97
+ 'deactivated',
98
+ $arg,
99
+ );
100
+ else :
101
+ $ret[] = array(
102
+ 'error',
103
+ $arg,
104
+ );
105
+ endif;
106
+ endforeach;
107
+ endif;
108
+ return $ret;
109
+ } /* FeedWordPress::unsubscribe () */
110
+
111
+ function deactivate ($args) {
112
+ return $this->unsubscribe('deactivate', $args);
113
+ } /* FeedWordPressRPC::deactivate () */
114
+
115
+ function delete ($args) {
116
+ return $this->unsubscribe('delete', $args);
117
+ } /* FeedWordPressRPC::delete () */
118
+
119
+ function nuke ($args) {
120
+ return $this->unsubscribe('nuke', $args);
121
+ } /* FeedWordPressRPC::nuke () */
122
+ } /* class FeedWordPressRPC */
123
+
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: Charles Johnson
3
  Donate link: http://feedwordpress.radgeek.com/
4
  Tags: syndication, aggregation, feed, atom, rss
5
  Requires at least: 3.0
6
- Tested up to: 3.1.3
7
- Stable tag: 2011.0602
8
 
9
  FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
10
 
@@ -93,6 +93,39 @@ outs, see the documentation at the [FeedWordPress project homepage][].
93
 
94
  == Changelog ==
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  = 2011.0602 =
97
 
98
  * WP 3.1.3 COMPAT / BUGFIX: WHITESPACE IN GUIDS NO LONGER PRODUCES DUPLICATE
3
  Donate link: http://feedwordpress.radgeek.com/
4
  Tags: syndication, aggregation, feed, atom, rss
5
  Requires at least: 3.0
6
+ Tested up to: 3.2
7
+ Stable tag: 2011.0706
8
 
9
  FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
10
 
93
 
94
  == Changelog ==
95
 
96
+ = 2011.0706 =
97
+
98
+ * WP 3.2 COMPATIBILITY: ELIMINATES FATAL ERROR "Call to undefined method
99
+ WP_SimplePie_File::WP_SimplePie_File() in
100
+ [...]/wp-content/plugins/feedwordpress/feedwordpress.php on line 1841." The
101
+ latest release of WordPress, version 3.2, has shifted the minimum
102
+ requirements up to PHP 5.2, and in line with the shift to PHP5 they have
103
+ rewritten a number of code segments that made use of now-obsolete PHP4
104
+ idioms. Unfortunately, this caused a fatal error whenever FeedWordPress
105
+ attempted to make use of the cache, since FWP's caching plugin was written
106
+ to match the older idiom. FeedWordPress has been updated to follow the new,
107
+ PHP5 idiom when possible, thus eliminating the fatal error.
108
+
109
+ * PERFORMANCE: The handling of queries to determine whether posts had been
110
+ previously syndicated produced some very slow queries (usually, but not
111
+ always, involving a scan over the MD5(post_guid) column of the table). The
112
+ code that prepares MySQL queries for previously-syndicated checks has been
113
+ revised to eliminate the MD5(post_guid) scan entirely, and to significantly
114
+ improve performance by eliminating other unnecessary clauses.
115
+
116
+ * BUGFIX: NO LONGER DESTROYS STICKY POSTS. Previous versions could destroy
117
+ (or, more precisely, replace the content of) sticky posts due to some
118
+ queries mashed together in unexpected ways by WordPress. Version 2011.0706
119
+ accounts for and eliminates the problem; your sticky posts should be safe
120
+ once again.
121
+
122
+ * BUGFIX: GUIDS CONTAINING MYSQL-ESCAPED CHARACTERS NO LONGER CAUSE DUPLICATE
123
+ POSTS TO APPEAR. One remaining source of duplicate post issues in 2011.0602
124
+ was guids that contained characters that needed to be escaped for MySQL,
125
+ such as single quotes and double quotes. The work-around for handling
126
+ filtered URIs has now been corrected to ensure that these do not cause
127
+ duplicate posts.
128
+
129
  = 2011.0602 =
130
 
131
  * WP 3.1.3 COMPAT / BUGFIX: WHITESPACE IN GUIDS NO LONGER PRODUCES DUPLICATE
syndicatedlink.class.php CHANGED
@@ -165,6 +165,8 @@ class SyndicatedLink {
165
  } /* SyndicatedLink::found () */
166
 
167
  function stale () {
 
 
168
  $stale = true;
169
  if (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='ping')) :
170
  $stale = false; // don't update on any timed updates; pings only
@@ -172,6 +174,8 @@ class SyndicatedLink {
172
  $stale = true; // update on the next timed update
173
  elseif (!isset($this->settings['update/ttl']) or !isset($this->settings['update/last'])) :
174
  $stale = true; // initial update
 
 
175
  else :
176
  $after = ((int) $this->settings['update/last'])
177
  +((int) $this->settings['update/ttl'] * 60);
165
  } /* SyndicatedLink::found () */
166
 
167
  function stale () {
168
+ global $feedwordpress;
169
+
170
  $stale = true;
171
  if (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='ping')) :
172
  $stale = false; // don't update on any timed updates; pings only
174
  $stale = true; // update on the next timed update
175
  elseif (!isset($this->settings['update/ttl']) or !isset($this->settings['update/last'])) :
176
  $stale = true; // initial update
177
+ elseif ($feedwordpress->force_update_all()) :
178
+ $stale = true; // forced general updating
179
  else :
180
  $after = ((int) $this->settings['update/last'])
181
  +((int) $this->settings['update/ttl'] * 60);
syndicatedpost.class.php CHANGED
@@ -788,7 +788,6 @@ class SyndicatedPost {
788
  $guid = SyndicatedPost::normalize_guid_prefix().md5($guid);
789
  endif;
790
  $guid = trim($guid);
791
-
792
  return $guid;
793
  } /* SyndicatedPost::normalize_guid() */
794
 
@@ -1244,9 +1243,10 @@ class SyndicatedPost {
1244
 
1245
  $q = new WP_Query(array(
1246
  'fields' => '_synfresh', // id, guid, post_modified_gmt
 
1247
  'guid' => $this->guid(),
1248
  ));
1249
-
1250
  $old_post = NULL;
1251
  if ($q->have_posts()) :
1252
  while ($q->have_posts()) : $q->the_post();
@@ -1577,16 +1577,7 @@ class SyndicatedPost {
1577
  function normalize_post ($new = true) {
1578
  global $wpdb;
1579
 
1580
- $out = array();
1581
-
1582
- // Why the fuck doesn't wp_insert_post already do this?
1583
- foreach ($this->post as $key => $value) :
1584
- if (is_string($value)) :
1585
- $out[$key] = $wpdb->escape($value);
1586
- else :
1587
- $out[$key] = $value;
1588
- endif;
1589
- endforeach;
1590
 
1591
  $fullPost = $out['post_title'].$out['post_content'];
1592
  $fullPost .= (isset($out['post_excerpt']) ? $out['post_excerpt'] : '');
@@ -1609,6 +1600,16 @@ class SyndicatedPost {
1609
 
1610
  // Normalize the guid if necessary.
1611
  $out['guid'] = SyndicatedPost::normalize_guid($out['guid']);
 
 
 
 
 
 
 
 
 
 
1612
  return $out;
1613
  }
1614
 
788
  $guid = SyndicatedPost::normalize_guid_prefix().md5($guid);
789
  endif;
790
  $guid = trim($guid);
 
791
  return $guid;
792
  } /* SyndicatedPost::normalize_guid() */
793
 
1243
 
1244
  $q = new WP_Query(array(
1245
  'fields' => '_synfresh', // id, guid, post_modified_gmt
1246
+ 'ignore_sticky_posts' => true,
1247
  'guid' => $this->guid(),
1248
  ));
1249
+
1250
  $old_post = NULL;
1251
  if ($q->have_posts()) :
1252
  while ($q->have_posts()) : $q->the_post();
1577
  function normalize_post ($new = true) {
1578
  global $wpdb;
1579
 
1580
+ $out = $this->post;
 
 
 
 
 
 
 
 
 
1581
 
1582
  $fullPost = $out['post_title'].$out['post_content'];
1583
  $fullPost .= (isset($out['post_excerpt']) ? $out['post_excerpt'] : '');
1600
 
1601
  // Normalize the guid if necessary.
1602
  $out['guid'] = SyndicatedPost::normalize_guid($out['guid']);
1603
+
1604
+ // Why the fuck doesn't wp_insert_post already do this?
1605
+ foreach ($out as $key => $value) :
1606
+ if (is_string($value)) :
1607
+ $out[$key] = $wpdb->escape($value);
1608
+ else :
1609
+ $out[$key] = $value;
1610
+ endif;
1611
+ endforeach;
1612
+
1613
  return $out;
1614
  }
1615
 
syndicationdataqueries.class.php CHANGED
@@ -2,8 +2,9 @@
2
  class SyndicationDataQueries {
3
  function SyndicationDataQueries () {
4
  add_action('init', array(&$this, 'init'));
5
- add_filter('pre_get_posts', array(&$this, 'pre_get_posts'), 10, 1);
6
  add_filter('posts_search', array(&$this, 'posts_search'), 10, 2);
 
7
  add_filter('posts_fields', array(&$this, 'posts_fields'), 10, 2);
8
  add_filter('posts_request', array(&$this, 'posts_request'), 10, 2);
9
  }
@@ -13,15 +14,19 @@ class SyndicationDataQueries {
13
  $wp->add_query_var('guid');
14
  }
15
 
16
- function pre_get_posts (&$q) {
17
  if ($q->get('guid')) :
18
- $q->query_vars['post_type'] = get_post_types();
19
- $q->query_vars['post_status'] = implode(",", get_post_stati());
20
  endif;
21
 
22
  if ($q->get('fields') == '_synfresh') :
23
- $q->query_vars['cache_results'] = false; // Not suitable for caching.
24
  endif;
 
 
 
 
25
  }
26
 
27
  function posts_request ($sql, &$query) {
@@ -36,31 +41,45 @@ class SyndicationDataQueries {
36
  if ($guid = $query->get('guid')) :
37
  if (strlen(trim($guid)) > 0) :
38
  $seek = array($guid);
39
- $md5Seek = array();
40
 
41
  // MD5 hashes
42
  if (preg_match('/^[0-9a-f]{32}$/i', $guid)) :
43
- $md5Seek = array($guid);
44
  $seek[] = SyndicatedPost::normalize_guid_prefix().$guid;
45
  endif;
46
 
47
- // URLs that are invalid, or that WordPress just doesn't like
 
48
  $nGuid = SyndicatedPost::normalize_guid($guid);
49
  if ($guid != $nGuid) :
50
  $seek[] = $nGuid;
51
  endif;
52
 
 
 
 
53
  // Assemble
54
  $guidMatch = "(guid = '".implode("') OR (guid = '", $seek)."')";
55
- if (count($md5Seek) > 0) :
56
- $guidMatch .= " OR (MD5(guid) = '".implode("') OR (MD5(guid) = '", $md5Seek)."')";
57
- endif;
58
-
59
  $search .= $wpdb->prepare(" AND ($guidMatch)");
60
  endif;
61
  endif;
 
 
 
 
 
 
62
  return $search;
63
- } /* SyndicationDataQueries::posts_where () */
 
 
 
 
 
 
 
 
 
 
64
 
65
  function posts_fields ($fields, &$query) {
66
  global $wpdb;
2
  class SyndicationDataQueries {
3
  function SyndicationDataQueries () {
4
  add_action('init', array(&$this, 'init'));
5
+ add_action('parse_query', array(&$this, 'parse_query'), 10, 1);
6
  add_filter('posts_search', array(&$this, 'posts_search'), 10, 2);
7
+ add_filter('posts_where', array(&$this, 'posts_where'), 10, 2);
8
  add_filter('posts_fields', array(&$this, 'posts_fields'), 10, 2);
9
  add_filter('posts_request', array(&$this, 'posts_request'), 10, 2);
10
  }
14
  $wp->add_query_var('guid');
15
  }
16
 
17
+ function parse_query (&$q) {
18
  if ($q->get('guid')) :
19
+ $q->is_single = false; // Causes nasty side-effects.
20
+ $q->is_singular = true; // Doesn't?
21
  endif;
22
 
23
  if ($q->get('fields') == '_synfresh') :
24
+ $q->query_vars['cache_results'] = false; // Not suitable.
25
  endif;
26
+ } /* SyndicationDataQueries::parse_query () */
27
+
28
+ function pre_get_posts (&$q) {
29
+ //
30
  }
31
 
32
  function posts_request ($sql, &$query) {
41
  if ($guid = $query->get('guid')) :
42
  if (strlen(trim($guid)) > 0) :
43
  $seek = array($guid);
 
44
 
45
  // MD5 hashes
46
  if (preg_match('/^[0-9a-f]{32}$/i', $guid)) :
 
47
  $seek[] = SyndicatedPost::normalize_guid_prefix().$guid;
48
  endif;
49
 
50
+ // Invalid URIs, URIs that WordPress just doesn't like, and URIs
51
+ // that WordPress decides to munge.
52
  $nGuid = SyndicatedPost::normalize_guid($guid);
53
  if ($guid != $nGuid) :
54
  $seek[] = $nGuid;
55
  endif;
56
 
57
+ // Escape to prevent frak-ups, injections, etc.
58
+ $seek = array_map('esc_sql', $seek);
59
+
60
  // Assemble
61
  $guidMatch = "(guid = '".implode("') OR (guid = '", $seek)."')";
 
 
 
 
62
  $search .= $wpdb->prepare(" AND ($guidMatch)");
63
  endif;
64
  endif;
65
+
66
+ if ($query->get('fields')=='_synfresh') :
67
+ // Ugly hack to ensure we ONLY check by guid in syndicated freshness
68
+ // checks -- for reasons of both performance and correctness. Pitch:
69
+ $search .= " -- '";
70
+ endif;
71
  return $search;
72
+ } /* SyndicationDataQueries::posts_search () */
73
+
74
+ function posts_where ($where, &$q) {
75
+ // Ugly hack to ensure we ONLY check by guid in syndicated freshness
76
+ // checks -- for reasons of both performance and correctness. Catch:
77
+ if (strpos($where, " -- '") !== false) :
78
+ $bits = explode(" -- '", $where, 2);
79
+ $where = $bits[0];
80
+ endif;
81
+ return $where;
82
+ } /* SyndicationDataQueries::post_where () */
83
 
84
  function posts_fields ($fields, &$query) {
85
  global $wpdb;