I assume you mean fetching an external feed with an HTTP authentication.
Fetching feeds with HTTP Authentication
Note that fetch_rss()
uses the MagPie library, that’s deprecated in WordPress.
Use instead fetch_feed()
that uses the SimplePie library.
It looks though it doesn’t support this kind of url:
http://user:[email protected]/feed/
like we can use with curl
in command-line, e.g.:
# curl -i http://user:[email protected]/feed/
The fetch_feed()
function calls the wp_safe_remote_request()
function, to fetch the feed. This is happens in the WP_SimplePie_File
class, that’s an extension of the SimplePie_File
class.
That’s good news, because it means we can use the http_request_args
filter, to modify the request headers. If we check out the Codex page on the HTTP API, we see that in the external references, that there’s a link to John Blackbourn’s short but informative post about Basic Authentication with the WordPress HTTP API. There he gives the following example:
$args = array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( YOUR_USERNAME . ':' . YOUR_PASSWORD )
)
);
wp_remote_request( $url, $args );
to send the correct authentication header with the request.
Demo plugin
We can now add a support for the following url type:
$rss = fetch_feed( 'http://user:[email protected]/feed/' );
with the this demo plugin:
<?php
/**
* Plugin Name: Fetch Feeds with http authentication
* Description: Allows feeds urls like http://user:[email protected]/feed/
* Plugin URI: http://wordpress.stackexchange.com/a/199101/26350
*/
add_action( 'wp_feed_options', function( $feed, $url )
{
$user = parse_url( $feed->feed_url, PHP_URL_USER );
$pass = parse_url( $feed->feed_url, PHP_URL_PASS );
// Nothing to do
if( ! $user || ! $pass )
return;
// Remove the user:pass@ part from the feed url
$feed->feed_url = str_replace(
sprintf( '%s:%s@', $user, $pass ),
'',
$feed->feed_url
);
add_filter( 'http_request_args', function( $r, $url ) use ( $user, $pass )
{
// Add the user & pass to the request's header
if( $user && $pass )
$r['headers']['Authorization'] = 'Basic ' . base64_encode( $user . ':' . $pass );
return $r;
}, 10, 2 );
}, 10, 2 );
Update:
This is how the error looks like:
WP HTTP Error: A valid URL was not provided.
when we run:
$rss = fetch_feed( 'http://user:[email protected]/feed/' );
It comes from the WP_Http::request()
method:
if ( empty( $url ) || empty( $arrURL['scheme'] ) )
return new WP_Error('http_request_failed', __('A valid URL was not provided.'));
Here’s how the wp_safe_remote_request()
function is defined:
function wp_safe_remote_request( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
I was just playing with it and tested:
$args['reject_unsafe_urls'] = false;
through:
add_action( 'wp_feed_options', function( $feed )
{
$user = parse_url( $feed->feed_url, PHP_URL_USER );
$pass = parse_url( $feed->feed_url, PHP_URL_PASS );
if( ! $user || ! $pass )
return;
add_filter( 'http_request_args', function( $r, $url ) use ( $user, $pass )
{
if( $user && $pass )
$r['reject_unsafe_urls'] = false;
return $r;
}, 10, 2 );
} );
and then this worked:
$rss = fetch_feed( 'http://user:[email protected]/feed/' );
Inside the WP_Http::request()
method we got this condition:
if ( $r['reject_unsafe_urls'] )
$url = wp_http_validate_url( $url );
so it looks like wp_http_validate_url()
is not validating this url:
http://user:[email protected]/feed/
By setting reject_unsafe_urls
to false, we skip that check.
There’s actually a filter available for this: http_request_reject_unsafe_urls
, but I wouldn’t recommend using:
add_filter( `http_request_reject_unsafe_urls`, '__return_false' );
I think the demo plugin above, would in general be a better choice, because it still uses the wp_http_validate_url()
on the auth stripped url.
Note:
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
return false;
within the wp_http_validate_url()
function , seems to be the show-stopper for fetch_feed()
for urls with user:pass.