diff --git a/wp-content/plugins/feedwordpress/feedfinder.class.php b/wp-content/plugins/feedwordpress/feedfinder.class.php index 97a85f58f57fd6671db061c6ad218521fcecf517..5837f3e6de08b5211eb4735a3ad12ccc79920d39 100644 --- a/wp-content/plugins/feedwordpress/feedfinder.class.php +++ b/wp-content/plugins/feedwordpress/feedfinder.class.php @@ -12,6 +12,7 @@ require_once(dirname(__FILE__).'/feedwordpresshtml.class.php'); class FeedFinder { var $uri = NULL; + var $credentials = NULL; var $_cache_uri = NULL; var $verify = FALSE; @@ -36,12 +37,51 @@ class FeedFinder { var $_obvious_feed_url = array('[./]rss', '[./]rdf', '[./]atom', '[./]feed', '\.xml'); var $_maybe_feed_url = array ('rss', 'rdf', 'atom', 'feed', 'xml'); - function FeedFinder ($uri = NULL, $verify = TRUE, $fallbacks = 3) { + function FeedFinder ($uri = NULL, $params = array(), $fallbacks = 3) { + if (is_bool($params)) : + $params = array("verify" => $params); + endif; + + $params = wp_parse_args($params, array( + "verify" => true, + "authentication" => NULL, + "username" => NULL, + "password" => NULL, + )); + $verify = $params['verify']; + $this->credentials = array( + "authentication" => $params['authentication'], + "username" => $params['username'], + "password" => $params['password'], + ); + $this->uri = $uri; $this->verify = $verify; $this->fallbacks = $fallbacks; } /* FeedFinder::FeedFinder () */ - function find ($uri = NULL) { + function find ($uri = NULL, $params = array()) { + $params = wp_parse_args($params, array( // Defaults + "authentication" => -1, + "username" => NULL, + "password" => NULL, + )); + + // Equivalents + if ($params['authentication']=='-') : + $params['authentication'] = NULL; + $params['username'] = NULL; + $params['password'] = NULL; + endif; + + // Set/reset + if ($params['authentication'] != -1) : + $this->credentials = array( + "authentication" => $params['authentication'], + "username" => $params['username'], + "password" => $params['password'], + ); + endif; + $ret = array (); if (!is_null($this->data($uri))) : if ($this->is_opml($uri)) : @@ -50,8 +90,8 @@ class FeedFinder { if ($this->is_feed($uri)) : $href = array($this->uri); else : - // Assume that we have HTML or XHTML (even if we don't, who's it gonna hurt?) - // Autodiscovery is the preferred method + // Assume that we have HTML or XHTML (even if we don't, who's + // it gonna hurt?) Autodiscovery is the preferred method. $href = $this->_link_rel_feeds(); // ... but we'll also take the little orange buttons @@ -66,8 +106,8 @@ class FeedFinder { endif; endif; - // Our search may turn up duplicate URIs. We only need to do any given URI once. - // Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414> + // Our search may turn up duplicate URIs. We only need to do + // any given URI once. Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414> $href = array_unique($href); endif; @@ -83,7 +123,7 @@ class FeedFinder { foreach ($href as $u) : $the_uri = SimplePie_Misc::absolutize_url($u, $this->uri); if ($this->verify and ($u != $this->uri and $the_uri != $this->uri)) : - $feed = new FeedFinder($the_uri); + $feed = new FeedFinder($the_uri, $this->credentials); if ($feed->is_feed()) : $ret[] = $the_uri; endif; unset($feed); else : @@ -91,7 +131,13 @@ class FeedFinder { endif; endforeach; endif; - + + if ($this->is_401($uri)) : + $ret = array_merge(array( + new WP_Error('http_request_failed', '401 Not authorized', array("uri" => $this->uri, "status" => 401)), + ), $ret); + endif; + return array_values($ret); } /* FeedFinder::find () */ @@ -128,6 +174,10 @@ class FeedFinder { return $message; } + function is_401 ($uri = NULL) { + return (intval($this->status($uri))==401); + } /* FeedFinder::is_401 () */ + function is_feed ($uri = NULL) { $data = $this->data($uri); @@ -163,9 +213,12 @@ class FeedFinder { $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress'; // Use WordPress API function - $client = wp_remote_request($this->uri, array( + $client = wp_remote_request($this->uri, array_merge( + $this->credentials, + array( 'headers' => $headers, 'timeout' => FeedWordPress::fetch_timeout(), + ) )); $this->_response = $client; diff --git a/wp-content/plugins/feedwordpress/feeds-page.php b/wp-content/plugins/feedwordpress/feeds-page.php index 3aa1c3bb73f22caf302e6f3c86f8dc368035cb42..ac62d18f88d41c3d7fd9cfb3f0df1ca843d55deb 100644 --- a/wp-content/plugins/feedwordpress/feeds-page.php +++ b/wp-content/plugins/feedwordpress/feeds-page.php @@ -193,11 +193,24 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { <option value="no"<?php echo (!$automatic_updates)?' selected="selected"':''; ?>>cron job or manual updates</option> </select> <div id="cron-job-explanation" class="setting-description"> - <p>If you want to use a cron job, + <p><?php + $path = `which curl`; $opts = '--silent %s'; + if (is_null($path) or strlen(trim($path))==0) : + $path = `which wget`; $opts = '-q -O - %s'; + if (is_null($path) or strlen(trim($path))==0) : + $path = '/usr/bin/curl'; $opts = '--silent %s'; + endif; + endif; + $path = preg_replace('/\n+$/', '', $path); + $crontab = `crontab -l`; + + $cmdline = $path . ' ' . sprintf($opts, get_bloginfo('url').'?update_feedwordpress=1'); + + ?>If you want to use a cron job, you can perform scheduled updates by sending regularly-scheduled - requests to <a href="<?php bloginfo('home'); ?>?update_feedwordpress=1"><code><?php bloginfo('url') ?>?update_feedwordpress=1</code></a> + requests to <a href="<?php bloginfo('url'); ?>?update_feedwordpress=1"><code><?php bloginfo('url') ?>?update_feedwordpress=1</code></a> For example, inserting the following line in your crontab:</p> - <pre style="font-size: 0.80em"><code>*/10 * * * * /usr/bin/curl --silent <?php bloginfo('url'); ?>?update_feedwordpress=1</code></pre> + <pre style="font-size: 0.80em"><code>*/10 * * * * <?php print esc_html($cmdline); ?></code></pre> <p class="setting-description">will check in every 10 minutes and check for updates on any feeds that are ready to be polled for updates.</p> </div> @@ -363,6 +376,65 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { ); } /* FeedWordPressFeedsPage::fetch_settings_box () */ + function display_authentication_credentials_box ($params = array()) { + static $count = 0; + + $params = wp_parse_args($params, array( + 'username' => NULL, + 'password' => NULL, + 'method' => '-', + )); + + // Equivalents + if (is_null($params['method'])) : $params['method'] = '-'; endif; + + $count++; + $slug = ($count > 1 ? '-'.$count : ''); + + global $feedwordpress; + $authMethods = apply_filters( + 'feedwordpress_http_auth_methods', + $feedwordpress->httpauth->methods_available() + ); + + if (count($authMethods) > 1) : /* More than '-' */ + ?> + <div class="link-rss-authentication" id="link-rss-authentication<?php print $slug; ?>"> + <table> + <tbody> + <tr class="link-rss-authentication-credentials" id="link-rss-authentication-credentials<?php print $slug; ?>"> + <td><label>user: <input type="text" name="link_rss_username" + value="<?php print esc_attr($params['username']); ?>" size="16" + placeholder="username to access this feed" /></label></td> + <td><label>pass: <input type="text" name="link_rss_password" + value="<?php print esc_attr($params['password']); ?>" size="16" + placeholder="password to access this feed" /></label></td> + <td class="link-rss-authentication-method" id="link-rss-authentication-method<?php print $slug; ?>"><label>method: <select class="link-rss-auth-method" id="link-rss-auth-method" name="link_rss_auth_method" size="1"> +<?php foreach ($authMethods as $value => $label) : ?> + <option value="<?php print esc_attr($value); ?>"<?php + if ($value == $params['method']) : ?> selected="selected"<?php + endif; ?>><?php print esc_html($label); ?></option> +<?php endforeach; ?> + </select></label></td> + </tr> + </tbody> + </table> + </div> + + <script type="text/javascript"> + jQuery('<td><a class="add-remove remove-it" id="link-rss-userpass-remove<?php print $slug; ?>" href="#"><span class="x">(X)</span> Remove</a></td>') + .appendTo('#link-rss-authentication-credentials<?php print $slug; ?>') + .click( feedAuthenticationMethodUnPress ); + jQuery('#link-rss-auth-method<?php print $slug; ?>').change( feedAuthenticationMethod ); + feedAuthenticationMethod({ + init: true, + node: jQuery('#link-rss-authentication<?php print $slug; ?>') }); + </script> + + <?php + endif; + } + function feed_information_box ($page, $box = NULL) { global $wpdb; $link_rss_params = maybe_unserialize($page->setting('query parameters', '')); @@ -412,7 +484,31 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { $hardcode['url'] = get_option('feedwordpress_hardcode_url'); endif; + $hideAuth = false; + + $username = $this->setting('http username', NULL); + + if (is_null($username)) : + $username = ''; + $hideAuth = true; + endif; + + $password = $this->setting('http password', NULL); + if (is_null($password)) : + $password = ''; + endif; + + $auth = $this->setting('http auth method', NULL); + + global $feedwordpress; + + if (is_null($auth)) : + $auth = '-'; + $hideAuth = true; + endif; + // Hey ho, let's go + ?> <table class="edit-form"> @@ -425,6 +521,12 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { title="Check feed <<?php echo esc_html($rss_url); ?>> for validity">validate</a>) <input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /> + <?php $this->display_authentication_credentials_box(array( + 'username' => $username, + 'password' => $password, + 'method' => $auth, + )); ?> + <table id="link-rss-params"> <tbody> <?php @@ -459,7 +561,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { jQuery('<td><a href="#" class="add-remove link-rss-params-remove"><span class="x">(X)</span> Remove</a></td>').insertAfter('.link-rss-params-value-cell'); jQuery('#link-rss-params-new').hide(); - jQuery('<a class="add-remove" id="link-rss-params-add" href="#">+ Add a query parameter</a>').insertAfter('#link-rss-params'); + jQuery('<a class="add-remove" id="link-rss-params-add" href="#">+ Add a query parameter</a>').insertAfter('#link-rss-params'); jQuery('#link-rss-params-add').click( function () { var next = jQuery('#link-rss-params-num').val(); var newRow = jQuery('#link-rss-params-new').clone().attr('id', 'link-rss-params-'+next); @@ -611,10 +713,35 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { <?php } + function url_for_401 ($err) { + $ret = NULL; + if (is_wp_error($err)) : + if ($err->get_error_code()=='http_request_failed') : + $data = $err->get_error_data('http_request_failed'); + + if (is_array($data) and isset($data['status'])) : + if (401==$data['status']) : + $ret = $data['uri']; + endif; + endif; + endif; + endif; + return $ret; + } + function display_feedfinder () { global $wpdb; $lookup = (isset($_REQUEST['lookup']) ? $_REQUEST['lookup'] : NULL); + + $auth = FeedWordPress::param('link_rss_auth_method'); + $username = FeedWordPress::param('link_rss_username'); + $password = FeedWordPress::param('link_rss_password'); + $credentials = array( + "authentication" => $auth, + "username" => $username, + "password" => $password, + ); $feeds = array(); $feedSwitch = false; $current = null; if ($this->for_feed_settings()) : // Existing feed? @@ -623,7 +750,11 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { // Switch Feed without a specific feed yet suggested // Go to the human-readable homepage to look for // auto-detection links + $lookup = $this->link->link->link_url; + $auth = $this->link->setting('http auth method'); + $username = $this->link->setting('http username'); + $password = $this->link->setting('http password'); // Guarantee that you at least have the option to // stick with what works. @@ -650,13 +781,13 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { $finder[$lookup] = new FeedFinder($lookup); foreach ($finder as $url => $ff) : - $feeds = array_merge($feeds, $ff->find()); + $feeds = array_merge($feeds, $ff->find( + /*url=*/ NULL, + /*params=*/ $credentials)); endforeach; $feeds = array_values( // Renumber from 0..(N-1) - array_unique( // Eliminate duplicates - $feeds - ) + $feeds ); if (count($feeds) > 0): @@ -679,10 +810,26 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { $form_class = ''; endif; + global $fwp_credentials; + foreach ($feeds as $key => $f): + $ofc = $fwp_credentials; + $fwp_credentials = $credentials; // Set $pie = FeedWordPress::fetch($f); + $fwp_credentials = $ofc; // Re-Set + $rss = (is_wp_error($pie) ? $pie : new MagpieFromSimplePie($pie)); + if ($this->url_for_401($pie)) : + $this->display_alt_feed_box($lookup, array( + "err" => $pie, + "auth" => $auth, + "username" => $username, + "password" => $password + )); + continue; + endif; + if ($rss and !is_wp_error($rss)): $feed_link = (isset($rss->channel['link'])?$rss->channel['link']:''); $feed_title = (isset($rss->channel['title'])?$rss->channel['title']:$feed_link); @@ -777,6 +924,11 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { <li><strong>Encoding:</strong> <?php echo isset($rss->encoding)?esc_html($rss->encoding):"<em>Unknown</em>"; ?></li> <li><strong>Description:</strong> <?php echo isset($rss->channel['description'])?esc_html($rss->channel['description']):"<em>Unknown</em>"; ?></li> </ul> + <?php $this->display_authentication_credentials_box(array( + 'username' => $username, + 'password' => $password, + 'method' => $auth, + )); ?> <?php do_action('feedwordpress_feedfinder_form', $f, $post, $link, $this->for_feed_settings()); ?> <div class="submit"><input type="submit" class="button-primary" name="Use" value="« Use this feed" /> <input type="submit" class="button" name="Cancel" value="× Cancel" /></div> @@ -810,12 +962,26 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { // Do some more diagnostics if the API for it is available. if (function_exists('_wp_http_get_object')) : $httpObject = _wp_http_get_object(); - $transports = $httpObject->_getTransport(); - - print "<h4>".__('HTTP Transports available').":</h4>\n"; - print "<ol>\n"; - print "<li>".implode("</li>\n<li>", array_map('get_class', $transports))."</li>\n"; - print "</ol>\n"; + + if (is_callable(array($httpObject, '_getTransport'))) : + $transports = $httpObject->_getTransport(); + + print "<h4>".__('HTTP Transports available').":</h4>\n"; + print "<ol>\n"; + print "<li>".implode("</li>\n<li>", array_map('get_class', $transports))."</li>\n"; + print "</ol>\n"; + elseif (is_callable(array($httpObject, '_get_first_available_transport'))) : + $transport = $httpObject->_get_first_available_transport( + array(), + $url + ); + + print "<h4>".__("HTTP Transport").":</h4>\n"; + print "<ol>\n"; + print "<li>".FeedWordPress::val($transport)."</li>\n"; + print "</ol>\n"; + endif; + print "</div>\n"; endif; endforeach; @@ -830,8 +996,22 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { return false; // Don't continue } /* FeedWordPressFeedsPage::display_feedfinder() */ - function display_alt_feed_box ($lookup, $alt = false) { + function display_alt_feed_box ($lookup, $params = false) { global $fwp_post; + + if (is_bool($params)) : + $params = array("alt" => $params); + endif; + + $params = wp_parse_args($params, array( // Defaults + "alt" => false, + "err" => NULL, + "auth" => NULL, + "password" => NULL, + "username" => NULL, + )); + $alt = $params['alt']; + ?> <form action="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/<?php echo basename(__FILE__); ?>" method="post"> <div class="inside"><?php @@ -841,6 +1021,14 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { <?php if (!$alt): ?>style="margin: 1.0em 3.0em; font-size: smaller;"<?php endif; ?>> <legend><?php if ($alt) : ?>Alternative feeds<?php else: ?>Find feeds<?php endif; ?></legend> <?php if ($alt) : ?><h3>Use a different feed</h3><?php endif; ?> + <?php if (is_wp_error($params['err'])) : + ?> + <p><em><strong>401 Not Authorized.</strong> This URL may require + a username and password to access it.</em> You may want to add login + credentials below and check it again.</p> + <?php + endif; + ?> <div><label>Address: <input type="text" name="lookup" id="use-another-feed" placeholder="URL" @@ -853,9 +1041,17 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { <?php if (is_null($lookup)) : ?> <?php FeedWordPressSettingsUI::magic_input_tip_js('use-another-feed'); ?> <?php endif; ?> + <?php $this->stamp_link_id('link_id'); ?> <input type="hidden" name="action" value="feedfinder" /> <input type="submit" class="button<?php if ($alt): ?>-primary<?php endif; ?>" value="Check »" /></div> + + <?php $this->display_authentication_credentials_box(array( + 'username' => $params['username'], + 'password' => $params['password'], + 'method' => $params['auth'], + )); ?> + <p>This can be the address of a feed, or of a website. FeedWordPress will try to automatically detect any feeds associated with a website.</p> @@ -867,6 +1063,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { function save_settings ($post) { if ($this->for_feed_settings()) : + if (isset($post['link_rss_params_key'])) : $qp = array(); foreach ($post['link_rss_params_key'] as $index => $key) : @@ -968,8 +1165,39 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { if (isset($post['update_minimum'])) : $this->update_setting('update/minimum', $post['update_minimum']); endif; + + if ( + isset($post['link_rss_auth_method']) + and $post['link_rss_auth_method'] + and ('-' != $post['link_rss_auth_method']) + ) : + $this->update_setting('http auth method', $post['link_rss_auth_method']); + else : + $this->update_setting('http auth method', NULL); + endif; + + if ( + isset($post['link_rss_username']) + and (strlen($post['link_rss_username']) > 0) + and ('-' != $post['link_rss_auth_method']) + ) : + $this->update_setting('http username', $post['link_rss_username']); + else : + $this->update_setting('http username', NULL); + endif; + + if ( + isset($post['link_rss_password']) + and (strlen($post['link_rss_password']) > 0) + and ('-' != $post['link_rss_auth_method']) + ) : + $this->update_setting('http password', $post['link_rss_password']); + else : + $this->update_setting('http password', NULL); + endif; $this->updatedPosts->accept_POST($post); + parent::save_settings($post); } /* FeedWordPressFeedsPage::save_settings() */ diff --git a/wp-content/plugins/feedwordpress/feedwordpress-elements.css b/wp-content/plugins/feedwordpress/feedwordpress-elements.css index f575a51fb741b8c4dd8c478713f5299730f0b10f..9e92b099cf0230f3fd952d02dfcc07ca82e27f5a 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress-elements.css +++ b/wp-content/plugins/feedwordpress/feedwordpress-elements.css @@ -387,6 +387,24 @@ table.twofer td.secondary { padding-left: 10px; width: 30%; } vertical-align: middle; } +#link-rss-userpass-use, .link-rss-authentication table { + display: block; + font-size: 75%; + white-space: nowrap; + padding: 0.5em 0; +} +#feed-finder .link-rss-authentication table { + font-size: inherit; +} + +#link-rss-authentication label { + font-weight: bold; + padding-left: 1.5em; +} +#link-rss-authentication td { + width: 25%; +} + #feedwordpress-admin-feeds .link-rss-params-row { vertical-align: middle; } #feedwordpress-admin-feeds .link-rss-params-remove, .feedwordpress-admin .remove-it { display: block; diff --git a/wp-content/plugins/feedwordpress/feedwordpress-elements.js b/wp-content/plugins/feedwordpress/feedwordpress-elements.js index 50333aba83eddb218dab711926ee1b46cb8ede26..fa793373b25a1e888d1b6b9202c35778cd2b97e5 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress-elements.js +++ b/wp-content/plugins/feedwordpress/feedwordpress-elements.js @@ -368,6 +368,65 @@ $.fn.fwpList = function( settings ) { })(jQuery); +/** + * Admin interface: Uses Username/Parameter UI for Feed Settings. + * + */ +function feedAuthenticationMethodPress (params) { + feedAuthenticationMethod({value: 'basic', node: jQuery(this)}); + return false; +} +function feedAuthenticationMethodUnPress (params) { + feedAuthenticationMethod({value: '-', node: jQuery(this)}); + return false; +} +function feedAuthenticationMethod (params) { + var s = jQuery.extend({}, { + init: false, + value: null, + node: jQuery(this) + }, params); + + var speed = (s.init ? 0 : 'slow'); + + var elDiv = jQuery(s.node).closest('.link-rss-authentication'); + var elTable = elDiv.find('table'); + var elMethod = elTable.find('.link-rss-auth-method'); + var elLink = elDiv.find('.link-rss-userpass-use'); + + console.log('--- ---'); + console.log(s.node); + console.log(elDiv); + console.log(elTable); + console.log(elMethod); + console.log(elLink); + console.log(elMethod.val()); + + // Set. + if (s.value != null) { + elMethod.val(s.value); + } + + if (elMethod.val()=='-') { + elTable.hide(speed, function () { + // Just in case. Make sure that we don't duplicate. + elLink.remove(); + + jQuery('<a style="display: none" class="add-remove link-rss-userpass-use" href="#">+ Uses username/password</a>') + .insertAfter(elTable) + .click(feedAuthenticationMethodPress) + .show(speed); + }); + } else { + elLink.hide(speed, function () { jQuery(this).remove(); } ); + elTable.show(speed); + } /* if */ +} /* function feedAuthenticationMethod () */ + +/** + * Admin interface: Live category and tag boxes + */ + jQuery(document).ready( function($) { // Category boxes $('.feedwordpress-category-div').each( function () { diff --git a/wp-content/plugins/feedwordpress/feedwordpress.php b/wp-content/plugins/feedwordpress/feedwordpress.php index 310f9bd8f8e96ed831e21a2f5bb75a7b9063f67c..fbccc1c65961df747cf244d8ff1b7f5ecbc43dfe 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress.php +++ b/wp-content/plugins/feedwordpress/feedwordpress.php @@ -3,7 +3,7 @@ Plugin Name: FeedWordPress Plugin URI: http://feedwordpress.radgeek.com/ Description: simple and flexible Atom/RSS syndication for WordPress -Version: 2011.0721 +Version: 2011.1019 Author: Charles Johnson Author URI: http://radgeek.com/ License: GPL @@ -11,7 +11,7 @@ License: GPL /** * @package FeedWordPress - * @version 2011.0721 + * @version 2011.1019 */ # This uses code derived from: @@ -34,7 +34,7 @@ License: GPL # -- Don't change these unless you know what you're doing... -define ('FEEDWORDPRESS_VERSION', '2011.0721'); +define ('FEEDWORDPRESS_VERSION', '2011.1019'); define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact'); if (!defined('FEEDWORDPRESS_BLEG')) : @@ -122,6 +122,7 @@ require_once("${dir}/syndicationdataqueries.class.php"); require_once("${dir}/feedwordpress_file.class.php"); require_once("${dir}/feedwordpress_parser.class.php"); require_once("${dir}/feedwordpressrpc.class.php"); +require_once("${dir}/feedwordpresshttpauthenticator.class.php"); // Magic quotes are just about the stupidest thing ever. if (is_array($_POST)) : @@ -144,24 +145,6 @@ else : // Something went wrong. Let's just guess. $fwp_path = 'feedwordpress'; endif; -// If this is a FeedWordPress admin page, queue up scripts for AJAX functions that FWP uses -// If it is a display page or a non-FeedWordPress admin page, don't. -wp_register_style('feedwordpress-elements', WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-elements.css'); -if (FeedWordPressSettingsUI::is_admin()) : - // For JavaScript that needs to be generated dynamically - add_action('admin_print_scripts', array('FeedWordPressSettingsUI', 'admin_scripts')); - - // For CSS that needs to be generated dynamically. - add_action('admin_print_styles', array('FeedWordPressSettingsUI', 'admin_styles')); - - wp_enqueue_style('dashboard'); - wp_enqueue_style('feedwordpress-elements'); - - if (function_exists('wp_admin_css')) : - wp_admin_css('css/dashboard'); - endif; -endif; - if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe! # Syndicated items are generally received in output-ready (X)HTML and @@ -915,6 +898,7 @@ class FeedWordPress { var $feeds = NULL; + var $httpauth = NULL; # function FeedWordPress (): Contructor; retrieve a list of feeds function FeedWordPress () { $this->feeds = array (); @@ -922,6 +906,8 @@ class FeedWordPress { if ($links): foreach ($links as $link): $this->feeds[] = new SyndicatedLink($link); endforeach; endif; + + $this->httpauth = new FeedWordPressHTTPAuthenticator; } // FeedWordPress::FeedWordPress () # function update (): polls for updates on one or more Contributor feeds @@ -998,13 +984,22 @@ class FeedWordPress { if (is_null($crash_ts)) : $crash_ts = $this->crash_ts(); endif; - - $max_polls = apply_filters('feedwordpress_polls_per_update', get_option('feedwordpress_polls_per_update', 10), $uri); // Randomize order for load balancing purposes $feed_set = $this->feeds; shuffle($feed_set); + $updateWindow = (int) get_option('feedwordpress_update_window', DEFAULT_UPDATE_PERIOD) * 60 /* sec/min */; + $interval = (int) get_option('feedwordpress_freshness', FEEDWORDPRESS_FRESHNESS_INTERVAL); + $portion = max( + (int) ceil(count($feed_set) / ($updateWindow / $interval)), + 10 + ); + + $max_polls = apply_filters('feedwordpress_polls_per_update', get_option( + 'feedwordpress_polls_per_update', $portion + ), $uri); + $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri); // Loop through and check for new posts @@ -1163,6 +1158,27 @@ class FeedWordPress { } // FeedWordPress::stale() function init () { + global $fwp_path; + + // If this is a FeedWordPress admin page, queue up scripts for AJAX + // functions that FWP uses. If it is a display page or a non-FWP admin + // page, don't. + wp_register_style('feedwordpress-elements', WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-elements.css'); + if (FeedWordPressSettingsUI::is_admin()) : + // For JavaScript that needs to be generated dynamically + add_action('admin_print_scripts', array('FeedWordPressSettingsUI', 'admin_scripts')); + + // For CSS that needs to be generated dynamically. + add_action('admin_print_styles', array('FeedWordPressSettingsUI', 'admin_styles')); + + wp_enqueue_style('dashboard'); + wp_enqueue_style('feedwordpress-elements'); + + if (function_exists('wp_admin_css')) : + wp_admin_css('css/dashboard'); + endif; + endif; + $this->clear_cache_magic_url(); $this->update_magic_url(); } /* FeedWordPress::init() */ @@ -1566,6 +1582,11 @@ class FeedWordPress { } /*static*/ function fetch ($url, $params = array()) { + if (is_wp_error($url)) : + // Let's bounce. + return $url; + endif; + $force_feed = true; // Default // Allow user to change default feed-fetch timeout with a global setting. Props Erigami Scholey-Fuller <http://www.piepalace.ca/blog/2010/11/feedwordpress-broke-my-heart.html> 'timeout' => @@ -1574,7 +1595,7 @@ class FeedWordPress { if (!is_array($params)) : $force_feed = $params; else : // Parameter array - $args = shortcode_atts(array( + $args = wp_parse_args(array( 'force_feed' => $force_feed, 'timeout' => $timeout ), $params); diff --git a/wp-content/plugins/feedwordpress/feedwordpress_file.class.php b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php index 70a9edffe2d889546cb4dc0ea643e3d58a01e910..c78bbbd6329ee9425ef796de9cc6b6a49125405d 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress_file.class.php +++ b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php @@ -1,16 +1,72 @@ <?php +$GLOBALS['fwp_credentials'] = NULL; + class FeedWordPress_File extends WP_SimplePie_File { function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { self::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); } function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { - if (is_callable(array('WP_SimplePie_File', 'WP_SimplePie_File'))) : // PHP 4 idiom - WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - else : // PHP 5+ - parent::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - endif; + $this->url = $url; + $this->timeout = $timeout; + $this->redirects = $redirects; + $this->headers = $headers; + $this->useragent = $useragent; + + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE; + + global $wpdb; + global $fwp_credentials; + if ( preg_match('/^http(s)?:\/\//i', $url) ) { + $args = array( 'timeout' => $this->timeout, 'redirection' => $this->redirects); + + if ( !empty($this->headers) ) + $args['headers'] = $this->headers; + + if ( SIMPLEPIE_USERAGENT != $this->useragent ) //Use default WP user agent unless custom has been specified + $args['user-agent'] = $this->useragent; + + // This is ugly as hell, but communicating up and down the chain + // in any other way is difficult. + + if (!is_null($fwp_credentials)) : + + $args['authentication'] = $fwp_credentials['authentication']; + $args['username'] = $fwp_credentials['username']; + $args['password'] = $fwp_credentials['password']; + + else : + + $links = $wpdb->get_results( + $wpdb->prepare("SELECT * FROM {$wpdb->links} WHERE link_rss = '%s'", $url) + ); + if ($links) : + $source = new SyndicatedLink($links[0]); + $args['authentication'] = $source->authentication_method(); + $args['username'] = $source->username(); + $args['password'] = $source->password(); + endif; + + endif; + + $res = wp_remote_request($url, $args); + + if ( is_wp_error($res) ) { + $this->error = 'WP HTTP Error: ' . $res->get_error_message(); + $this->success = false; + } else { + $this->headers = wp_remote_retrieve_headers( $res ); + $this->body = wp_remote_retrieve_body( $res ); + $this->status_code = wp_remote_retrieve_response_code( $res ); + } + } else { + if ( ! $this->body = file_get_contents($url) ) { + $this->error = 'file_get_contents could not read the file'; + $this->success = false; + } + } + // SimplePie makes a strongly typed check against integers with // this, but WordPress puts a string in. Which causes caching // to break and fall on its ass when SimplePie is getting a 304, diff --git a/wp-content/plugins/feedwordpress/feedwordpresshttpauthenticator.class.php b/wp-content/plugins/feedwordpress/feedwordpresshttpauthenticator.class.php new file mode 100644 index 0000000000000000000000000000000000000000..7434f1e6250fad1b94527b670d762c81340b8891 --- /dev/null +++ b/wp-content/plugins/feedwordpress/feedwordpresshttpauthenticator.class.php @@ -0,0 +1,169 @@ +<?php +class FeedWordPressHTTPAuthenticator { + var $args = array(); + + function FeedWordPressHTTPAuthenticator () { + self::__construct(); + } + + function __construct () { + add_filter('use_curl_transport', array(&$this, 'digest_do_it'), 2, 1000); + foreach (array('fsockopen', 'fopen', 'streams', 'http_extension') as $transport) : + add_filter("use_{$transport}_transport", array(&$this, 'digest_dont'), 2, 1000); + endforeach; + + add_filter('pre_http_request', array(&$this, 'pre_http_request'), 10, 3); + add_action('http_api_curl', array(&$this, 'set_auth_options'), 1000, 1); + } /* FeedWordPressHTTPAuthenticator::__construct () */ + + function methods_available () { + $methods = array('-' => 'None'); + + if ($this->have_curl(array('authentication' => 'digest'))) : + $methods = array_merge(array( + 'digest' => 'Digest', + ), $methods); + endif; + + if ( + $this->have_curl(array('authentication' => 'basic')) + or $this->have_streams(array('authentication' => 'basic')) + ) : + $methods = array_merge(array( + 'basic' => 'Basic', + ), $methods); + endif; + + return $methods; + } + + function pre_http_request ($pre, $args, $url) { + $this->args = wp_parse_args($args, array( + 'authentication' => NULL, + 'username' => NULL, + 'password' => NULL, + )); + + // Ruh roh... + if (!is_null($this->args['authentication'])) : + switch ($this->args['authentication']) : + case '-' : + // No HTTP Auth method. Remove this stuff. + $this->args['authentication'] = NULL; + $this->args['username'] = NULL; + $this->args['password'] = NULL; + break; + case 'basic' : + if ($this->have_curl($args, $url)) : + // Don't need to do anything. http_api_curl hook takes care + // of it. + break; + elseif ($this->have_streams($args, $url)) : + // curl has a nice native way to jam in the username and + // passwd but streams and fsockopen do not. So we have to + // make a recursive call with the credentials in the URL. + // Wee ha! + $method = $this->args['authentication']; + $credentials = $this->args['username']; + if (!is_null($this->args['password'])) : + $credentials .= ':'.$args['password']; + endif; + + // Remove these so we don't recurse all the way down + unset($this->args['authentication']); + unset($this->args['username']); + unset($this->args['password']); + + $url = preg_replace('!(https?://)!', '$1'.$credentials.'@', $url); + + // Subsidiary request + $pre = wp_remote_request($url, $this->args); + break; + endif; + case 'digest' : + if ($this->have_curl($args, $url)) : + // Don't need to do anything. http_api_curl hook takes care + // of it. + break; + endif; + default : + if (is_callable('WP_Http', '_get_first_available_transport')) : + $trans = WP_Http::_get_first_available_transport($args, $url); + if (!$trans) : + $trans = WP_Http::_get_first_available_transport(array(), $url); + endif; + elseif (is_callable('WP_Http', '_getTransport')) : + $transports = WP_Http::_getTransport($args); + $trans = get_class(reset($transports)); + else : + $trans = 'HTTP'; + endif; + + $pre = new WP_Error('http_request_failed', + sprintf( + __('%s cannot use %s authentication with the %s transport.'), + __CLASS__, + $args['authentication'], + $trans + ) + ); + endswitch; + endif; + return $pre; + } /* FeedWordPressHTTPAuthenticator::pre_http_request () */ + + function have_curl ($args, $url = NULL) { + return WP_Http_Curl::test($args); + } + + function have_streams ($args, $url = NULL) { + return WP_Http_Streams::test($args); + } + + function need_curl ($args) { + $args = wp_parse_args($args, array( + 'authentication' => NULL, + )); + + switch ($args['authentication']) : + case 'digest' : + $use = true; + break; + default : + $use = false; + endswitch; + return $use; + } /* FeedWordPressHTTPAuthenticator::need_curl () */ + + function digest_do_it ($use, $args) { + return $this->if_curl($use, $args, true); + } /* FeedWordPerssHTTPAuthenticator::digest_do_it () */ + + function digest_dont ($use, $args) { + return $this->if_curl($use, $args, false); + } /* FeedWordPressHTTPAuthenticator::digest_dont () */ + + function if_curl ($use, $args, $what) { + if ($this->need_curl($args)) : + $use = $what; + endif; + return $use; + } /* FeedWordPressHTTPAuthenticator::if_curl () */ + + function set_auth_options (&$handle) { + if ('digest'==$this->args['authentication']) : + curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + endif; + + if (!is_null($this->args['username'])) : + $userPass = $this->args['username']; + if (!is_null($this->args['password'])) : + $userPass .= ':'.$this->args['password']; + endif; + + curl_setopt($handle, CURLOPT_USERPWD, $userPass); + endif; + + } /* FeedWordPressHTTPAuthenticator::set_auth_options() */ + +} /* class FeedWordPressHTTPAuthenticator */ diff --git a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php index 71e060ef6f8ba32a5417cb1a9c5be91a9631271e..3a08b094258922e7cbbfdbdc93d2c5111cb82bed 100644 --- a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php +++ b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php @@ -207,6 +207,8 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage { if (isset($_FILES['opml_upload']['name']) and (strlen($_FILES['opml_upload']['name']) > 0)) : $in = 'tag:localhost'; + + /*FIXME: check whether $_FILES['opml_upload']['error'] === UPLOAD_ERR_OK or not...*/ $localData = file_get_contents($_FILES['opml_upload']['tmp_name']); $merge_all = true; elseif (isset($fwp_post['multilookup'])) : @@ -1117,6 +1119,7 @@ function fwp_switchfeed_page () { $link_id = FeedWordPress::syndicate_link($fwp_post['feed_title'], $fwp_post['feed_link'], $fwp_post['feed']); if ($link_id): $existingLink = new SyndicatedLink($link_id); + ?> <div class="updated"><p><a href="<?php print $fwp_post['feed_link']; ?>"><?php print esc_html($fwp_post['feed_title']); ?></a> has been added as a contributing site, using the feed at @@ -1141,7 +1144,22 @@ updated to <<a href="<?php echo esc_html($fwp_post['feed']); ?>"><?php echo e endif; if (isset($existingLink)) : + $auth = FeedWordPress::post('link_rss_auth_method'); + if (!is_null($auth) and $auth != '-') : + $existingLink->update_setting('http auth method', $auth); + $existingLink->update_setting('http username', + FeedWordPress::post('link_rss_username') + ); + $existingLink->update_setting('http password', + FeedWordPress::post('link_rss_password') + ); + else : + $existingLink->update_setting('http auth method', NULL); + $existingLink->update_setting('http username', NULL); + $existingLink->update_setting('http password', NULL); + endif; do_action('feedwordpress_admin_switchfeed', $fwp_post['feed'], $existingLink); + $existingLink->save_settings(/*reload=*/ true); endif; if (!$changed) : diff --git a/wp-content/plugins/feedwordpress/readme.txt b/wp-content/plugins/feedwordpress/readme.txt index 97e4bbca30350ca02ccbd295a9fd08b0e4eeb3b0..d4bb3f2b635754a3c01a6d21cafb4780f5524644 100644 --- a/wp-content/plugins/feedwordpress/readme.txt +++ b/wp-content/plugins/feedwordpress/readme.txt @@ -3,8 +3,8 @@ Contributors: Charles Johnson Donate link: http://feedwordpress.radgeek.com/ Tags: syndication, aggregation, feed, atom, rss Requires at least: 3.0 -Tested up to: 3.2 -Stable tag: 2011.0721 +Tested up to: 3.2.1 +Stable tag: 2011.1019 FeedWordPress syndicates content from feeds you choose into your WordPress weblog. @@ -94,6 +94,64 @@ outs, see the documentation at the [FeedWordPress project homepage][]. == Changelog == += 2011.1019 = + +* BUGFIX: "THERE ARE NO HTTP TRANSPORTS AVAILABLE" ERROR FIXED: The initial + support for HTTP Basic and Digest authentication in version 2011.1018 + contained a bug that could cause HTTP requests for feeds or for other + WordPress resources to break down if you do not have the PHP curl module + installed. This bug has been fixed, and these errors should no longer + appear. + +* IMPROVED HTTP AUTHENTICATION SUPPORT: In addition, the HTTP Authentication + support in FeedWordPress has been extended, to ensure that Basic + authentication is available in many web host configurations, and to allow + you to add a username and password for a feed immediately when you + subscribe to it. + += 2011.1018 = + +* HTTP BASIC AND DIGEST AUTHENTICATION SUPPORT: FeedWordPress now offers + improved support for syndicating feeds that make use of HTTP Basic or HTTP + Digest authentication methods. In order to set up authentication on one of + your feeds, just go to its Settings > Feed page, and click on the "Uses + Username/Password" link underneath the Feed URL. Enter the username and + password for accessing the feed, then select the authentication method. (If + you're not sure which method your feed provider uses, try Basic first.) + Save Changes, and syndicate away. + + NOTE: HTTP Digest support requires the curl module for PHP. If you are not + sure whether this module has been installed, contact your web hosting + provider to check. + +* WP 3.3 (BETA) COMPATIBILITY: This version fixes an init-sequence bug that + could cause intrusive warning messages or fatal errors in WP 3.3 beta + versions. + +* BUGFIX: FIXES LONG DELAYS IN UPDATES SCHEDULES IN LARGE INSTALLATIONS. A + performance feature introduced in version 2011.0721 had some flaws in its + implementation, which tended to create serious delays (on the order of + several hours) in FeedWordPress's attempts to schedule updates for feeds, + when users had a very large number of feeds (several dozen or more) in their + FeedWordPress installation. This feature has been reconfigured to adjust + dynamically to the number of feeds in Syndicated Sources and the frequency + with which they are updated. If you've seen a lot of ready-to-update feeds + piling up, several hours after they were supposed to get updated, then this + upgrade should better ensure that your feeds get updated in a timely fashion. + +* BUGFIX: syndicated_item_guid FILTERS FIXED. Previous versions of + FeedWordPress theoretically allowed for filters on the syndicated_item_guid + hook, which was intended to filter the globally-unique identifier element + (rss:guid or atom:id) -- useful if you need to convince FeedWordPress to use + different guids, or to recognize two or more incoming posts as versions of + the same post rather than as distinct items. However, while the hook + affected the guid stored in the WordPress database, it did not affect the + guid used to check whether an incoming feed item had already been syndicated + or was a new item -- which greatly limited the practical usefulness of the + filter. This bug has been fixed: syndicated_item_guid filters should now + properly control not only the final database record, but also the initial + uniqueness test applied to posts. + = 2011.0721 = * BUGFIX: SERIOUS BUG CAUSING RARE UNEXPECTED DELETION OF PAGES AND OTHER @@ -124,7 +182,7 @@ outs, see the documentation at the [FeedWordPress project homepage][]. specific scheduling decisions are made because of, e.g., requests from the feed producer. -* FEED UPDATE SCHEDULING IMPROVEMENTS: ENFORCEABLE "MINIMUM INTERVAL" SETTIN +* FEED UPDATE SCHEDULING IMPROVEMENTS: ENFORCEABLE "MINIMUM INTERVAL" SETTING TO SPACE OUT UPDATES. Some feeds request specific update schedules, using standard elements such as sy:updateFrequency and rss:ttl. Normally, FeedWordPress respects any scheduling requests that a feed makes -- if it diff --git a/wp-content/plugins/feedwordpress/syndicatedlink.class.php b/wp-content/plugins/feedwordpress/syndicatedlink.class.php index 735bd6e09a9cfefe176445c766b44c470eb29d83..93b809c428bcee2a06604b2e5bdae28990f449df 100644 --- a/wp-content/plugins/feedwordpress/syndicatedlink.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedlink.class.php @@ -630,6 +630,22 @@ class SyndicatedLink { return $uri; } /* SyndicatedLink::uri () */ + function username () { + return $this->setting('http username', 'http_username', NULL); + } /* SyndicatedLink::username () */ + + function password () { + return $this->setting('http password', 'http_password', NULL); + } /* SyndicatedLink::password () */ + + function authentication_method () { + $auth = $this->setting('http auth method', NULL); + if (('-' == $auth) or (strlen($auth)==0)) : + $auth = NULL; + endif; + return $auth; + } /* SyndicatedLink::authentication_method () */ + function property_cascade ($fromFeed, $link_field, $setting, $simplepie_method) { $value = NULL; if ($fromFeed) : diff --git a/wp-content/plugins/feedwordpress/syndicatedpost.class.php b/wp-content/plugins/feedwordpress/syndicatedpost.class.php index e96869e572e8a5602a6c88a7c47a6e6a36451cb2..2c46841023429f6a99476d16521775364a4c4d3e 100644 --- a/wp-content/plugins/feedwordpress/syndicatedpost.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedpost.class.php @@ -10,7 +10,7 @@ require_once(dirname(__FILE__).'/feedtime.class.php'); * different feed formats, which may be useful to FeedWordPress users * who make use of feed data in PHP add-ons and filters. * - * @version 2011.0601 + * @version 2011.0831 */ class SyndicatedPost { var $item = null; // MagpieRSS representation @@ -1239,12 +1239,13 @@ class SyndicatedPost { endif; if (is_null($this->_freshness)) : // Not yet checked and cached. - $guid = $wpdb->escape($this->guid()); + $guid = $this->post['guid']; + $eguid = $wpdb->escape($this->post['guid']); $q = new WP_Query(array( 'fields' => '_synfresh', // id, guid, post_modified_gmt 'ignore_sticky_posts' => true, - 'guid' => $this->guid(), + 'guid' => $guid, )); $old_post = NULL; @@ -1255,7 +1256,7 @@ class SyndicatedPost { endif; if (is_null($old_post)) : // No post with this guid - FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a NEW POST.'); + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$guid.'] "'.$this->entry->get_title().'" is a NEW POST.'); $this->_wp_id = NULL; $this->_freshness = 2; // New content else : @@ -1293,7 +1294,7 @@ class SyndicatedPost { $updated = ($updated and !$frozen); if ($updated) : - FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is an update of an existing post.'); + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$guid.'] "'.$this->entry->get_title().'" is an update of an existing post.'); $this->_freshness = 1; // Updated content $this->_wp_id = $old_post->ID; @@ -1304,7 +1305,7 @@ class SyndicatedPost { array($this->update_hash()) ); else : - FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a duplicate of an existing post.'); + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$guid.'] "'.$this->entry->get_title().'" is a duplicate of an existing post.'); $this->_freshness = 0; // Same old, same old $this->_wp_id = $old_post->ID; endif;